xref: /linux/tools/testing/selftests/clone3/clone3.c (revision 79997eda0d31bc68203c95ecb978773ee6ce7a1f)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 /* Based on Christian Brauner's clone3() example */
4 
5 #define _GNU_SOURCE
6 #include <errno.h>
7 #include <inttypes.h>
8 #include <linux/types.h>
9 #include <linux/sched.h>
10 #include <stdbool.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <sys/syscall.h>
15 #include <sys/types.h>
16 #include <sys/un.h>
17 #include <sys/wait.h>
18 #include <unistd.h>
19 #include <sched.h>
20 
21 #include "../kselftest.h"
22 #include "clone3_selftests.h"
23 
24 enum test_mode {
25 	CLONE3_ARGS_NO_TEST,
26 	CLONE3_ARGS_ALL_0,
27 	CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
28 	CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
29 	CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
30 	CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
31 };
32 
33 static int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode)
34 {
35 	struct __clone_args args = {
36 		.flags = flags,
37 		.exit_signal = SIGCHLD,
38 	};
39 
40 	struct clone_args_extended {
41 		struct __clone_args args;
42 		__aligned_u64 excess_space[2];
43 	} args_ext;
44 
45 	pid_t pid = -1;
46 	int status;
47 
48 	memset(&args_ext, 0, sizeof(args_ext));
49 	if (size > sizeof(struct __clone_args))
50 		args_ext.excess_space[1] = 1;
51 
52 	if (size == 0)
53 		size = sizeof(struct __clone_args);
54 
55 	switch (test_mode) {
56 	case CLONE3_ARGS_NO_TEST:
57 		/*
58 		 * Uses default 'flags' and 'SIGCHLD'
59 		 * assignment.
60 		 */
61 		break;
62 	case CLONE3_ARGS_ALL_0:
63 		args.flags = 0;
64 		args.exit_signal = 0;
65 		break;
66 	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG:
67 		args.exit_signal = 0xbadc0ded00000000ULL;
68 		break;
69 	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG:
70 		args.exit_signal = 0x0000000080000000ULL;
71 		break;
72 	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG:
73 		args.exit_signal = 0x0000000000000100ULL;
74 		break;
75 	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG:
76 		args.exit_signal = 0x00000000000000f0ULL;
77 		break;
78 	}
79 
80 	memcpy(&args_ext.args, &args, sizeof(struct __clone_args));
81 
82 	pid = sys_clone3((struct __clone_args *)&args_ext, size);
83 	if (pid < 0) {
84 		ksft_print_msg("%s - Failed to create new process\n",
85 				strerror(errno));
86 		return -errno;
87 	}
88 
89 	if (pid == 0) {
90 		ksft_print_msg("I am the child, my PID is %d\n", getpid());
91 		_exit(EXIT_SUCCESS);
92 	}
93 
94 	ksft_print_msg("I am the parent (%d). My child's pid is %d\n",
95 			getpid(), pid);
96 
97 	if (waitpid(-1, &status, __WALL) < 0) {
98 		ksft_print_msg("Child returned %s\n", strerror(errno));
99 		return -errno;
100 	}
101 	if (WEXITSTATUS(status))
102 		return WEXITSTATUS(status);
103 
104 	return 0;
105 }
106 
107 static bool test_clone3(uint64_t flags, size_t size, int expected,
108 			enum test_mode test_mode)
109 {
110 	int ret;
111 
112 	ksft_print_msg(
113 		"[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n",
114 		getpid(), flags, size);
115 	ret = call_clone3(flags, size, test_mode);
116 	ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n",
117 			getpid(), ret, expected);
118 	if (ret != expected) {
119 		ksft_print_msg(
120 			"[%d] Result (%d) is different than expected (%d)\n",
121 			getpid(), ret, expected);
122 		return false;
123 	}
124 
125 	return true;
126 }
127 
128 typedef bool (*filter_function)(void);
129 typedef size_t (*size_function)(void);
130 
131 static bool not_root(void)
132 {
133 	if (getuid() != 0) {
134 		ksft_print_msg("Not running as root\n");
135 		return true;
136 	}
137 
138 	return false;
139 }
140 
141 static bool no_timenamespace(void)
142 {
143 	if (not_root())
144 		return true;
145 
146 	if (!access("/proc/self/ns/time", F_OK))
147 		return false;
148 
149 	ksft_print_msg("Time namespaces are not supported\n");
150 	return true;
151 }
152 
153 static size_t page_size_plus_8(void)
154 {
155 	return getpagesize() + 8;
156 }
157 
158 struct test {
159 	const char *name;
160 	uint64_t flags;
161 	size_t size;
162 	size_function size_function;
163 	int expected;
164 	enum test_mode test_mode;
165 	filter_function filter;
166 };
167 
168 static const struct test tests[] = {
169 	{
170 		.name = "simple clone3()",
171 		.flags = 0,
172 		.size = 0,
173 		.expected = 0,
174 		.test_mode = CLONE3_ARGS_NO_TEST,
175 	},
176 	{
177 		.name = "clone3() in a new PID_NS",
178 		.flags = CLONE_NEWPID,
179 		.size = 0,
180 		.expected = 0,
181 		.test_mode = CLONE3_ARGS_NO_TEST,
182 		.filter = not_root,
183 	},
184 	{
185 		.name = "CLONE_ARGS_SIZE_VER0",
186 		.flags = 0,
187 		.size = CLONE_ARGS_SIZE_VER0,
188 		.expected = 0,
189 		.test_mode = CLONE3_ARGS_NO_TEST,
190 	},
191 	{
192 		.name = "CLONE_ARGS_SIZE_VER0 - 8",
193 		.flags = 0,
194 		.size = CLONE_ARGS_SIZE_VER0 - 8,
195 		.expected = -EINVAL,
196 		.test_mode = CLONE3_ARGS_NO_TEST,
197 	},
198 	{
199 		.name = "sizeof(struct clone_args) + 8",
200 		.flags = 0,
201 		.size = sizeof(struct __clone_args) + 8,
202 		.expected = 0,
203 		.test_mode = CLONE3_ARGS_NO_TEST,
204 	},
205 	{
206 		.name = "exit_signal with highest 32 bits non-zero",
207 		.flags = 0,
208 		.size = 0,
209 		.expected = -EINVAL,
210 		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
211 	},
212 	{
213 		.name = "negative 32-bit exit_signal",
214 		.flags = 0,
215 		.size = 0,
216 		.expected = -EINVAL,
217 		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
218 	},
219 	{
220 		.name = "exit_signal not fitting into CSIGNAL mask",
221 		.flags = 0,
222 		.size = 0,
223 		.expected = -EINVAL,
224 		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
225 	},
226 	{
227 		.name = "NSIG < exit_signal < CSIG",
228 		.flags = 0,
229 		.size = 0,
230 		.expected = -EINVAL,
231 		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
232 	},
233 	{
234 		.name = "Arguments sizeof(struct clone_args) + 8",
235 		.flags = 0,
236 		.size = sizeof(struct __clone_args) + 8,
237 		.expected = 0,
238 		.test_mode = CLONE3_ARGS_ALL_0,
239 	},
240 	{
241 		.name = "Arguments sizeof(struct clone_args) + 16",
242 		.flags = 0,
243 		.size = sizeof(struct __clone_args) + 16,
244 		.expected = -E2BIG,
245 		.test_mode = CLONE3_ARGS_ALL_0,
246 	},
247 	{
248 		.name = "Arguments sizeof(struct clone_arg) * 2",
249 		.flags = 0,
250 		.size = sizeof(struct __clone_args) + 16,
251 		.expected = -E2BIG,
252 		.test_mode = CLONE3_ARGS_ALL_0,
253 	},
254 	{
255 		.name = "Arguments > page size",
256 		.flags = 0,
257 		.size_function = page_size_plus_8,
258 		.expected = -E2BIG,
259 		.test_mode = CLONE3_ARGS_NO_TEST,
260 	},
261 	{
262 		.name = "CLONE_ARGS_SIZE_VER0 in a new PID NS",
263 		.flags = CLONE_NEWPID,
264 		.size = CLONE_ARGS_SIZE_VER0,
265 		.expected = 0,
266 		.test_mode = CLONE3_ARGS_NO_TEST,
267 		.filter = not_root,
268 	},
269 	{
270 		.name = "CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS",
271 		.flags = CLONE_NEWPID,
272 		.size = CLONE_ARGS_SIZE_VER0 - 8,
273 		.expected = -EINVAL,
274 		.test_mode = CLONE3_ARGS_NO_TEST,
275 	},
276 	{
277 		.name = "sizeof(struct clone_args) + 8 in a new PID NS",
278 		.flags = CLONE_NEWPID,
279 		.size = sizeof(struct __clone_args) + 8,
280 		.expected = 0,
281 		.test_mode = CLONE3_ARGS_NO_TEST,
282 		.filter = not_root,
283 	},
284 	{
285 		.name = "Arguments > page size in a new PID NS",
286 		.flags = CLONE_NEWPID,
287 		.size_function = page_size_plus_8,
288 		.expected = -E2BIG,
289 		.test_mode = CLONE3_ARGS_NO_TEST,
290 	},
291 	{
292 		.name = "New time NS",
293 		.flags = CLONE_NEWTIME,
294 		.size = 0,
295 		.expected = 0,
296 		.test_mode = CLONE3_ARGS_NO_TEST,
297 		.filter = no_timenamespace,
298 	},
299 	{
300 		.name = "exit signal (SIGCHLD) in flags",
301 		.flags = SIGCHLD,
302 		.size = 0,
303 		.expected = -EINVAL,
304 		.test_mode = CLONE3_ARGS_NO_TEST,
305 	},
306 };
307 
308 int main(int argc, char *argv[])
309 {
310 	size_t size;
311 	int i;
312 
313 	ksft_print_header();
314 	ksft_set_plan(ARRAY_SIZE(tests));
315 	test_clone3_supported();
316 
317 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
318 		if (tests[i].filter && tests[i].filter()) {
319 			ksft_test_result_skip("%s\n", tests[i].name);
320 			continue;
321 		}
322 
323 		if (tests[i].size_function)
324 			size = tests[i].size_function();
325 		else
326 			size = tests[i].size;
327 
328 		ksft_print_msg("Running test '%s'\n", tests[i].name);
329 
330 		ksft_test_result(test_clone3(tests[i].flags, size,
331 					     tests[i].expected,
332 					     tests[i].test_mode),
333 				 "%s\n", tests[i].name);
334 	}
335 
336 	ksft_finished();
337 }
338