diff options
author | Dmitry V. Levin <ldv@altlinux.org> | 2020-01-12 22:09:46 +0000 |
---|---|---|
committer | Dmitry V. Levin <ldv@altlinux.org> | 2020-01-14 09:28:05 +0000 |
commit | 57898f408482e5f9dc44f5d1aec0eff867161196 (patch) | |
tree | 32ac1d02f9f99cf639f8072c0df9773cf6f9eeb6 | |
parent | c58bf6b042ce2713a87d57bf0741448afd0a5d64 (diff) | |
download | strace-57898f408482e5f9dc44f5d1aec0eff867161196.tar.gz |
clone: implement decoding of new fields in struct clone_args
* configure.ac (AC_CHECK_TYPES): Remove struct clone_args.
(AC_CHECK_MEMBERS): Check for struct clone_args.set_tid_size
in <linux/sched.h>.
* clone.c (struct strace_clone_args): Add set_tid and set_tid_size
fields.
(SYS_FUNC(clone3)): Decode set_tid and set_tid_size fields of struct
clone_args introduced by Linux kernel commit v5.5-rc1~180^2~5.
* NEWS: Mention this change.
* tests/clone3.c: Check HAVE_STRUCT_CLONE_ARGS_SET_TID_SIZE instead of
HAVE_STRUCT_CLONE_ARGS.
(struct test_clone_args): Add set_tid and set_tid_size fields.
(MAX_SET_TID_SIZE): New macro.
(print_set_tid): New function.
(print_clone3): Use it.
(main): Check decoding of set_tid and set_tid_size fields.
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | clone.c | 19 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | tests/clone3.c | 70 |
4 files changed, 81 insertions, 11 deletions
@@ -5,6 +5,7 @@ Noteworthy changes in release ?.? (????-??-??) * Added -e trace=%creds option for tracing syscalls related to process credentials. * Enhanced decoding of BPF_PROG_LOAD bpf syscall command. + * Updated decoding of clone3 syscall to match Linux 5.5. * Updated lists of BPF_* constants. * Bug fixes @@ -147,6 +147,8 @@ struct strace_clone_args { uint64_t stack; uint64_t stack_size; uint64_t tls; + uint64_t set_tid; + uint64_t set_tid_size; }; /** @@ -262,6 +264,23 @@ SYS_FUNC(clone3) print_tls_arg(tcp, arg.tls); } + if (arg.set_tid || arg.set_tid_size) { + static const unsigned int max_set_tid_size = 32; + + if (!arg.set_tid || !arg.set_tid_size || + arg.set_tid_size > max_set_tid_size) { + PRINT_FIELD_ADDR64(", ", arg, set_tid); + } else { + int buf; + + tprints(", set_tid="); + print_array(tcp, arg.set_tid, arg.set_tid_size, + &buf, sizeof(buf), tfetch_mem, + print_int32_array_member, 0); + } + PRINT_FIELD_U(", ", arg, set_tid_size); + } + if (size > fetch_size) print_nonzero_bytes(tcp, ", ", addr, fetch_size, MIN(size, get_pagesize()), diff --git a/configure.ac b/configure.ac index 576ff7c14..9ee2a7785 100644 --- a/configure.ac +++ b/configure.ac @@ -620,7 +620,7 @@ AC_CHECK_MEMBERS(m4_normalize([ struct iocb.aio_rw_flags ]),,, [#include <linux/aio_abi.h>]) -AC_CHECK_TYPES([struct clone_args],,, [#include <linux/sched.h>]) +AC_CHECK_MEMBERS([struct clone_args.set_tid_size],,, [#include <linux/sched.h>]) CPPFLAGS="$saved_CPPFLAGS" diff --git a/tests/clone3.c b/tests/clone3.c index 527b28b3e..8e9c36f97 100644 --- a/tests/clone3.c +++ b/tests/clone3.c @@ -48,9 +48,11 @@ struct test_clone_args { uint64_t stack; uint64_t stack_size; uint64_t tls; + uint64_t set_tid; + uint64_t set_tid_size; }; -#ifdef HAVE_STRUCT_CLONE_ARGS +#ifdef HAVE_STRUCT_CLONE_ARGS_SET_TID_SIZE typedef struct clone_args struct_clone_args; #else typedef struct test_clone_args struct_clone_args; @@ -76,6 +78,8 @@ enum validity_flags { #undef _ +#define MAX_SET_TID_SIZE 32 + static const int child_exit_status = 42; #if RETVAL_INJECTED @@ -196,6 +200,23 @@ print_tls(const char *pfx, uint64_t arg_ptr, enum validity_flags vf) #endif } +static void +print_set_tid(uint64_t set_tid, uint64_t set_tid_size) +{ + if (!set_tid || set_tid != (uintptr_t) set_tid || + !set_tid_size || set_tid_size > MAX_SET_TID_SIZE) { + print_addr64(", set_tid=", set_tid); + } else { + printf(", set_tid="); + int *tids = (int *) (uintptr_t) set_tid; + for (unsigned int i = 0; i < set_tid_size; ++i) + printf("%s%d", i ? ", " : "[", tids[i]); + printf("]"); + } + + printf(", set_tid_size=%" PRIu64, set_tid_size); +} + static inline void print_clone3(struct_clone_args *const arg, long rc, kernel_ulong_t sz, enum validity_flags valid, @@ -242,6 +263,10 @@ print_clone3(struct_clone_args *const arg, long rc, kernel_ulong_t sz, if (arg->flags & CLONE_SETTLS) print_tls("tls=", arg->tls, valid); + if (sz >= offsetofend(struct_clone_args, set_tid_size) && + (arg->set_tid || arg->set_tid_size)) + print_set_tid(arg->set_tid, arg->set_tid_size); + printf("}"); if (rc < 0) @@ -299,13 +324,24 @@ main(int argc, char *argv[]) { { .flags = CLONE_PARENT_SETTID | CLONE_CLEAR_SIGHAND }, ERR(EINVAL) | ERR(0), 0, "CLONE_PARENT_SETTID|CLONE_CLEAR_SIGHAND", "0" }, - }; + { { .set_tid = 0xfacefeedcafebabe }, + ERR(E2BIG) | ERR(EINVAL), 0, "0", "0" }, + { { .set_tid_size = 0xfacecafefeedbabe }, + ERR(E2BIG) | ERR(EINVAL), 0, "0", "0" }, + { { .set_tid = 0xfacefeedcafebabe, + .set_tid_size = MAX_SET_TID_SIZE + 1 }, + ERR(E2BIG) | ERR(EINVAL), 0, "0", "0" }, + }; TAIL_ALLOC_OBJECT_CONST_PTR(struct_clone_args, arg); - struct_clone_args *arg2 = tail_alloc(sizeof(*arg2) + 8); + const size_t arg1_size = offsetofend(struct_clone_args, tls); + struct_clone_args *const arg1 = tail_alloc(arg1_size); + const size_t arg2_size = sizeof(*arg) + 8; + struct_clone_args *const arg2 = tail_alloc(arg2_size); TAIL_ALLOC_OBJECT_CONST_PTR(int, pidfd); TAIL_ALLOC_OBJECT_CONST_PTR(int, child_tid); TAIL_ALLOC_OBJECT_CONST_PTR(int, parent_tid); + int *const tids = tail_alloc(sizeof(*tids) * MAX_SET_TID_SIZE); long rc; #if defined HAVE_STRUCT_USER_DESC @@ -319,6 +355,7 @@ main(int argc, char *argv[]) *pidfd = 0xbadc0ded; *child_tid = 0xdeadface; *parent_tid = 0xfeedbeef; + fill_memory(tids, sizeof(*tids) * MAX_SET_TID_SIZE); rc = do_clone3(NULL, 0, ERR(EINVAL)); printf("clone3(NULL, 0) = %s" INJ_STR, sprintrc(rc)); @@ -327,15 +364,16 @@ main(int argc, char *argv[]) printf("clone3(%p, %zu) = %s" INJ_STR, arg + 1, sizeof(*arg), sprintrc(rc)); - rc = do_clone3((char *) arg + sizeof(uint64_t), - sizeof(*arg) - sizeof(uint64_t), ERR(EINVAL)); + size_t short_size = arg1_size - sizeof(uint64_t); + char *short_start = (char *) arg1 + sizeof(uint64_t); + rc = do_clone3(short_start, short_size, ERR(EINVAL)); printf("clone3(%p, %zu) = %s" INJ_STR, - (char *) arg + sizeof(uint64_t), sizeof(*arg) - sizeof(uint64_t), - sprintrc(rc)); + short_start, short_size, sprintrc(rc)); memset(arg, 0, sizeof(*arg)); - memset(arg2, 0, sizeof(*arg2) + 8); + memset(arg1, 0, arg1_size); + memset(arg2, 0, arg2_size); rc = do_clone3(arg, 64, ERR(0)); printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0}, 64)" @@ -350,10 +388,22 @@ main(int argc, char *argv[]) ", %zu) = %s" INJ_STR, sizeof(*arg) + 8, sprintrc(rc)); - rc = do_clone3(arg2, sizeof(*arg2) + 8, ERR(0)); + rc = do_clone3(arg1, arg1_size, ERR(0)); printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0}" ", %zu) = %s" INJ_STR, - sizeof(*arg2) + 8, sprintrc(rc)); + arg1_size, sprintrc(rc)); + + rc = do_clone3(arg2, arg2_size, ERR(0)); + printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0}" + ", %zu) = %s" INJ_STR, + arg2_size, sprintrc(rc)); + + arg->set_tid = (uintptr_t) tids; + arg->set_tid_size = MAX_SET_TID_SIZE; + rc = do_clone3(arg, sizeof(*arg), ERR(E2BIG) | ERR(EINVAL)); + print_clone3(arg, rc, sizeof(*arg), STRUCT_VALID, "0", "0"); + printf(", %zu) = %s" INJ_STR, sizeof(*arg), sprintrc(rc)); + memset(arg, 0, sizeof(*arg)); /* * NB: the following check is purposefully fragile (it will break |