Browse Source

clone: implement clone3 syscall decoding

* configure.ac (AC_CHECK_HEADERS): Check for linux/sched.h presence.
(AC_CHECK_TYPES): Check for struct clone_args in <linux/sched.h>.
* clone.c: Include "print_fields.h".
(struct strace_clone_args): New type.
(print_nonzero_bytes): New function.
(SYS_FUNC(clone3)): New decoder.
* linux/syscallent-common.h ([BASE_NR + 435]): Wire up clone3.
* NEWS: Mention this change.
* tests/clone3.c: New file.
* tests/clone3-Xabbrev.c: Likewise.
* tests/clone3-Xraw.c: Likewise.
* tests/clone3-Xverbose.c: Likewise.
* tests/clone3-success.c: Likewise.
* tests/clone3-success-Xabbrev.c: Likewise.
* tests/clone3-success-Xraw.c: Likewise.
* tests/clone3-success-Xverbose.c: Likewise.
* tests/clone3-success.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add clone3-success,
clone3-success-Xabbrev, clone3-success-Xraw, and
clone3-success-Xverbose.
(DECODER_TESTS): Add clone3-success.test.
* tests/gen_tests.in (clone3, clone3-Xabbrev, clone3-Xraw,
clone3-Xverbose, clone3-success-Xabbrev, clone3-success-Xraw,
clone3-success-Xverbose): New entries.
* tests/pure_executables.list: Add clone3, clone3-Xabbrev, clone3-Xraw,
and clone3-Xverbose.
* tests/.gitignore: Add clone3, clone3-Xabbrev, clone3-Xraw,
clone3-Xverbose, clone3-success, clone3-success-Xabbrev,
clone3-success-Xraw, and clone3-success-Xverbose.

Co-Authored-by: Dmitry V. Levin <ldv@altlinux.org>
Eugene Syromyatnikov 2 months ago
parent
commit
91fbffc06d

+ 1
- 1
NEWS View File

@@ -2,7 +2,7 @@ Noteworthy changes in release ?.? (????-??-??)
2 2
 ==============================================
3 3
 
4 4
 * Improvements
5
-  * Implemented decoding of pidfd_open syscall.
5
+  * Implemented decoding of pidfd_open and clone3 syscalls.
6 6
   * Enhanced decoding of NETLINK_ROUTE protocol.
7 7
   * Implemented decoding of UNIX_DIAG_UID netlink attribute.
8 8
   * Updated lists of BPF_*, ETH_*, KEYCTL_*, KVM_*, MAP_*, SO_*, TCP_*, V4L2_*,

+ 189
- 0
clone.c View File

@@ -18,6 +18,8 @@
18 18
 # define CSIGNAL 0x000000ff
19 19
 #endif
20 20
 
21
+#include "print_fields.h"
22
+
21 23
 #include "xlat/clone_flags.h"
22 24
 #include "xlat/setns_types.h"
23 25
 #include "xlat/unshare_flags.h"
@@ -137,6 +139,193 @@ SYS_FUNC(clone)
137 139
 	return 0;
138 140
 }
139 141
 
