summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry V. Levin <ldv@altlinux.org>2020-01-12 22:09:46 +0000
committerDmitry V. Levin <ldv@altlinux.org>2020-01-14 09:28:05 +0000
commit57898f408482e5f9dc44f5d1aec0eff867161196 (patch)
tree32ac1d02f9f99cf639f8072c0df9773cf6f9eeb6
parentc58bf6b042ce2713a87d57bf0741448afd0a5d64 (diff)
downloadstrace-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--NEWS1
-rw-r--r--clone.c19
-rw-r--r--configure.ac2
-rw-r--r--tests/clone3.c70
4 files changed, 81 insertions, 11 deletions
diff --git a/NEWS b/NEWS
index 86468c7a6..177d39a7f 100644
--- a/NEWS
+++ b/NEWS
@@ -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
diff --git a/clone.c b/clone.c
index aa5894490..da1f3b557 100644
--- a/clone.c
+++ b/clone.c
@@ -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