From: Dmitry V. Levin Date: Sun, 19 Feb 2017 00:31:40 +0000 (+0000) Subject: sched: enhance decoding of sched_setattr syscall X-Git-Tag: v4.17~201 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=556652be53452fabcc26a1b0849c1a3d7133d264;hp=f31755fda2015cbb1aa0686e257118169f102031;p=strace sched: enhance decoding of sched_setattr syscall Implement read/write semantics of struct sched_attr.size argument of sched_setattr syscall. Do not print members of struct sched_attr besides sched_attr.size when the specified structure size is less than the minimal size allowed by the kernel. * sched.c (print_sched_attr): Fetch struct sched_attr.size and use it as the structure size. Print struct sched_attr.size only when the structure size is less than SCHED_ATTR_MIN_SIZE. (SYS_FUNC(sched_setattr)): Call print_sched_attr with zero size argument. Print struct sched_attr.size returned by the kernel on exiting syscall in case of E2BIG. Print the last syscall argument on exiting syscall. (SYS_FUNC(sched_getattr)): Do not call print_sched_attr with zero size argument. * NEWS: Mention it. * tests/sched_xetattr.c (main): Check it. --- diff --git a/NEWS b/NEWS index c82eecbe..6c588593 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ Noteworthy changes in release ?.?? (????-??-??) =============================================== +* Improvements + * Enhanced decoding of sched_setattr syscall. + Noteworthy changes in release 4.16 (2017-02-14) =============================================== diff --git a/sched.c b/sched.c index a648f863..409fb67a 100644 --- a/sched.c +++ b/sched.c @@ -96,33 +96,73 @@ SYS_FUNC(sched_rr_get_interval) static void print_sched_attr(struct tcb *const tcp, const kernel_ulong_t addr, - unsigned int size) + unsigned int usize) { struct sched_attr attr = {}; + unsigned int size; + + if (usize) { + /* called from sched_getattr */ + size = usize <= sizeof(attr) ? usize : (unsigned) sizeof(attr); + if (umoven_or_printaddr(tcp, addr, size, &attr)) + return; + /* the number of bytes written by the kernel */ + size = attr.size; + } else { + /* called from sched_setattr */ + if (umove_or_printaddr(tcp, addr, &attr.size)) + return; + usize = attr.size; + if (!usize) + usize = SCHED_ATTR_MIN_SIZE; + size = usize <= sizeof(attr) ? usize : (unsigned) sizeof(attr); + if (size >= SCHED_ATTR_MIN_SIZE) { + if (umoven_or_printaddr(tcp, addr, size, &attr)) + return; + } + } + + tprintf("{size=%u", attr.size); + + if (size >= SCHED_ATTR_MIN_SIZE) { + tprints(", sched_policy="); + printxval(schedulers, attr.sched_policy, "SCHED_???"); + tprints(", sched_flags="); + printflags64(sched_flags, attr.sched_flags, "SCHED_FLAG_???"); + +#define PRINT_SCHED_FIELD(field, fmt) \ + tprintf(", " #field "=%" fmt, attr.field) - if (size > sizeof(attr)) - size = sizeof(attr); - if (umoven_or_printaddr(tcp, addr, size, &attr)) - return; - - tprintf("{size=%u, sched_policy=", attr.size); - printxval(schedulers, attr.sched_policy, "SCHED_???"); - tprints(", sched_flags="); - printflags64(sched_flags, attr.sched_flags, "SCHED_FLAG_???"); - tprintf(", sched_nice=%d", attr.sched_nice); - tprintf(", sched_priority=%u", attr.sched_priority); - tprintf(", sched_runtime=%" PRIu64, attr.sched_runtime); - tprintf(", sched_deadline=%" PRIu64, attr.sched_deadline); - tprintf(", sched_period=%" PRIu64 "}", attr.sched_period); + PRINT_SCHED_FIELD(sched_nice, "d"); + PRINT_SCHED_FIELD(sched_priority, "u"); + PRINT_SCHED_FIELD(sched_runtime, PRIu64); + PRINT_SCHED_FIELD(sched_deadline, PRIu64); + PRINT_SCHED_FIELD(sched_period, PRIu64); + + if (usize > size) + tprints(", ..."); + } + + tprints("}"); } SYS_FUNC(sched_setattr) { - tprintf("%d, ", (int) tcp->u_arg[0]); - print_sched_attr(tcp, tcp->u_arg[1], 0x100); - tprintf(", %u", (unsigned int) tcp->u_arg[2]); + if (entering(tcp)) { + tprintf("%d, ", (int) tcp->u_arg[0]); + print_sched_attr(tcp, tcp->u_arg[1], 0); + } else { + struct sched_attr attr; - return RVAL_DECODED; + if (verbose(tcp) && tcp->u_error == E2BIG + && umove(tcp, tcp->u_arg[1], &attr.size) == 0) { + tprintf(" => {size=%u}", attr.size); + } + + tprintf(", %u", (unsigned int) tcp->u_arg[2]); + } + + return 0; } SYS_FUNC(sched_getattr) @@ -130,10 +170,13 @@ SYS_FUNC(sched_getattr) if (entering(tcp)) { tprintf("%d, ", (int) tcp->u_arg[0]); } else { - print_sched_attr(tcp, tcp->u_arg[1], tcp->u_arg[2]); - tprintf(", %u, %u", - (unsigned int) tcp->u_arg[2], - (unsigned int) tcp->u_arg[3]); + const unsigned int size = tcp->u_arg[2]; + + if (size) + print_sched_attr(tcp, tcp->u_arg[1], size); + else + printaddr(tcp->u_arg[1]); + tprintf(", %u, %u", size, (unsigned int) tcp->u_arg[3]); } return 0; diff --git a/tests/sched_xetattr.c b/tests/sched_xetattr.c index f3d2b377..23eb19cf 100644 --- a/tests/sched_xetattr.c +++ b/tests/sched_xetattr.c @@ -68,6 +68,7 @@ main(void) (kernel_ulong_t) 0xdefaceddeadc0deULL; struct sched_attr *const attr = tail_alloc(sizeof(*attr)); + unsigned int *const psize = tail_alloc(sizeof(*psize)); void *const efault = attr + 1; sys_sched_getattr(0, 0, 0, 0); @@ -150,6 +151,38 @@ main(void) attr->sched_deadline, attr->sched_period); + *psize = attr->size; + + sys_sched_setattr(0, (unsigned long) psize, 0); + printf("sched_setattr(0, %p, 0) = %s\n", psize, errstr); + + attr->size = 0; + + sys_sched_setattr(0, (unsigned long) attr, 0); + printf("sched_setattr(0, {size=%u, sched_policy=", attr->size); + printxval(schedulers, attr->sched_policy, NULL); + printf(", sched_flags=%s, sched_nice=%d, sched_priority=%u" + ", sched_runtime=%" PRIu64 ", sched_deadline=%" PRIu64 + ", sched_period=%" PRIu64 "}, 0) = 0\n", + "SCHED_FLAG_RESET_ON_FORK", + attr->sched_nice, + attr->sched_priority, + attr->sched_runtime, + attr->sched_deadline, + attr->sched_period); + + attr->size = 1; + + sys_sched_setattr(0, (unsigned long) attr, 0); + printf("sched_setattr(0, {size=%u} => {size=%u}, 0) = %s\n", + 1, attr->size, errstr); + + attr->size = SCHED_ATTR_MIN_SIZE - 1; + + sys_sched_setattr(0, (unsigned long) attr, 0); + printf("sched_setattr(0, {size=%u} => {size=%u}, 0) = %s\n", + SCHED_ATTR_MIN_SIZE - 1, attr->size, errstr); + attr->size = 0x90807060; attr->sched_policy = 0xca7faced; attr->sched_flags = 0xbadc0ded1057da7aULL; @@ -163,7 +196,7 @@ main(void) printf("sched_setattr(%d, {size=%u, sched_policy=%#x /* SCHED_??? */, " "sched_flags=%#" PRIx64 " /* SCHED_FLAG_??? */, " "sched_nice=%d, sched_priority=%u, sched_runtime=%" PRIu64 ", " - "sched_deadline=%" PRIu64 ", sched_period=%" PRIu64 "}, %u)" + "sched_deadline=%" PRIu64 ", sched_period=%" PRIu64 ", ...}, %u)" " = %s\n", (int) bogus_pid, attr->size,