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