1 /*
2 * Check decoding of clone flags.
3 *
4 * Copyright (c) 2017-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 #include "xmalloc.h"
12
13 #include <errno.h>
14 #include <limits.h>
15 #include <sched.h>
16 #include <signal.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <sys/wait.h>
20 #include <unistd.h>
21 #include <linux/sched.h>
22
23 static const int child_exit_status = 42;
24 static pid_t pid;
25
26 static pid_t
27 wait_cloned(pid_t pid, int sig, const char *text)
28 {
29 if (pid < 0)
30 perror_msg_and_fail("clone %s", text);
31 int status;
32 pid_t rc = wait(&status);
33 if (sig) {
34 if (rc != pid)
35 perror_msg_and_fail("unexpected wait rc %d from %s",
36 rc, text);
37 if (!WIFEXITED(status) ||
38 WEXITSTATUS(status) != child_exit_status)
39 error_msg_and_fail("unexpected wait status %#x from %s",
40 status, text);
41 } else {
42 if (rc >= 0)
43 error_msg_and_fail("unexpected wait rc %d from %s",
44 rc, text);
45 }
46 return pid;
47 }
48
49 #ifdef IA64
50 extern int __clone2(int (*)(void *), void *, size_t, int, void *, ...);
51 # define do_clone(fn_, stack_, size_, flags_, arg_, ...) \
52 wait_cloned(__clone2((fn_), (stack_), (size_), (flags_), (arg_), \
53 ## __VA_ARGS__), (flags_) & 0xff, #flags_)
54 # define SYSCALL_NAME "clone2"
55 # define STACK_SIZE_FMT ", stack_size=%#lx"
56 # define STACK_SIZE_ARG child_stack_size,
57 #else
58 # define do_clone(fn_, stack_, size_, flags_, arg_, ...) \
59 wait_cloned(clone((fn_), (stack_), (flags_), (arg_), \
60 ## __VA_ARGS__), (flags_) & 0xff, #flags_)
61 # define SYSCALL_NAME "clone"
62 # define STACK_SIZE_FMT ""
63 # define STACK_SIZE_ARG
64 #endif
65
66 static int
67 child(void *const arg)
68 {
69 return child_exit_status;
70 }
71
72 int
73 main(void)
74 {
75 const unsigned long child_stack_size = get_page_size();
76 void *const child_stack =
77 tail_alloc(child_stack_size * 2) + child_stack_size;
78
79 const char *child_stack_expected_str = getenv("CHILD_STACK_EXPECTED");
80 const char *child_stack_reported_str = getenv("CHILD_STACK_REPORTED");
81
82 if (!child_stack_expected_str || !child_stack_reported_str) {
83 const unsigned long child_stack_base =
84 (unsigned long) child_stack / 0x1000;
85 pid = do_clone(child, child_stack, child_stack_size,
86 SIGCHLD, 0);
87 printf("%s\\(child_stack=(%#lx|%#lx)[[:xdigit:]]{3}"
88 STACK_SIZE_FMT ", flags=%s\\) = %d\n",
89 SYSCALL_NAME, child_stack_base, child_stack_base - 1,
90 STACK_SIZE_ARG "SIGCHLD", pid);
91 return 0;
92 }
93 const unsigned long child_stack_expected =
94 strtoul(child_stack_expected_str, 0, 16);
95 const unsigned long child_stack_reported =
96 strtoul(child_stack_reported_str, 0, 16);
97 const unsigned long child_stack_printed =
98 (unsigned long) child_stack +
99 (child_stack_reported - child_stack_expected);
100
101 pid = do_clone(child, child_stack, child_stack_size, 0, 0);
102 printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s) = %d\n",
103 SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
104 "0", pid);
105
106 pid = do_clone(child, child_stack, child_stack_size, CLONE_FS, 0);
107 printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s) = %d\n",
108 SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
109 "CLONE_FS", pid);
110
111 pid = do_clone(child, child_stack, child_stack_size, SIGCHLD, 0);
112 printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s) = %d\n",
113 SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
114 "SIGCHLD", pid);
115
116 pid = do_clone(child, child_stack, child_stack_size,
117 CLONE_FS|SIGCHLD, 0);
118 printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s) = %d\n",
119 SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
120 "CLONE_FS|SIGCHLD", pid);
121
122 TAIL_ALLOC_OBJECT_CONST_PTR(pid_t, ptid);
123 pid = do_clone(child, child_stack, child_stack_size,
124 CLONE_PARENT_SETTID|SIGCHLD, 0, ptid);
125 printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s"
126 ", parent_tid=[%u]) = %d\n",
127 SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
128 "CLONE_PARENT_SETTID|SIGCHLD", *ptid, pid);
129
130 char buf[PATH_MAX];
131 if (readlink("/proc/self/fd/0", buf, sizeof(buf) - 1) > 0) {
132 *ptid = 0;
133 pid = do_clone(child, child_stack, child_stack_size,
134 CLONE_PIDFD|SIGCHLD, 0, ptid);
135 char *fname = xasprintf("/proc/self/fd/%d", *ptid);
136 int rc = readlink(fname, buf, sizeof(buf) - 1);
137 if ((unsigned int) rc >= sizeof(buf))
138 perror_msg_and_fail("readlink");
139 buf[rc] = '\0';
140 printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s"
141 ", parent_tid=[%u<%s>]) = %d\n",
142 SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
143 "CLONE_PIDFD|SIGCHLD", *ptid, buf, pid);
144 }
145
146 return 0;
147 }