2 * Check decoding of clone3 syscall.
4 * Copyright (c) 2019 The strace developers.
7 * SPDX-License-Identifier: GPL-2.0-or-later
19 #ifdef HAVE_LINUX_SCHED_H
20 # include <linux/sched.h>
23 #ifdef HAVE_STRUCT_USER_DESC
32 #ifndef RETVAL_INJECTED
33 # define RETVAL_INJECTED 0
36 #ifndef HAVE_STRUCT_CLONE_ARGS
38 # include <linux/types.h>
40 # define XLAT_MACROS_ONLY
41 # include "xlat/clone_flags.h"
42 # undef XLAT_MACROS_ONLY
54 #endif /* !HAVE_STRUCT_CLONE_ARGS */
56 enum validity_flag_bits {
64 #define _(x_) x_ = 1 << x_##_BIT
76 static const int child_exit_status = 42;
79 static const long injected_retval = 42;
81 # define INJ_STR " (INJECTED)\n"
82 #else /* !RETVAL_INJECTED */
84 #endif /* RETVAL_INJECTED */
94 while (waitpid(pid, &status, WEXITED | __WCLONE) != pid) {
96 perror_msg_and_fail("waitpid(%d)", pid);
102 do_clone3_(void *args, kernel_ulong_t size, bool should_fail, int line)
104 long rc = syscall(__NR_clone3, args, size);
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);
112 if (should_fail && rc >= 0)
113 error_msg_and_fail("%d: Unexpected success of a clone3() call",
116 if (!should_fail && rc < 0 && errno != ENOSYS)
117 perror_msg_and_fail("%d: Unexpected failure of a clone3() call",
121 _exit(child_exit_status);
123 if (rc > 0 && ((struct clone_args *) args)->exit_signal)
130 #define do_clone3(args_, size_, should_fail_) \
131 do_clone3_((args_), (size_), (should_fail_), __LINE__)
134 print_addr64(const char *pfx, uint64_t addr)
137 printf("%s%#" PRIx64, pfx, addr);
139 printf("%sNULL", pfx);
143 print_tls(const char *pfx, uint64_t arg_ptr, enum validity_flags vf)
145 # if defined HAVE_STRUCT_USER_DESC && defined __i386__
146 if (!(vf & TLS_VALID)) {
147 print_addr64(pfx, arg_ptr);
151 struct user_desc *arg = (struct user_desc *) (uintptr_t) arg_ptr;
153 printf("%s{entry_number=%d"
158 ", read_exec_only=%u"
159 ", limit_in_pages=%u"
160 ", seg_not_present=%u"
170 arg->seg_not_present,
173 print_addr64(pfx, arg_ptr);
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)
182 int saved_errno = errno;
184 if (!(valid & STRUCT_VALID)) {
190 printf("{flags=%#" PRIx64, (uint64_t) arg->flags);
192 if (flags_str[0] == '0')
193 printf("{flags=%#" PRIx64, (uint64_t) arg->flags);
195 printf("{flags=%#" PRIx64 " /* %s */",
196 (uint64_t) arg->flags, flags_str);
198 printf("{flags=%s", flags_str);
201 if (arg->flags & CLONE_PIDFD)
202 print_addr64(", pidfd=", arg->pidfd);
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);
209 print_addr64(", child_tid=", arg->child_tid);
212 if (arg->flags & CLONE_PARENT_SETTID)
213 print_addr64(", parent_tid=", arg->parent_tid);
215 printf(", exit_signal=%s", es_str);
216 print_addr64(", stack=", arg->stack);
217 printf(", stack_size=%" PRIx64, (uint64_t) arg->stack_size);
219 if (arg->flags & CLONE_SETTLS)
220 print_tls("tls=", arg->tls, valid);
229 if (arg->flags & CLONE_PIDFD) {
230 if (valid & PIDFD_VALID)
231 printf(" => {pidfd=[%d]",
232 *(int *) (uintptr_t) arg->pidfd);
234 print_addr64(" => {pidfd=", arg->pidfd);
239 if (arg->flags & CLONE_PARENT_SETTID) {
240 printf(comma ? ", " : " => {");
242 if (valid & PARENT_TID_VALID)
243 printf("parent_tid=[%d]",
244 *(int *) (uintptr_t) arg->parent_tid);
246 print_addr64("parent_tid=", arg->parent_tid);
259 main(int argc, char *argv[])
261 static const struct {
262 struct clone_args args;
264 enum validity_flags vf;
265 const char *flags_str;
269 false, 0, "0", "0" },
270 { { .flags = CLONE_PARENT_SETTID },
271 false, 0, "CLONE_PARENT_SETTID", "0" },
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));
281 # if defined HAVE_STRUCT_USER_DESC
282 struct user_desc *tls = tail_alloc(sizeof(*tls));
284 fill_memory(tls, sizeof(*tls));
286 int *tls = tail_alloc(sizeof(*tls));
290 *child_tid = 0xdeadface;
291 *parent_tid = 0xfeedbeef;
293 rc = do_clone3(NULL, 0, true);
294 printf("clone3(NULL, 0) = %s" INJ_STR, sprintrc(rc));
296 rc = do_clone3(arg + 1, sizeof(*arg), true);
297 printf("clone3(%p, %zu) = %s" INJ_STR,
298 arg + 1, sizeof(*arg), sprintrc(rc));
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),
307 memset(arg, 0, sizeof(*arg));
308 memset(arg2, 0, sizeof(*arg2) + 8);
310 rc = do_clone3(arg, 64, false);
311 printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0}, 64)"
315 rc = do_clone3(arg, sizeof(*arg) + 8, true);
316 printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0, ???}"
320 ", %zu) = %s" INJ_STR,
321 sizeof(*arg) + 8, sprintrc(rc));
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));
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.
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 */ "
339 "\"\\xfa\\xce\\xfe\\xed\\xde\\xad\\xc0\\xde\""
341 "\"\\xde\\xc0\\xad\\xde\\xed\\xfe\\xce\\xfa\""
344 "} => {/* bytes %zu..%zu */ "
346 "\"\\xfa\\xce\\xfe\\xed\\xde\\xad\\xc0\\xde\""
348 "\"\\xde\\xc0\\xad\\xde\\xed\\xfe\\xce\\xfa\""
350 #endif /* RETVAL_INJECTED */
351 "}, %zu) = %s" INJ_STR,
352 0xdeadface00000000ULL | SIGCHLD,
353 sizeof(*arg2), sizeof(*arg2) + 7,
355 sizeof(*arg2), sizeof(*arg2) + 7,
357 sizeof(*arg2) + 8, sprintrc(rc));
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, ???}"
366 ", %zu) = %s" INJ_STR,
367 sizeof(*arg) + 16, sprintrc(rc));
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));
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)"
388 XLAT_UNKNOWN(0xdec0dead004000ff, "CLONE_???"),
391 arg->exit_signal = SIGCHLD;
395 const char *flag_str;
397 const char *field_name;
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 },
418 for (size_t i = 0; i < ARRAY_SIZE(pid_fields); i++) {
422 arg->flags = 0xbad0000000000001ULL | pid_fields[i].flag;
425 snprintf(flag_str, sizeof(flag_str), "%#" PRIx64,
426 (uint64_t) arg->flags);
428 snprintf(flag_str, sizeof(flag_str),
429 "%#" PRIx64 " /* %s|0xbad0000000000001 */",
430 (uint64_t) arg->flags, pid_fields[i].flag_str);
432 snprintf(flag_str, sizeof(flag_str), "%s|0xbad0000000000001",
433 pid_fields[i].flag_str);
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);
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);
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);
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);
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,
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);
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,
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));
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}"
514 "}, 64) = %s" INJ_STR,
515 #if !defined HAVE_STRUCT_USER_DESC || !defined __i386__
520 for (size_t i = 0; i < ARRAY_SIZE(arg_vals); i++) {
521 memcpy(arg, &arg_vals[i].args, sizeof(*arg));
523 rc = do_clone3(arg, sizeof(*arg), arg_vals[i].should_fail);
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));
531 puts("+++ exited with 0 +++");