]> granicus.if.org Git - strace/blob - tests/clone3.c
Remove XLAT_END
[strace] / tests / clone3.c
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
113         static int unimplemented_error = -1;
114
115         if (should_fail) {
116                 if (rc >= 0)
117                         error_msg_and_fail("%d: Unexpected success"
118                                            " of a clone3() call", line);
119                 if (unimplemented_error < 0)
120                         unimplemented_error =
121                                 (errno == EINVAL) ? ENOSYS : errno;
122         } else {
123                 if (rc < 0 && errno != unimplemented_error)
124                         perror_msg_and_fail("%d: Unexpected failure"
125                                             " of a clone3() call", line);
126         }
127
128         if (!rc)
129                 _exit(child_exit_status);
130
131         if (rc > 0 && ((struct clone_args *) args)->exit_signal)
132                 wait_cloned(rc);
133 #endif
134
135         return rc;
136 }
137
138 #define do_clone3(args_, size_, should_fail_) \
139         do_clone3_((args_), (size_), (should_fail_), __LINE__)
140
141 static inline void
142 print_addr64(const char *pfx, uint64_t addr)
143 {
144         if (addr)
145                 printf("%s%#" PRIx64, pfx, addr);
146         else
147                 printf("%sNULL", pfx);
148 }
149
150 static void
151 print_tls(const char *pfx, uint64_t arg_ptr, enum validity_flags vf)
152 {
153 #if defined HAVE_STRUCT_USER_DESC && defined __i386__
154         if (!(vf & TLS_VALID)) {
155                 print_addr64(pfx, arg_ptr);
156                 return;
157         }
158
159         struct user_desc *arg = (struct user_desc *) (uintptr_t) arg_ptr;
160
161         printf("%s{entry_number=%d"
162                ", base_addr=%#08x"
163                ", limit=%#08x"
164                ", seg_32bit=%u"
165                ", contents=%u"
166                ", read_exec_only=%u"
167                ", limit_in_pages=%u"
168                ", seg_not_present=%u"
169                ", useable=%u}",
170                pfx,
171                arg->entry_number,
172                arg->base_addr,
173                arg->limit,
174                arg->seg_32bit,
175                arg->contents,
176                arg->read_exec_only,
177                arg->limit_in_pages,
178                arg->seg_not_present,
179                arg->useable);
180 #else
181         print_addr64(pfx, arg_ptr);
182 #endif
183 }
184
185 static inline void
186 print_clone3(struct clone_args *const arg, long rc, kernel_ulong_t sz,
187              enum validity_flags valid,
188              const char *flags_str, const char *es_str)
189 {
190         int saved_errno = errno;
191
192         if (!(valid & STRUCT_VALID)) {
193                 printf("%p", arg);
194                 goto out;
195         }
196
197 #if XLAT_RAW
198         printf("{flags=%#" PRIx64, (uint64_t) arg->flags);
199 #elif XLAT_VERBOSE
200         if (flags_str[0] == '0')
201                 printf("{flags=%#" PRIx64, (uint64_t) arg->flags);
202         else
203                 printf("{flags=%#" PRIx64 " /* %s */",
204                        (uint64_t) arg->flags, flags_str);
205 #else
206         printf("{flags=%s", flags_str);
207 #endif
208
209         if (arg->flags & CLONE_PIDFD)
210                 print_addr64(", pidfd=", arg->pidfd);
211
212         if (arg->flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) {
213                 if (valid & CHILD_TID_VALID)
214                         printf(", child_tid=[%d]",
215                                *(int *) (uintptr_t) arg->child_tid);
216                 else
217                         print_addr64(", child_tid=", arg->child_tid);
218         }
219
220         if (arg->flags & CLONE_PARENT_SETTID)
221                 print_addr64(", parent_tid=", arg->parent_tid);
222
223         printf(", exit_signal=%s", es_str);
224         print_addr64(", stack=", arg->stack);
225         printf(", stack_size=%" PRIx64, (uint64_t) arg->stack_size);
226
227         if (arg->flags & CLONE_SETTLS)
228                 print_tls("tls=", arg->tls, valid);
229
230         printf("}");
231
232         if (rc < 0)
233                 goto out;
234
235         bool comma = false;
236
237         if (arg->flags & CLONE_PIDFD) {
238                 if (valid & PIDFD_VALID)
239                         printf(" => {pidfd=[%d]",
240                                *(int *) (uintptr_t) arg->pidfd);
241                 else
242                         print_addr64(" => {pidfd=", arg->pidfd);
243
244                 comma = true;
245         }
246
247         if (arg->flags & CLONE_PARENT_SETTID) {
248                 printf(comma ? ", " : " => {");
249
250                 if (valid & PARENT_TID_VALID)
251                         printf("parent_tid=[%d]",
252                                *(int *) (uintptr_t) arg->parent_tid);
253                 else
254                         print_addr64("parent_tid=", arg->parent_tid);
255
256                 comma = true;
257         }
258
259         if (comma)
260                 printf("}");
261
262 out:
263         errno = saved_errno;
264 }
265
266 int
267 main(int argc, char *argv[])
268 {
269         static const struct {
270                 struct clone_args args;
271                 bool should_fail;
272                 enum validity_flags vf;
273                 const char *flags_str;
274                 const char *es_str;
275         } arg_vals[] = {
276                 { { .flags = 0 },
277                         false, 0, "0", "0" },
278                 { { .flags = CLONE_PARENT_SETTID },
279                         false, 0, "CLONE_PARENT_SETTID", "0" },
280         };
281
282         struct clone_args *arg = tail_alloc(sizeof(*arg));
283         struct clone_args *arg2 = tail_alloc(sizeof(*arg2) + 8);
284         int *pidfd = tail_alloc(sizeof(*pidfd));
285         int *child_tid = tail_alloc(sizeof(*child_tid));
286         int *parent_tid = tail_alloc(sizeof(*parent_tid));
287         long rc;
288
289 #if defined HAVE_STRUCT_USER_DESC
290         struct user_desc *tls = tail_alloc(sizeof(*tls));
291
292         fill_memory(tls, sizeof(*tls));
293 #else
294         int *tls = tail_alloc(sizeof(*tls));
295 #endif
296
297         *pidfd = 0xbadc0ded;
298         *child_tid = 0xdeadface;
299         *parent_tid = 0xfeedbeef;
300
301         rc = do_clone3(NULL, 0, true);
302         printf("clone3(NULL, 0) = %s" INJ_STR, sprintrc(rc));
303
304         rc = do_clone3(arg + 1, sizeof(*arg), true);
305         printf("clone3(%p, %zu) = %s" INJ_STR,
306                arg + 1, sizeof(*arg), sprintrc(rc));
307
308         rc = do_clone3((char *) arg + sizeof(uint64_t),
309                        sizeof(*arg) - sizeof(uint64_t), true);
310         printf("clone3(%p, %zu) = %s" INJ_STR,
311                (char *) arg + sizeof(uint64_t), sizeof(*arg) - sizeof(uint64_t),
312                sprintrc(rc));
313
314
315         memset(arg, 0, sizeof(*arg));
316         memset(arg2, 0, sizeof(*arg2) + 8);
317
318         rc = do_clone3(arg, 64, false);
319         printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0}, 64)"
320                " = %s" INJ_STR,
321                sprintrc(rc));
322
323         rc = do_clone3(arg, sizeof(*arg) + 8, true);
324         printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0, ???}"
325 #if RETVAL_INJECTED
326                " => {???}"
327 #endif
328                ", %zu) = %s" INJ_STR,
329                sizeof(*arg) + 8, sprintrc(rc));
330
331         rc = do_clone3(arg2, sizeof(*arg2) + 8, false);
332         printf("clone3({flags=0, exit_signal=0, stack=NULL, stack_size=0}"
333                ", %zu) = %s" INJ_STR,
334                sizeof(*arg2) + 8, sprintrc(rc));
335
336         /*
337          * NB: the following check is purposedly fragile (it will break
338          *     when system's struct clone_args has additional fields,
339          *     so it signalises that the decoder needs to be updated.
340          */
341         arg2[1].flags = 0xfacefeeddeadc0de;
342         arg2->exit_signal = 0xdeadface00000000ULL | SIGCHLD;
343         rc = do_clone3(arg2, sizeof(*arg2) + 8, true);
344         printf("clone3({flags=0, exit_signal=%llu, stack=NULL, stack_size=0"
345                ", /* bytes %zu..%zu */ "
346 #if WORDS_BIGENDIAN
347                "\"\\xfa\\xce\\xfe\\xed\\xde\\xad\\xc0\\xde\""
348 #else
349                "\"\\xde\\xc0\\xad\\xde\\xed\\xfe\\xce\\xfa\""
350 #endif
351 #if RETVAL_INJECTED
352                "} => {/* bytes %zu..%zu */ "
353 # if WORDS_BIGENDIAN
354                "\"\\xfa\\xce\\xfe\\xed\\xde\\xad\\xc0\\xde\""
355 # else
356                "\"\\xde\\xc0\\xad\\xde\\xed\\xfe\\xce\\xfa\""
357 # endif
358 #endif /* RETVAL_INJECTED */
359                "}, %zu) = %s" INJ_STR,
360                0xdeadface00000000ULL | SIGCHLD,
361                sizeof(*arg2), sizeof(*arg2) + 7,
362 #if RETVAL_INJECTED
363                sizeof(*arg2), sizeof(*arg2) + 7,
364 #endif
365                sizeof(*arg2) + 8, sprintrc(rc));
366
367         arg2->exit_signal = 0xdeadc0de;
368         rc = do_clone3(arg2, sizeof(*arg) + 16, true);
369         printf("clone3({flags=0, exit_signal=3735929054, stack=NULL"
370                ", stack_size=0, ???}"
371 #if RETVAL_INJECTED
372                " => {???}"
373 #endif
374                ", %zu) = %s" INJ_STR,
375                sizeof(*arg) + 16, sprintrc(rc));
376
377         arg->flags = 0xfacefeedbeefc0de;
378         arg->exit_signal = 0x1e55c0de;
379         rc = do_clone3(arg, 64, true);
380         printf("clone3({flags=%s, child_tid=NULL, exit_signal=508936414"
381                ", stack=NULL, stack_size=0, tls=NULL}, 64) = %s" INJ_STR,
382                XLAT_KNOWN(0xfacefeedbeefc0de, "CLONE_VFORK|CLONE_PARENT"
383                "|CLONE_THREAD|CLONE_NEWNS|CLONE_SYSVSEM|CLONE_SETTLS"
384                "|CLONE_CHILD_CLEARTID|CLONE_UNTRACED|CLONE_NEWCGROUP"
385                "|CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER|CLONE_NEWPID|CLONE_IO"
386                "|0xfacefeed004000de"), sprintrc(rc));
387
388         arg->flags = 0xdec0dead004000ffULL;
389         arg->exit_signal = 250;
390         arg->stack = 0xface1e55beeff00dULL;
391         arg->stack_size = 0xcaffeedefacedca7ULL;
392         rc = do_clone3(arg, 64, true);
393         printf("clone3({flags=%s, exit_signal=250"
394                ", stack=0xface1e55beeff00d, stack_size=0xcaffeedefacedca7}, 64)"
395                " = %s" INJ_STR,
396                XLAT_UNKNOWN(0xdec0dead004000ff, "CLONE_???"),
397                sprintrc(rc));
398
399         arg->exit_signal = SIGCHLD;
400
401         struct {
402                 uint64_t flag;
403                 const char *flag_str;
404                 uint64_t *field;
405                 const char *field_name;
406                 int *ptr;
407                 bool deref_exiting;
408         } pid_fields[] = {
409                 { ARG_STR(CLONE_PIDFD),
410                         (uint64_t *) &arg->pidfd,
411                         "pidfd", pidfd, true },
412                 { ARG_STR(CLONE_CHILD_SETTID),
413                         (uint64_t *) &arg->child_tid,
414                         "child_tid", child_tid },
415                 { ARG_STR(CLONE_CHILD_CLEARTID),
416                         (uint64_t *) &arg->child_tid,
417                         "child_tid", child_tid },
418                 { ARG_STR(CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID),
419                         (uint64_t *) &arg->child_tid,
420                         "child_tid", child_tid },
421                 { ARG_STR(CLONE_PARENT_SETTID),
422                         (uint64_t *) &arg->parent_tid,
423                         "parent_tid", parent_tid, true },
424         };
425
426         for (size_t i = 0; i < ARRAY_SIZE(pid_fields); i++) {
427                 char flag_str[128];
428                 const char *rc_str;
429
430                 arg->flags = 0xbad0000000000001ULL | pid_fields[i].flag;
431
432 #if XLAT_RAW
433                 snprintf(flag_str, sizeof(flag_str), "%#" PRIx64,
434                          (uint64_t) arg->flags);
435 #elif XLAT_VERBOSE
436                 snprintf(flag_str, sizeof(flag_str),
437                          "%#" PRIx64 " /* %s|0xbad0000000000001 */",
438                          (uint64_t) arg->flags, pid_fields[i].flag_str);
439 #else
440                 snprintf(flag_str, sizeof(flag_str), "%s|0xbad0000000000001",
441                          pid_fields[i].flag_str);
442 #endif
443
444                 pid_fields[i].field[0] = 0;
445                 rc = do_clone3(arg, 64, true);
446                 rc_str = sprintrc(rc);
447                 printf("clone3({flags=%s, %s=NULL"
448                        ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
449                        ", stack=0xface1e55beeff00d"
450                        ", stack_size=0xcaffeedefacedca7}",
451                        flag_str, pid_fields[i].field_name);
452 #if RETVAL_INJECTED
453                 if (pid_fields[i].deref_exiting)
454                         printf(" => {%s=NULL}", pid_fields[i].field_name);
455 #endif /* RETVAL_INJECTED */
456                 printf(", 64) = %s" INJ_STR, rc_str);
457
458                 pid_fields[i].field[0] = (uintptr_t) (pid_fields[i].ptr + 1);
459                 rc = do_clone3(arg, 64, true);
460                 rc_str = sprintrc(rc);
461                 printf("clone3({flags=%s, %s=%p"
462                        ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
463                        ", stack=0xface1e55beeff00d"
464                        ", stack_size=0xcaffeedefacedca7}",
465                        flag_str, pid_fields[i].field_name,
466                        pid_fields[i].ptr + 1);
467 #if RETVAL_INJECTED
468                 if (pid_fields[i].deref_exiting)
469                         printf(" => {%s=%p}",
470                                pid_fields[i].field_name, pid_fields[i].ptr + 1);
471 #endif /* RETVAL_INJECTED */
472                 printf(", 64) = %s" INJ_STR, rc_str);
473
474                 pid_fields[i].field[0] = (uintptr_t) pid_fields[i].ptr;
475                 rc = do_clone3(arg, 64, true);
476                 rc_str = sprintrc(rc);
477                 printf("clone3({flags=%s, %s=%p"
478                        ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
479                        ", stack=0xface1e55beeff00d"
480                        ", stack_size=0xcaffeedefacedca7}",
481                        flag_str, pid_fields[i].field_name,
482                        pid_fields[i].ptr);
483 #if RETVAL_INJECTED
484                 if (pid_fields[i].deref_exiting)
485                         printf(" => {%s=[%d]}",
486                                pid_fields[i].field_name, *pid_fields[i].ptr);
487 #endif /* RETVAL_INJECTED */
488                 printf(", 64) = %s" INJ_STR, rc_str);
489         }
490
491         arg->flags = 0xbad0000000000001ULL | CLONE_SETTLS;
492         rc = do_clone3(arg, 64, true);
493         printf("clone3({flags="
494                XLAT_KNOWN(0xbad0000000080001, "CLONE_SETTLS|0xbad0000000000001")
495                ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
496                ", stack=0xface1e55beeff00d"
497                ", stack_size=0xcaffeedefacedca7, tls=NULL}, 64) = %s" INJ_STR,
498                sprintrc(rc));
499
500         arg->tls = (uintptr_t) (tls + 1);
501         rc = do_clone3(arg, 64, true);
502         printf("clone3({flags="
503                XLAT_KNOWN(0xbad0000000080001, "CLONE_SETTLS|0xbad0000000000001")
504                ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
505                ", stack=0xface1e55beeff00d"
506                ", stack_size=0xcaffeedefacedca7, tls=%p}, 64) = %s" INJ_STR,
507                tls + 1, sprintrc(rc));
508
509         arg->tls = (uintptr_t) tls;
510         rc = do_clone3(arg, 64, true);
511         printf("clone3({flags="
512                XLAT_KNOWN(0xbad0000000080001, "CLONE_SETTLS|0xbad0000000000001")
513                ", exit_signal=" XLAT_KNOWN(SIGCHLD, "SIGCHLD")
514                ", stack=0xface1e55beeff00d, stack_size=0xcaffeedefacedca7, tls="
515 #if defined HAVE_STRUCT_USER_DESC && defined __i386__
516                "{entry_number=2206368128, base_addr=0x87868584"
517                ", limit=0x8b8a8988, seg_32bit=0, contents=2, read_exec_only=1"
518                ", limit_in_pages=0, seg_not_present=0, useable=0}"
519 #else
520                "%p"
521 #endif
522                "}, 64) = %s" INJ_STR,
523 #if !defined HAVE_STRUCT_USER_DESC || !defined __i386__
524                tls,
525 #endif
526                sprintrc(rc));
527
528         for (size_t i = 0; i < ARRAY_SIZE(arg_vals); i++) {
529                 memcpy(arg, &arg_vals[i].args, sizeof(*arg));
530
531                 rc = do_clone3(arg, sizeof(*arg), arg_vals[i].should_fail);
532                 printf("clone3(");
533                 print_clone3(arg, rc, sizeof(*arg),
534                              arg_vals[i].vf | STRUCT_VALID,
535                              arg_vals[i].flags_str, arg_vals[i].es_str);
536                 printf(", %zu) = %s" INJ_STR, sizeof(*arg), sprintrc(rc));
537         }
538
539         puts("+++ exited with 0 +++");
540
541         return 0;
542 }