142
+
143
+struct strace_clone_args {
144
+	uint64_t flags;
145
+	uint64_t /* int * */ pidfd;
146
+	uint64_t /* int * */ child_tid;
147
+	uint64_t /* int * */ parent_tid;
148
+	uint64_t /* int */   exit_signal;
149
+	uint64_t stack;
150
+	uint64_t stack_size;
151
+	uint64_t tls;
152
+};
153
+
154
+/**
155
+ * Print a region of tracee memory only in case non-zero bytes are present
156
+ * there.  It almost fits into printstr_ex, but it has some pretty specific
157
+ * behaviour peculiarities (like printing of ellipsis on error) to readily
158
+ * integrate it there.
159
+ *
160
+ * Since it is expected to be used for printing tail of a structure in tracee's
161
+ * memory, it accepts a combination of start_addr/start_offs/total_len and does
162
+ * the relevant calculations itself.
163
+ *
164
+ * @param prefix     A string printed in cases something is going to be printed.
165
+ * @param start_addr Address of the beginning of a structure (whose tail
166
+ *                   is supposedly to be printed) in tracee's memory.
167
+ * @param start_offs Offset from the beginning of the structure where the tail
168
+ *                   data starts.
169
+ * @param total_len  Total size of the tracee's memory region containing
170
+ *                   the structure and the tail data.
171
+ *                   Caller is responsible for imposing a sensible (usually
172
+ *                   mandated by the kernel interface, like get_pagesize())
173
+ *                   limit here.
174
+ * @param style      Passed to string_quote as "style" parameter.
175
+ * @return           Returns true is anything was printed, false otherwise.
176
+ */
177
+static bool
178
+print_nonzero_bytes(struct tcb *const tcp, const char *prefix,
179
+		    const kernel_ulong_t start_addr,
180
+		    const unsigned int start_offs,
181
+		    const unsigned int total_len,
182
+		    const unsigned int style)
183
+{
184
+	if (start_offs >= total_len)
185
+		return false;
186
+
187
+	const kernel_ulong_t addr = start_addr + start_offs;
188
+	const unsigned int len = total_len - start_offs;
189
+	const unsigned int size = MIN(len, max_strlen);
190
+
191
+	char *str = malloc(len);
192
+
193
+	if (!str) {
194
+		error_func_msg("memory exhausted when tried to allocate"
195
+                               " %u bytes", len);
196
+		tprintf("%s???", prefix);
197
+		return true;
198
+	}
199
+
200
+	bool ret = true;
201
+
202
+	if (umoven(tcp, addr, len, str)) {
203
+		tprintf("%s???", prefix);
204
+	} else if (is_filled(str, 0, len)) {
205
+		ret = false;
206
+	} else {
207
+		tprints(prefix);
208
+		tprintf("/* bytes %u..%u */ ", start_offs, total_len - 1);
209
+
210
+		print_quoted_string(str, size, style);
211
+
212
+		if (size < len)
213
+			tprints("...");
214
+	}
215
+
216
+	free(str);
217
+	return ret;
218
+}
219
+
220
+SYS_FUNC(clone3)
221
+{
222
+	static const size_t minsz = offsetofend(struct strace_clone_args, tls);
223
+
224
+	const kernel_ulong_t addr = tcp->u_arg[0];
225
+	const kernel_ulong_t size = tcp->u_arg[1];
226
+
227
+	struct strace_clone_args arg = { 0 };
228
+	kernel_ulong_t fetch_size;
229
+
230
+	fetch_size = MIN(size, sizeof(arg));
231
+
232
+	if (entering(tcp)) {
233
+		if (fetch_size < minsz) {
234
+			printaddr(addr);
235
+			goto out;
236
+		} else if (umoven_or_printaddr(tcp, addr, fetch_size, &arg)) {
237
+			goto out;
238
+		}
239
+
240
+		PRINT_FIELD_FLAGS("{", arg, flags, clone_flags,
241
+				  "CLONE_???");
242
+
243
+		if (arg.flags & CLONE_PIDFD)
244
+			PRINT_FIELD_ADDR64(", ", arg, pidfd);
245
+
246
+		if (arg.flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
247
+			PRINT_FIELD_ADDR64(", ", arg, child_tid);
248
+
249
+		if (arg.flags & CLONE_PARENT_SETTID)
250
+			PRINT_FIELD_ADDR64(", ", arg, parent_tid);
251
+
252
+		tprints(", exit_signal=");
253
+		if (arg.exit_signal < INT_MAX)
254
+			printsignal(arg.exit_signal);
255
+		else
256
+			tprintf("%" PRIu64, arg.exit_signal);
257
+
258
+		PRINT_FIELD_ADDR64(", ", arg, stack);
259
+		PRINT_FIELD_X(", ", arg, stack_size);
260
+
261
+		if (arg.flags & CLONE_SETTLS) {
262
+			tprints(", tls=");
263
+			print_tls_arg(tcp, arg.tls);
264
+		}
265
+
266
+		if (size > fetch_size)
267
+			print_nonzero_bytes(tcp, ", ", addr, fetch_size,
268
+					    MIN(size, get_pagesize()),
269
+					    QUOTE_FORCE_HEX);
270
+
271
+		tprints("}");
272
+
273
+		if ((arg.flags & (CLONE_PIDFD | CLONE_PARENT_SETTID)) ||
274
+		    (size > fetch_size))
275
+			return 0;
276
+
277
+		goto out;
278
+	}
279
+
280
+	/* exiting */
281
+
282
+	if (syserror(tcp))
283
+		goto out;
284
+
285
+	if (umoven(tcp, addr, fetch_size, &arg)) {
286
+		tprints(" => ");
287
+		printaddr(addr);
288
+		goto out;
289
+	}
290
+
291
+	static const char initial_pfx[] = " => {";
292
+	const char *pfx = initial_pfx;
293
+
294
+	if (arg.flags & CLONE_PIDFD) {
295
+		tprintf("%spidfd=", pfx);
296
+		printnum_fd(tcp, arg.pidfd);
297
+		pfx = ", ";
298
+	}
299
+
300
+	if (arg.flags & CLONE_PARENT_SETTID) {
301
+		tprintf("%sparent_tid=", pfx);
302
+		printnum_int(tcp, arg.parent_tid, "%d"); /* TID */
303
+		pfx = ", ";
304
+	}
305
+
306
+	if (size > fetch_size) {
307
+		/*
308
+		 * TODO: it is possible to also store the tail on entering
309
+		 *       and then compare against it on exiting in order
310
+		 *       to avoid double-printing, but it would also require yet
311
+		 *       another complication of print_nonzero_bytes interface.
312
+		 */
313
+		if (print_nonzero_bytes(tcp, pfx, addr, fetch_size,
314
+					MIN(size, get_pagesize()),
315
+					QUOTE_FORCE_HEX))
316
+			pfx = ", ";
317
+	}
318
+
319
+	if (pfx != initial_pfx)
320
+		tprints("}");
321
+
322
+out:
323
+	tprintf(", %" PRI_klu, size);
324
+
325
+	return RVAL_DECODED;
326
+}
327
+
328
+
140 329
 SYS_FUNC(setns)
141 330
 {
142 331
 	printfd(tcp, tcp->u_arg[0]);

+ 3
- 0
configure.ac View File

@@ -423,6 +423,7 @@ AC_CHECK_HEADERS(m4_normalize([
423 423
 	linux/nsfs.h
424 424
 	linux/perf_event.h
425 425
 	linux/quota.h
426
+	linux/sched.h
426 427
 	linux/seccomp.h
427 428
 	linux/securebits.h
428 429
 	linux/sem.h
@@ -613,6 +614,8 @@ AC_CHECK_MEMBERS(m4_normalize([
613 614
 		struct iocb.aio_rw_flags
614 615
 		]),,, [#include <linux/aio_abi.h>])
615 616
 
617
+AC_CHECK_TYPES([struct clone_args],,, [#include <linux/sched.h>])
618
+
616 619
 CPPFLAGS="$saved_CPPFLAGS"
617 620
 
618 621
 AC_CHECK_HEADERS([linux/btrfs.h], [

+ 1
- 0
linux/syscallent-common.h View File

@@ -19,3 +19,4 @@
19 19
 [BASE_NR + 432] = { 3,	TD,		SEN(fsmount),			"fsmount"		},
20 20
 [BASE_NR + 433] = { 3,	TD|TF,		SEN(fspick),			"fspick"		},
21 21
 [BASE_NR + 434] = { 2,	TD,		SEN(pidfd_open),		"pidfd_open"		},
22
+[BASE_NR + 435] = { 2,	TP,		SEN(clone3),			"clone3"		},

+ 8
- 0
tests/.gitignore View File

@@ -42,6 +42,14 @@ clock_adjtime
42 42
 clock_nanosleep
43 43
 clock_xettime
44 44
 clone-flags
45
+clone3
46
+clone3-Xabbrev
47
+clone3-Xraw
48
+clone3-Xverbose
49
+clone3-success
50
+clone3-success-Xabbrev
51
+clone3-success-Xraw
52
+clone3-success-Xverbose
45 53
 clone_parent
46 54
 clone_ptrace
47 55
 copy_file_range

+ 5
- 0
tests/Makefile.am View File

@@ -86,6 +86,10 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \
86 86
 	check_sigign \
87 87
 	clone_parent \
88 88
 	clone_ptrace \
89
+	clone3-success \
90
+	clone3-success-Xabbrev \
91
+	clone3-success-Xraw \
92
+	clone3-success-Xverbose \
89 93
 	count-f \
90 94
 	delay \
91 95
 	execve-v \
@@ -235,6 +239,7 @@ DECODER_TESTS = \
235 239
 	caps-abbrev.test \
236 240
 	caps.test \
237 241
 	clone-flags.test \
242
+	clone3-success.test \
238 243
 	eventfd.test \
239 244
 	execve-v.test \
240 245
 	execve.test \

+ 1
- 0
tests/clone3-Xabbrev.c View File

@@ -0,0 +1 @@
1
+#include "clone3.c"

+ 2
- 0
tests/clone3-Xraw.c View File

@@ -0,0 +1,2 @@
1
+#define XLAT_RAW 1
2
+#include "clone3.c"

+ 2
- 0
tests/clone3-Xverbose.c View File

@@ -0,0 +1,2 @@
1
+#define XLAT_VERBOSE 1
2
+#include "clone3.c"

+ 2
- 0
tests/clone3-success-Xabbrev.c View File

@@ -0,0 +1,2 @@
1
+#define RETVAL_INJECTED 1
2
+#include "clone3.c"

+ 3
- 0
tests/clone3-success-Xraw.c View File

@@ -0,0 +1,3 @@
1
+#define RETVAL_INJECTED 1
2
+#define XLAT_RAW 1
3
+#include "clone3.c"

+ 3
- 0
tests/clone3-success-Xverbose.c View File

@@ -0,0 +1,3 @@
1
+#define RETVAL_INJECTED 1
2
+#define XLAT_VERBOSE 1
3
+#include "clone3.c"

+ 2
- 0
tests/clone3-success.c View File

@@ -0,0 +1,2 @@
1
+#define RETVAL_INJECTED 1
2
+#include "clone3.c"

+ 12
- 0
tests/clone3-success.test View File

@@ -0,0 +1,12 @@
1
+#!/bin/sh -efu
2
+#
3
+# Copyright (c) 2019 The strace developers.
4
+# All rights reserved.
5
+#
6
+# SPDX-License-Identifier: GPL-2.0-or-later
7
+
8
+. "${srcdir=.}/scno_tampering.sh"
9
+
10
+run_strace -a10 "$@" -e trace=clone3 -e inject=clone3:retval=42 \
11
+	"../$NAME" > "$EXP"
12
+match_diff "$LOG" "$EXP"

+ 534
- 0
tests/clone3.c View File

@@ -0,0 +1,534 @@
1
+/*
2
+ * Check decoding of clone3 syscall.
3
+ *
4
+ * Copyright (c) 2019 The strace developers.
5
+ * All rights reserved.
6
+ *
7
+ * SPDX-License-Identifier: GPL-2.0-or-later
8
+ */
9
+
10
+#include "tests.h"
11
+
12
+#include <errno.h>
13
+#include <inttypes.h>
14
+#include <stdio.h>
15
+#include <string.h>
16
+#include <unistd.h>
17
+#include <sys/wait.h>
18
+
19
+#ifdef HAVE_LINUX_SCHED_H
20
+# include <linux/sched.h>
21
+#endif
22
+
23
+#ifdef HAVE_STRUCT_USER_DESC
24
+# include <asm/ldt.h>
25
+#endif
26
+
27
+#include "scno.h"
28
+
29
+#ifndef VERBOSE
30
+# define VERBOSE 0
31
+#endif
32
+#ifndef RETVAL_INJECTED
33
+# define RETVAL_INJECTED 0
34
+#endif
35
+
36
+#ifndef HAVE_STRUCT_CLONE_ARGS
37
+# include <stdint.h>
38
+# include <linux/types.h>
39
+
40
+# define XLAT_MACROS_ONLY
41
+#  include "xlat/clone_flags.h"
42
+# undef XLAT_MACROS_ONLY
43
+
44
+struct clone_args {
45
+	uint64_t flags;
46
+	uint64_t pidfd;
47
+	uint64_t child_tid;
48
+	uint64_t parent_tid;
49
+	uint64_t exit_signal;
50
+	uint64_t stack;
51
+	uint64_t stack_size;
52
+	uint64_t tls;
53
+};
54
+#endif /* !HAVE_STRUCT_CLONE_ARGS */
55
+
56
+enum validity_flag_bits {
57
+	STRUCT_VALID_BIT,
58
+	PIDFD_VALID_BIT,
59
+	CHILD_TID_VALID_BIT,
60
+	PARENT_TID_VALID_BIT,
61
+	TLS_VALID_BIT,
62
+};
63
+
64
+#define _(x_) x_ = 1 << x_##_BIT
65
+
66
+enum validity_flags {
67
+	_(STRUCT_VALID),
68
+	_(PIDFD_VALID),
69
+	_(CHILD_TID_VALID),
70
+	_(PARENT_TID_VALID),
71
+	_(TLS_VALID),
72
+};
73
+
74
+#undef _
75
+
76
+static const int child_exit_status = 42;
77
+
78
+#if RETVAL_INJECTED
79
+static const long injected_retval = 42;
80
+
81
+# define INJ_STR " (INJECTED)\n"
82
+#else /* !RETVAL_INJECTED */
83
+# define INJ_STR "\n"
84
+#endif /* RETVAL_INJECTED */
85
+
86
+
87
+#if !RETVAL_INJECTED
88
+static void
89
+wait_cloned(int pid)
90
+{
91
+	int status;
92
+
93
+	errno = 0;
94
+	while (waitpid(pid, &status, WEXITED | __WCLONE) != pid) {
95
+		if (errno != EINTR)
96
+			perror_msg_and_fail("waitpid(%d)", pid);
97
+	}
98
+}
99
+#endif
100
+
101
+static long
102
+do_clone3_(void *args, kernel_ulong_t size, bool should_fail, int line)
103
+{
104
+	long rc = syscall(__NR_clone3, args, size);
105
+
106
+#if RETVAL_INJECTED
107
+	if (rc != injected_retval)
108
+		perror_msg_and_fail("%d: Unexpected injected return value "
109
+				    "of a clone3() call (%ld instead of %ld)",
110
+				    line, rc, injected_retval);
111
+#else
112
+	if (should_fail && rc >= 0)
113
+		error_msg_and_fail("%d: Unexpected success of a clone3() call",
114
+				   line);
115
+
116
+	if (!should_fail && rc < 0 && errno != ENOSYS)
117
+		perror_msg_and_fail("%d: Unexpected failure of a clone3() call",
118
+				    line);
119
+
120
+	if (!rc)
121
+		_exit(child_exit_status);
122
+
123
+	if (rc > 0 && ((struct clone_args *) args)->exit_signal)
124
+		wait_cloned(rc);
125
+#endif
126
+
127
+	return rc;
128
+}
129
+
130
+#define do_clone3(args_, size_, should_fail_) \
131
+	do_clone3_((args_), (size_), (should_fail_), __LINE__)
132
+
133
+static inline void
134
+print_addr64(const char *pfx, uint64_t addr)
135
+{
136
+	if (addr)
137
+		printf("%s%#" PRIx64, pfx, addr);
138
+	else
139
+		printf("%sNULL", pfx);
140
+}
141
+
142
+static void
143
+print_tls(const char *pfx, uint64_t arg_ptr, enum validity_flags vf)
144
+{
145
+# if defined HAVE_STRUCT_USER_DESC && defined __i386__
146
+	if (!(vf & TLS_VALID)) {
147
+		print_addr64(pfx, arg_ptr);
148
+		return;
149
+	}
150
+
151
+	struct user_desc *arg = (struct user_desc *) (uintptr_t) arg_ptr;
152
+
153
+	printf("%s{entry_number=%d"
154
+	       ", base_addr=%#08x"
155
+	       ", limit=%#08x"
156
+	       ", seg_32bit=%u"
157
+	       ", contents=%u"
158
+	       ", read_exec_only=%u"
159
+	       ", limit_in_pages=%u"
160
+	       ", seg_not_present=%u"
161
+	       ", useable=%u}",
162
+	       pfx,
163
+	       arg->entry_number,
164
+	       arg->base_addr,
165
+	       arg->limit,
166
+	       arg->seg_32bit,
167
+	       arg->contents,
168
+	       arg->read_exec_only,
169
+	       arg->limit_in_pages,
170
+	       arg->seg_not_present,
171
+	       arg->useable);
172
+# else
173
+	print_addr64(pfx, arg_ptr);
174
+# endif
175
+}
176
+
177
+static inline void
178
+print_clone3(struct clone_args *const arg, long rc, kernel_ulong_t sz,
179
+	     enum validity_flags valid,
180
+	     const char *flags_str, const char *es_str)
181
+{
182
+	int saved_errno = errno;
183
+
184
+	if (!(valid & STRUCT_VALID)) {
185
+		printf("%p", arg);
186
+		goto out;
187
+	}
188
+
189
+#if XLAT_RAW
190
+	printf("{flags=%#" PRIx64, (uint64_t) arg->flags);
191
+#elif XLAT_VERBOSE
192
+	if (flags_str[0] == '0')
193
+		printf("{flags=%#" PRIx64, (uint64_t) arg->flags);
194
+	else
195
+		printf("{flags=%#" PRIx64 " /* %s */",
196
+		       (uint64_t) arg->flags, flags_str);
197
+#else
198
+	printf("{flags=%s", flags_str);
199
+#endif
200
+
201
+	if (arg->flags & CLONE_PIDFD)
202
+		print_addr64(", pidfd=", arg->pidfd);
203
+
204
+	if (arg->flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) {
205
+		if (valid & CHILD_TID_VALID)
206
+			printf(", child_tid=[%d]",
207
+			       *(int *) (uintptr_t) arg->child_tid);
208
+		else
209
+			print_addr64(", child_tid=", arg->child_tid);
210
+	}
211
+
212
+	if (arg->flags & CLONE_PARENT_SETTID)
213
+		print_addr64(", parent_tid=", arg->parent_tid);
214
+
215
+	printf(", exit_signal=%s", es_str);
216
+	print_addr64(", stack=", arg->stack);
217
+	printf(", stack_size=%" PRIx64, (uint64_t) arg->stack_size);
218
+
219
+	if (arg->flags & CLONE_SETTLS)
220
+		print_tls("tls=", arg->tls, valid);
221
+
222
+	printf("}");
223
+
224
+	if (rc < 0)
225
+		goto out;
226
+
227
+	bool comma = false;
228
+
229
+	if (arg->flags & CLONE_PIDFD) {
230
+		if (valid & PIDFD_VALID)
231
+			printf(" => {pidfd=[%d]",
232
+			       *(int *) (uintptr_t) arg->pidfd);
233
+		else
234
+			print_addr64(" => {pidfd=", arg->pidfd);
235
+
236
+		comma = true;
237
+	}
238
+
239
+	if (arg->flags & CLONE_PARENT_SETTID) {
240
+		printf(comma ? ", " : " => {");
241
+
242
+		if (valid & PARENT_TID_VALID)
243
+			printf("parent_tid=[%d]",
244
+			       *(int *) (uintptr_t) arg->parent_tid);
245
+		else
246
+			print_addr64("parent_tid=", arg->parent_tid);
247
+
248
+		comma = true;
249
+	}
250
+
251
+	if (comma)
252
+		printf("}");
253
+
254
+out:
255
+	errno = saved_errno;
256
+}
257
+
258
+int
259
+main(int argc, char *argv[])
260
+{
261
+	static const struct {
262
+		struct clone_args args;
263
+		bool should_fail;
264
+		enum validity_flags vf;
265
+		const char *flags_str;
266
+		const char *es_str;
267
+	} arg_vals[] = {
268
+		{ { .flags = 0 },
269
+			false, 0, "0", "0" },
270
+		{ { .flags = CLONE_PARENT_SETTID },
271
+			false, 0, "CLONE_PARENT_SETTID", "0" },
272
+	};
273
+
274
+	struct clone_args *arg = tail_alloc(sizeof(*arg));
275
+	struct clone_args *arg2 = tail_alloc(sizeof(*arg2) + 8);
276
+	int *pidfd = tail_alloc(sizeof(*pidfd));
277
+	int *child_tid = tail_alloc(sizeof(*child_tid));
278
+	int *parent_tid = tail_alloc(sizeof(*parent_tid));
279
+	long rc;
280
+
281
+# if defined HAVE_STRUCT_USER_DESC
282
+	struct user_desc *tls = tail_alloc(sizeof(*tls));
283
+
284
+	fill_memory(tls, sizeof(*tls));
285
+# else
286
+	int *tls = tail_alloc(sizeof(*tls));
287
+# endif
288
+
289
+	*pidfd = 0xbadc0ded;
290
+	*child_tid = 0xdeadface;
291
+	*parent_tid = 0xfeedbeef;
292
+
293
+	rc = do_clone3(NULL, 0, true);
294
+	printf("clone3(NULL, 0) = %s" INJ_STR, sprintrc(rc));
295
+
296
+	rc = do_clone3(arg + 1, sizeof(*arg), true);
297
+	printf("clone3(%p, %zu) = %s" INJ_STR,
298
+	       arg + 1, sizeof(*arg), sprintrc(rc));
299
+
300
+	rc = do_clone3((char *) arg + sizeof(uint64_t),
301
+		       sizeof(*arg) - sizeof(uint64_t), true);
302
+	printf("clone3(%p, %zu) = %s" INJ_STR,
303
+	       (char *) arg + sizeof(uint64_t), sizeof(*arg) - sizeof(uint64_t),
304
+	       sprintrc(rc));
305
+
306
+
307
+	memset(arg, 0, sizeof(*arg));
308
+	memset(arg2, 0, sizeof(*arg2) + 8);
309
+
310
+	rc = do_clone3(arg, 64, false);
311
+	printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0}, 64)"
312
+	       " = %s" INJ_STR,
313
+	       sprintrc(rc));
314
+
315
+	rc = do_clone3(arg, sizeof(*arg) + 8, true);
316
+	printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0, ???}"
317
+#if RETVAL_INJECTED
318
+	       " => {???}"
319
+#endif
320
+	       ", %zu) = %s" INJ_STR,
321
+	       sizeof(*arg) + 8, sprintrc(rc));
322
+
323
+	rc = do_clone3(arg2, sizeof(*arg2) + 8, false);
324
+	printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0}"
325
+	       ", %zu) = %s" INJ_STR,
326
+	       sizeof(*arg2) + 8, sprintrc(rc));
327
+
328
+	/*
329
+	 * NB: the following check is purposedly fragile (it will break
330
+	 *     when system's struct clone_args has additional fields,
331
+	 *     so it signalises that the decoder needs to be updated.
332
+	 */
333
+	arg2[1].flags = 0xfacefeeddeadc0de;
334
+	arg2->exit_signal = 0xdeadface00000000ULL | SIGCHLD;
335
+	rc = do_clone3(arg2, sizeof(*arg2) + 8, true);
336
+	printf("clone3({flags=0, exit_signal=%llu, stack=NULL, stack_size=0"
337
+	       ", /* bytes %zu..%zu */ "
338
+#if WORDS_BIGENDIAN
339
+	       "\"\\xfa\\xce\\xfe\\xed\\xde\\xad\\xc0\\xde\""
340
+#else
341
+	       "\"\\xde\\xc0\\xad\\xde\\xed\\xfe\\xce\\xfa\""
342
+#endif
343
+#if RETVAL_INJECTED
344
+	       "} => {/* bytes %zu..%zu */ "
345
+# if WORDS_BIGENDIAN
346
+	       "\"\\xfa\\xce\\xfe\\xed\\xde\\xad\\xc0\\xde\""
347
+# else
348
+	       "\"\\xde\\xc0\\xad\\xde\\xed\\xfe\\xce\\xfa\""
349
+# endif
350
+#endif /* RETVAL_INJECTED */
351
+	       "}, %zu) = %s" INJ_STR,
352
+	       0xdeadface00000000ULL | SIGCHLD,
353
+	       sizeof(*arg2), sizeof(*arg2) + 7,
354
+#if RETVAL_INJECTED
355
+	       sizeof(*arg2), sizeof(*arg2) + 7,
356
+#endif
357
+	       sizeof(*arg2) + 8, sprintrc(rc));
358
+
359
+	arg2->exit_signal = 0xdeadc0de;
360
+	rc = do_clone3(arg2, sizeof(*arg) + 16, true);
361
+	printf("clone3({flags=0, exit_signal=3735929054, stack=NULL"
362
+	       ", stack_size=0, ???}"
363
+#if RETVAL_INJECTED
364
+	       " => {???}"
365
+#endif
366
+	       ", %zu) = %s" INJ_STR,
367
+	       sizeof(*arg) + 16, sprintrc(rc));
368
+
369
+	arg->flags = 0xfacefeedbeefc0de;
370
+	arg->exit_signal = 0x1e55c0de;
371
+	rc = do_clone3(arg, 64, true);
372
+	printf("clone3({flags=%s, child_tid=NULL, exit_signal=508936414"
373
+	       ", stack=NULL, stack_size=0, tls=NULL}, 64) = %s" INJ_STR,
374
+	       XLAT_KNOWN(0xfacefeedbeefc0de, "CLONE_VFORK|CLONE_PARENT"
375
+	       "|CLONE_THREAD|CLONE_NEWNS|CLONE_SYSVSEM|CLONE_SETTLS"
376
+	       "|CLONE_CHILD_CLEARTID|CLONE_UNTRACED|CLONE_NEWCGROUP"
377
+	       "|CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER|CLONE_NEWPID|CLONE_IO"
378
+	       "|0xfacefeed004000de"), sprintrc(rc));
379
+
380
+	arg->flags = 0xdec0dead004000ffULL;
381
+	arg->exit_signal = 250;
382
+	arg->stack = 0xface1e55beeff00dULL;
383
+	arg->stack_size = 0xcaffeedefacedca7ULL;
384
+	rc = do_clone3(arg, 64, true);
385
+	printf("clone3({flags=%s, exit_signal=250"
386
+	       ", stack=0xface1e55beeff00d, stack_size=0xcaffeedefacedca7}, 64)"
387
+	       " = %s" INJ_STR,
388
+	       XLAT_UNKNOWN(0xdec0dead004000ff, "CLONE_???"),
389
+	       sprintrc(rc));
390
+
391
+	arg->exit_signal = SIGCHLD;
392
+
393
+	struct {
394
+		uint64_t flag;
395
+		const char *flag_str;
396
+		uint64_t *field;
397
+		const char *field_name;
398
+		int *ptr;
399
+		bool deref_exiting;
400
+	} pid_fields[] = {
401
+		{ ARG_STR(CLONE_PIDFD),
402
+			(uint64_t *) &arg->pidfd,
403
+			"pidfd", pidfd, true },
404
+		{ ARG_STR(CLONE_CHILD_SETTID),
405
+			(uint64_t *) &arg->child_tid,
406
+			"child_tid", child_tid },
407
+		{ ARG_STR(CLONE_CHILD_CLEARTID),
408
+			(uint64_t *) &arg->child_tid,
409
+			"child_tid", child_tid },
410
+		{ ARG_STR(CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID),
411
+			(uint64_t *) &arg->child_tid,
412
+			"child_tid", child_tid },
413
+		{ ARG_STR(CLONE_PARENT_SETTID),
414
+			(uint64_t *) &arg->parent_tid,
415
+			"parent_tid", parent_tid, true },
416
+	};
417
+
418
+	for (size_t i = 0; i < ARRAY_SIZE(pid_fields); i++) {
419
+		char flag_str[128];
420
+		const char *rc_str;
421
+
422
+		arg->flags = 0xbad0000000000001ULL | pid_fields[i].flag;
423
+
424
+#if XLAT_RAW
425
+		snprintf(flag_str, sizeof(flag_str), "%#" PRIx64,
426
+			 (uint64_t) arg->flags);
427
+#elif XLAT_VERBOSE
428
+		snprintf(flag_str, sizeof(flag_str),
429
+			 "%#" PRIx64 " /* %s|0xbad0000000000001 */",
430
+			 (uint64_t) arg->flags, pid_fields[i].flag_str);
431
+#else
432
+		snprintf(flag_str, sizeof(flag_str), "%s|0xbad0000000000001",
433
+			 pid_fields[i].flag_str);
434
+#endif
435
+
436
+		pid_fields[i].field[0] = 0;
437
+		rc = do_clone3(arg, 64, true);
438
+		rc_str = sprintrc(rc);
439
+		printf("clone3({flags=%s, %s=NULL"
440
+		       ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
441
+		       ", stack=0xface1e55beeff00d"
442
+		       ", stack_size=0xcaffeedefacedca7}",
443
+		       flag_str, pid_fields[i].field_name);
444
+#if RETVAL_INJECTED
445
+		if (pid_fields[i].deref_exiting)
446
+			printf(" => {%s=NULL}", pid_fields[i].field_name);
447
+#endif /* RETVAL_INJECTED */
448
+		printf(", 64) = %s" INJ_STR, rc_str);
449
+
450
+		pid_fields[i].field[0] = (uintptr_t) (pid_fields[i].ptr + 1);
451
+		rc = do_clone3(arg, 64, true);
452
+		rc_str = sprintrc(rc);
453
+		printf("clone3({flags=%s, %s=%p"
454
+		       ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
455
+		       ", stack=0xface1e55beeff00d"
456
+		       ", stack_size=0xcaffeedefacedca7}",
457
+		       flag_str, pid_fields[i].field_name,
458
+		       pid_fields[i].ptr + 1);
459
+#if RETVAL_INJECTED
460
+		if (pid_fields[i].deref_exiting)
461
+			printf(" => {%s=%p}",
462
+			       pid_fields[i].field_name, pid_fields[i].ptr + 1);
463
+#endif /* RETVAL_INJECTED */
464
+		printf(", 64) = %s" INJ_STR, rc_str);
465
+
466
+		pid_fields[i].field[0] = (uintptr_t) pid_fields[i].ptr;
467
+		rc = do_clone3(arg, 64, true);
468
+		rc_str = sprintrc(rc);
469
+		printf("clone3({flags=%s, %s=%p"
470
+		       ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
471
+		       ", stack=0xface1e55beeff00d"
472
+		       ", stack_size=0xcaffeedefacedca7}",
473
+		       flag_str, pid_fields[i].field_name,
474
+		       pid_fields[i].ptr);
475
+#if RETVAL_INJECTED
476
+		if (pid_fields[i].deref_exiting)
477
+			printf(" => {%s=[%d]}",
478
+			       pid_fields[i].field_name, *pid_fields[i].ptr);
479
+#endif /* RETVAL_INJECTED */
480
+		printf(", 64) = %s" INJ_STR, rc_str);
481
+	}
482
+
483
+	arg->flags = 0xbad0000000000001ULL | CLONE_SETTLS;
484
+	rc = do_clone3(arg, 64, true);
485
+	printf("clone3({flags="
486
+	       XLAT_KNOWN(0xbad0000000080001, "CLONE_SETTLS|0xbad0000000000001")
487
+	       ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
488
+	       ", stack=0xface1e55beeff00d"
489
+	       ", stack_size=0xcaffeedefacedca7, tls=NULL}, 64) = %s" INJ_STR,
490
+	       sprintrc(rc));
491
+
492
+	arg->tls = (uintptr_t) (tls + 1);
493
+	rc = do_clone3(arg, 64, true);
494
+	printf("clone3({flags="
495
+	       XLAT_KNOWN(0xbad0000000080001, "CLONE_SETTLS|0xbad0000000000001")
496
+	       ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
497
+	       ", stack=0xface1e55beeff00d"
498
+	       ", stack_size=0xcaffeedefacedca7, tls=%p}, 64) = %s" INJ_STR,
499
+	       tls + 1, sprintrc(rc));
500
+
501
+	arg->tls = (uintptr_t) tls;
502
+	rc = do_clone3(arg, 64, true);
503
+	printf("clone3({flags="
504
+	       XLAT_KNOWN(0xbad0000000080001, "CLONE_SETTLS|0xbad0000000000001")
505
+	       ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
506
+	       ", stack=0xface1e55beeff00d, stack_size=0xcaffeedefacedca7, tls="
507
+#if defined HAVE_STRUCT_USER_DESC && defined __i386__
508
+	       "{entry_number=2206368128, base_addr=0x87868584"
509
+	       ", limit=0x8b8a8988, seg_32bit=0, contents=2, read_exec_only=1"
510
+	       ", limit_in_pages=0, seg_not_present=0, useable=0}"
511
+#else
512
+	       "%p"
513
+#endif
514
+	       "}, 64) = %s" INJ_STR,
515
+#if !defined HAVE_STRUCT_USER_DESC || !defined __i386__
516
+	       tls,
517
+#endif
518
+	       sprintrc(rc));
519
+
520
+	for (size_t i = 0; i < ARRAY_SIZE(arg_vals); i++) {
521
+		memcpy(arg, &arg_vals[i].args, sizeof(*arg));
522
+
523
+		rc = do_clone3(arg, sizeof(*arg), arg_vals[i].should_fail);
524
+		printf("clone3(");
525
+		print_clone3(arg, rc, sizeof(*arg),
526
+			     arg_vals[i].vf | STRUCT_VALID,
527
+			     arg_vals[i].flags_str, arg_vals[i].es_str);
528
+		printf(", %zu) = %s" INJ_STR, sizeof(*arg), sprintrc(rc));
529
+	}
530
+
531
+	puts("+++ exited with 0 +++");
532
+
533
+	return 0;
534
+}

+ 7
- 0
tests/gen_tests.in View File

@@ -31,6 +31,13 @@ clock	test_trace_expr 'times|fcntl.*' -e/clock
31 31
 clock_adjtime	-a37
32 32
 clock_nanosleep	-e trace=clock_nanosleep,clock_gettime
33 33
 clock_xettime	-a36 -e trace=clock_getres,clock_gettime,clock_settime
34
+clone3	-a16
35
+clone3-Xabbrev	-a16 -Xabbrev  -e trace=clone3
36
+clone3-Xraw	-a16 -Xraw     -e trace=clone3
37
+clone3-Xverbose	-a16 -Xverbose -e trace=clone3
38
+clone3-success-Xabbrev	+clone3-success.test -a16 -Xabbrev
39
+clone3-success-Xraw	+clone3-success.test -a16 -Xraw
40
+clone3-success-Xverbose	+clone3-success.test -a16 -Xverbose
34 41
 copy_file_range
35 42
 creat	-a20
36 43
 delete_module	-a23

+ 4
- 0
tests/pure_executables.list View File

@@ -32,6 +32,10 @@ clock_adjtime
32 32
 clock_nanosleep
33 33
 clock_xettime
34 34
 clone-flags
35
+clone3
36
+clone3-Xabbrev
37
+clone3-Xraw
38
+clone3-Xverbose
35 39
 copy_file_range
36 40
 creat
37 41
 delete_module

Loading…
Cancel
Save