Merge tag 'siox/for-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleine...
[linux-block.git] / tools / testing / selftests / clone3 / clone3.c
CommitLineData
17a81069
AR
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>
34dce23f 10#include <stdbool.h>
17a81069
AR
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"
41585bbe 22#include "clone3_selftests.h"
17a81069 23
17a81069
AR
24enum 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
17a81069
AR
33static int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode)
34{
e953aeaa 35 struct __clone_args args = {
17a81069
AR
36 .flags = flags,
37 .exit_signal = SIGCHLD,
38 };
39
40 struct clone_args_extended {
e953aeaa 41 struct __clone_args args;
17a81069
AR
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));
e953aeaa 49 if (size > sizeof(struct __clone_args))
17a81069
AR
50 args_ext.excess_space[1] = 1;
51
52 if (size == 0)
e953aeaa 53 size = sizeof(struct __clone_args);
17a81069
AR
54
55 switch (test_mode) {
a531b0c2
AR
56 case CLONE3_ARGS_NO_TEST:
57 /*
58 * Uses default 'flags' and 'SIGCHLD'
59 * assignment.
60 */
61 break;
17a81069
AR
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
e953aeaa 80 memcpy(&args_ext.args, &args, sizeof(struct __clone_args));
17a81069 81
e953aeaa 82 pid = sys_clone3((struct __clone_args *)&args_ext, size);
17a81069
AR
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
34dce23f
MB
107static bool test_clone3(uint64_t flags, size_t size, int expected,
108 enum test_mode test_mode)
17a81069
AR
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);
34dce23f
MB
118 if (ret != expected) {
119 ksft_print_msg(
17a81069
AR
120 "[%d] Result (%d) is different than expected (%d)\n",
121 getpid(), ret, expected);
34dce23f
MB
122 return false;
123 }
17a81069 124
34dce23f
MB
125 return true;
126}
17a81069 127
34dce23f
MB
128typedef bool (*filter_function)(void);
129typedef size_t (*size_function)(void);
17a81069 130
34dce23f
MB
131static bool not_root(void)
132{
133 if (getuid() != 0) {
134 ksft_print_msg("Not running as root\n");
135 return true;
136 }
17a81069 137
34dce23f
MB
138 return false;
139}
17a81069 140
ecae0bd5
LT
141static bool no_timenamespace(void)
142{
143 if (not_root())
144 return true;
17a81069 145
ecae0bd5
LT
146 if (!access("/proc/self/ns/time", F_OK))
147 return false;
17a81069 148
ecae0bd5
LT
149 ksft_print_msg("Time namespaces are not supported\n");
150 return true;
151}
17a81069 152
34dce23f
MB
153static size_t page_size_plus_8(void)
154{
155 return getpagesize() + 8;
156}
17a81069 157
34dce23f
MB
158struct 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};
17a81069 167
34dce23f
MB
168static 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,
ecae0bd5 297 .filter = no_timenamespace,
34dce23f
MB
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};
17a81069 307
34dce23f
MB
308int main(int argc, char *argv[])
309{
310 size_t size;
311 int i;
17a81069 312
34dce23f
MB
313 ksft_print_header();
314 ksft_set_plan(ARRAY_SIZE(tests));
315 test_clone3_supported();
17a81069 316
34dce23f
MB
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 }
17a81069 322
34dce23f
MB
323 if (tests[i].size_function)
324 size = tests[i].size_function();
325 else
326 size = tests[i].size;
17a81069 327
34dce23f 328 ksft_print_msg("Running test '%s'\n", tests[i].name);
515bddf0 329
34dce23f
MB
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 }
c4f461a1 335
d95debbd 336 ksft_finished();
17a81069 337}