1139749Simp// SPDX-License-Identifier: GPL-2.0
2113584Ssimokawa
3103285Sikob/* Based on Christian Brauner's clone3() example */
4103285Sikob
5103285Sikob#define _GNU_SOURCE
6103285Sikob#include <errno.h>
7103285Sikob#include <inttypes.h>
8103285Sikob#include <linux/types.h>
9103285Sikob#include <linux/sched.h>
10103285Sikob#include <stdbool.h>
11103285Sikob#include <stdint.h>
12103285Sikob#include <stdio.h>
13103285Sikob#include <stdlib.h>
14103285Sikob#include <sys/syscall.h>
15103285Sikob#include <sys/types.h>
16103285Sikob#include <sys/un.h>
17103285Sikob#include <sys/wait.h>
18103285Sikob#include <unistd.h>
19103285Sikob#include <sched.h>
20103285Sikob
21103285Sikob#include "../kselftest.h"
22103285Sikob#include "clone3_selftests.h"
23103285Sikob
24103285Sikobenum test_mode {
25103285Sikob	CLONE3_ARGS_NO_TEST,
26103285Sikob	CLONE3_ARGS_ALL_0,
27103285Sikob	CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
28103285Sikob	CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
29103285Sikob	CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
30103285Sikob	CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
31103285Sikob};
32103285Sikob
33103285Sikobstatic int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode)
34103285Sikob{
35103285Sikob	struct __clone_args args = {
36103285Sikob		.flags = flags,
37103285Sikob		.exit_signal = SIGCHLD,
38127468Ssimokawa	};
39127468Ssimokawa
40127468Ssimokawa	struct clone_args_extended {
41127468Ssimokawa		struct __clone_args args;
42103285Sikob		__aligned_u64 excess_space[2];
43103285Sikob	} args_ext;
44103285Sikob
45103285Sikob	pid_t pid = -1;
46103285Sikob	int status;
47103285Sikob
48103285Sikob	memset(&args_ext, 0, sizeof(args_ext));
49113584Ssimokawa	if (size > sizeof(struct __clone_args))
50170374Ssimokawa		args_ext.excess_space[1] = 1;
51170374Ssimokawa
52113584Ssimokawa	if (size == 0)
53103285Sikob		size = sizeof(struct __clone_args);
54103285Sikob
55169130Ssimokawa	switch (test_mode) {
56169130Ssimokawa	case CLONE3_ARGS_NO_TEST:
57103285Sikob		/*
58129585Sdfr		 * Uses default 'flags' and 'SIGCHLD'
59103285Sikob		 * assignment.
60129585Sdfr		 */
61129585Sdfr		break;
62129585Sdfr	case CLONE3_ARGS_ALL_0:
63129585Sdfr		args.flags = 0;
64103285Sikob		args.exit_signal = 0;
65103285Sikob		break;
66103285Sikob	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG:
67129585Sdfr		args.exit_signal = 0xbadc0ded00000000ULL;
68103285Sikob		break;
69106810Ssimokawa	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG:
70129585Sdfr		args.exit_signal = 0x0000000080000000ULL;
71103285Sikob		break;
72103285Sikob	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG:
73103285Sikob		args.exit_signal = 0x0000000000000100ULL;
74110193Ssimokawa		break;
75103285Sikob	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG:
76109645Ssimokawa		args.exit_signal = 0x00000000000000f0ULL;
77103285Sikob		break;
78127468Ssimokawa	}
79130585Sphk
80103285Sikob	memcpy(&args_ext.args, &args, sizeof(struct __clone_args));
81103285Sikob
82103285Sikob	pid = sys_clone3((struct __clone_args *)&args_ext, size);
83109645Ssimokawa	if (pid < 0) {
84103285Sikob		ksft_print_msg("%s - Failed to create new process\n",
85103285Sikob				strerror(errno));
86103285Sikob		return -errno;
87109645Ssimokawa	}
88103285Sikob
89103285Sikob	if (pid == 0) {
90103285Sikob		ksft_print_msg("I am the child, my PID is %d\n", getpid());
91124169Ssimokawa		_exit(EXIT_SUCCESS);
92124169Ssimokawa	}
93103285Sikob
94103285Sikob	ksft_print_msg("I am the parent (%d). My child's pid is %d\n",
95103285Sikob			getpid(), pid);
96103285Sikob
97103285Sikob	if (waitpid(-1, &status, __WALL) < 0) {
98103285Sikob		ksft_print_msg("Child returned %s\n", strerror(errno));
99103285Sikob		return -errno;
100103285Sikob	}
101103285Sikob	if (WEXITSTATUS(status))
102103285Sikob		return WEXITSTATUS(status);
103170374Ssimokawa
104103285Sikob	return 0;
105103285Sikob}
106103285Sikob
107103285Sikobstatic bool test_clone3(uint64_t flags, size_t size, int expected,
108103285Sikob			enum test_mode test_mode)
109129585Sdfr{
110103285Sikob	int ret;
111103285Sikob
112103285Sikob	ksft_print_msg(
113103285Sikob		"[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n",
114103285Sikob		getpid(), flags, size);
115103285Sikob	ret = call_clone3(flags, size, test_mode);
116103285Sikob	ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n",
117103285Sikob			getpid(), ret, expected);
118103285Sikob	if (ret != expected) {
119129585Sdfr		ksft_print_msg(
120169806Ssimokawa			"[%d] Result (%d) is different than expected (%d)\n",
121116978Ssimokawa			getpid(), ret, expected);
122103285Sikob		return false;
123103285Sikob	}
124103285Sikob
125103285Sikob	return true;
126103285Sikob}
127103285Sikob
128103285Sikobtypedef bool (*filter_function)(void);
129103285Sikobtypedef size_t (*size_function)(void);
130103285Sikob
131103285Sikobstatic bool not_root(void)
132109814Ssimokawa{
133103285Sikob	if (getuid() != 0) {
134103285Sikob		ksft_print_msg("Not running as root\n");
135169130Ssimokawa		return true;
136171457Ssimokawa	}
137171513Ssimokawa
138103285Sikob	return false;
139110193Ssimokawa}
140103285Sikob
141103285Sikobstatic bool no_timenamespace(void)
142129585Sdfr{
143103285Sikob	if (not_root())
144129585Sdfr		return true;
145116376Ssimokawa
146116376Ssimokawa	if (!access("/proc/self/ns/time", F_OK))
147116376Ssimokawa		return false;
148103285Sikob
149103285Sikob	ksft_print_msg("Time namespaces are not supported\n");
150108853Ssimokawa	return true;
151110193Ssimokawa}
152110193Ssimokawa
153170374Ssimokawastatic size_t page_size_plus_8(void)
154129585Sdfr{
155124169Ssimokawa	return getpagesize() + 8;
156129585Sdfr}
157130585Sphk
158124169Ssimokawastruct test {
159124169Ssimokawa	const char *name;
160124169Ssimokawa	uint64_t flags;
161124169Ssimokawa	size_t size;
162124169Ssimokawa	size_function size_function;
163124169Ssimokawa	int expected;
164124169Ssimokawa	enum test_mode test_mode;
165129585Sdfr	filter_function filter;
166129585Sdfr};
167103285Sikob
168113584Ssimokawastatic const struct test tests[] = {
169170374Ssimokawa	{
170170374Ssimokawa		.name = "simple clone3()",
171170374Ssimokawa		.flags = 0,
172170374Ssimokawa		.size = 0,
173103285Sikob		.expected = 0,
174103285Sikob		.test_mode = CLONE3_ARGS_NO_TEST,
175103285Sikob	},
176170374Ssimokawa	{
177170374Ssimokawa		.name = "clone3() in a new PID_NS",
178170374Ssimokawa		.flags = CLONE_NEWPID,
179170374Ssimokawa		.size = 0,
180170374Ssimokawa		.expected = 0,
181109645Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
182109645Ssimokawa		.filter = not_root,
183109645Ssimokawa	},
184109645Ssimokawa	{
185109645Ssimokawa		.name = "CLONE_ARGS_SIZE_VER0",
186109645Ssimokawa		.flags = 0,
187109645Ssimokawa		.size = CLONE_ARGS_SIZE_VER0,
188109645Ssimokawa		.expected = 0,
189109645Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
190109645Ssimokawa	},
191109645Ssimokawa	{
192109645Ssimokawa		.name = "CLONE_ARGS_SIZE_VER0 - 8",
193109645Ssimokawa		.flags = 0,
194109645Ssimokawa		.size = CLONE_ARGS_SIZE_VER0 - 8,
195124169Ssimokawa		.expected = -EINVAL,
196118293Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
197169130Ssimokawa	},
198109645Ssimokawa	{
199109645Ssimokawa		.name = "sizeof(struct clone_args) + 8",
200109645Ssimokawa		.flags = 0,
201113584Ssimokawa		.size = sizeof(struct __clone_args) + 8,
202109645Ssimokawa		.expected = 0,
203109645Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
204109645Ssimokawa	},
205109645Ssimokawa	{
206109645Ssimokawa		.name = "exit_signal with highest 32 bits non-zero",
207109890Ssimokawa		.flags = 0,
208109645Ssimokawa		.size = 0,
209109645Ssimokawa		.expected = -EINVAL,
210109645Ssimokawa		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
211124169Ssimokawa	},
212109645Ssimokawa	{
213109645Ssimokawa		.name = "negative 32-bit exit_signal",
214109645Ssimokawa		.flags = 0,
215113584Ssimokawa		.size = 0,
216111942Ssimokawa		.expected = -EINVAL,
217109645Ssimokawa		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
218109645Ssimokawa	},
219109645Ssimokawa	{
220111942Ssimokawa		.name = "exit_signal not fitting into CSIGNAL mask",
221109645Ssimokawa		.flags = 0,
222109645Ssimokawa		.size = 0,
223109645Ssimokawa		.expected = -EINVAL,
224120660Ssimokawa		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
225120660Ssimokawa	},
226169130Ssimokawa	{
227109645Ssimokawa		.name = "NSIG < exit_signal < CSIG",
228109645Ssimokawa		.flags = 0,
229169130Ssimokawa		.size = 0,
230109645Ssimokawa		.expected = -EINVAL,
231109645Ssimokawa		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
232103285Sikob	},
233103285Sikob	{
234103285Sikob		.name = "Arguments sizeof(struct clone_args) + 8",
235103285Sikob		.flags = 0,
236110577Ssimokawa		.size = sizeof(struct __clone_args) + 8,
237113584Ssimokawa		.expected = 0,
238170374Ssimokawa		.test_mode = CLONE3_ARGS_ALL_0,
239170374Ssimokawa	},
240170374Ssimokawa	{
241170374Ssimokawa		.name = "Arguments sizeof(struct clone_args) + 16",
242170374Ssimokawa		.flags = 0,
243170374Ssimokawa		.size = sizeof(struct __clone_args) + 16,
244170374Ssimokawa		.expected = -E2BIG,
245170374Ssimokawa		.test_mode = CLONE3_ARGS_ALL_0,
246170374Ssimokawa	},
247170374Ssimokawa	{
248169119Ssimokawa		.name = "Arguments sizeof(struct clone_arg) * 2",
249167632Ssimokawa		.flags = 0,
250103285Sikob		.size = sizeof(struct __clone_args) + 16,
251120660Ssimokawa		.expected = -E2BIG,
252129585Sdfr		.test_mode = CLONE3_ARGS_ALL_0,
253129585Sdfr	},
254129585Sdfr	{
255103285Sikob		.name = "Arguments > page size",
256103285Sikob		.flags = 0,
257103285Sikob		.size_function = page_size_plus_8,
258169119Ssimokawa		.expected = -E2BIG,
259110269Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
260103285Sikob	},
261120660Ssimokawa	{
262120660Ssimokawa		.name = "CLONE_ARGS_SIZE_VER0 in a new PID NS",
263120660Ssimokawa		.flags = CLONE_NEWPID,
264120660Ssimokawa		.size = CLONE_ARGS_SIZE_VER0,
265120660Ssimokawa		.expected = 0,
266120660Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
267129585Sdfr		.filter = not_root,
268120660Ssimokawa	},
269120660Ssimokawa	{
270129585Sdfr		.name = "CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS",
271124169Ssimokawa		.flags = CLONE_NEWPID,
272124169Ssimokawa		.size = CLONE_ARGS_SIZE_VER0 - 8,
273124169Ssimokawa		.expected = -EINVAL,
274124169Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
275124169Ssimokawa	},
276124169Ssimokawa	{
277124169Ssimokawa		.name = "sizeof(struct clone_args) + 8 in a new PID NS",
278124169Ssimokawa		.flags = CLONE_NEWPID,
279124169Ssimokawa		.size = sizeof(struct __clone_args) + 8,
280124169Ssimokawa		.expected = 0,
281124169Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
282169130Ssimokawa		.filter = not_root,
283169130Ssimokawa	},
284169130Ssimokawa	{
285124169Ssimokawa		.name = "Arguments > page size in a new PID NS",
286169117Ssimokawa		.flags = CLONE_NEWPID,
287129585Sdfr		.size_function = page_size_plus_8,
288124169Ssimokawa		.expected = -E2BIG,
289124169Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
290170374Ssimokawa	},
291170374Ssimokawa	{
292124169Ssimokawa		.name = "New time NS",
293124169Ssimokawa		.flags = CLONE_NEWTIME,
294124169Ssimokawa		.size = 0,
295129585Sdfr		.expected = 0,
296124169Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
297124169Ssimokawa		.filter = no_timenamespace,
298124169Ssimokawa	},
299148868Srwatson	{
300170374Ssimokawa		.name = "exit signal (SIGCHLD) in flags",
301103285Sikob		.flags = SIGCHLD,
302103285Sikob		.size = 0,
303103285Sikob		.expected = -EINVAL,
304170400Ssimokawa		.test_mode = CLONE3_ARGS_NO_TEST,
305103285Sikob	},
306127468Ssimokawa};
307127468Ssimokawa
308127468Ssimokawaint main(int argc, char *argv[])
309103285Sikob{
310127468Ssimokawa	size_t size;
311103285Sikob	int i;
312127468Ssimokawa
313127468Ssimokawa	ksft_print_header();
314127468Ssimokawa	ksft_set_plan(ARRAY_SIZE(tests));
315170374Ssimokawa	test_clone3_supported();
316111615Ssimokawa
317111615Ssimokawa	for (i = 0; i < ARRAY_SIZE(tests); i++) {
318127468Ssimokawa		if (tests[i].filter && tests[i].filter()) {
319120660Ssimokawa			ksft_test_result_skip("%s\n", tests[i].name);
320120660Ssimokawa			continue;
321120660Ssimokawa		}
322120660Ssimokawa
323120660Ssimokawa		if (tests[i].size_function)
324120660Ssimokawa			size = tests[i].size_function();
325120660Ssimokawa		else
326120660Ssimokawa			size = tests[i].size;
327120660Ssimokawa
328120660Ssimokawa		ksft_print_msg("Running test '%s'\n", tests[i].name);
329120660Ssimokawa
330120660Ssimokawa		ksft_test_result(test_clone3(tests[i].flags, size,
331120660Ssimokawa					     tests[i].expected,
332120660Ssimokawa					     tests[i].test_mode),
333120660Ssimokawa				 "%s\n", tests[i].name);
334121780Ssimokawa	}
335120660Ssimokawa
336120660Ssimokawa	ksft_finished();
337110195Ssimokawa}
338110269Ssimokawa