Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/clone3/clone3.c
26285 views
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("waitpid() returned %s\n", strerror(errno));
99
return -errno;
100
}
101
if (!WIFEXITED(status)) {
102
ksft_print_msg("Child did not exit normally, status 0x%x\n",
103
status);
104
return EXIT_FAILURE;
105
}
106
if (WEXITSTATUS(status))
107
return WEXITSTATUS(status);
108
109
return 0;
110
}
111
112
static bool test_clone3(uint64_t flags, size_t size, int expected,
113
enum test_mode test_mode)
114
{
115
int ret;
116
117
ksft_print_msg(
118
"[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n",
119
getpid(), flags, size);
120
ret = call_clone3(flags, size, test_mode);
121
ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n",
122
getpid(), ret, expected);
123
if (ret != expected) {
124
ksft_print_msg(
125
"[%d] Result (%d) is different than expected (%d)\n",
126
getpid(), ret, expected);
127
return false;
128
}
129
130
return true;
131
}
132
133
typedef bool (*filter_function)(void);
134
typedef size_t (*size_function)(void);
135
136
static bool not_root(void)
137
{
138
if (getuid() != 0) {
139
ksft_print_msg("Not running as root\n");
140
return true;
141
}
142
143
return false;
144
}
145
146
static bool no_timenamespace(void)
147
{
148
if (not_root())
149
return true;
150
151
if (!access("/proc/self/ns/time", F_OK))
152
return false;
153
154
ksft_print_msg("Time namespaces are not supported\n");
155
return true;
156
}
157
158
static size_t page_size_plus_8(void)
159
{
160
return getpagesize() + 8;
161
}
162
163
struct test {
164
const char *name;
165
uint64_t flags;
166
size_t size;
167
size_function size_function;
168
int expected;
169
enum test_mode test_mode;
170
filter_function filter;
171
};
172
173
static const struct test tests[] = {
174
{
175
.name = "simple clone3()",
176
.flags = 0,
177
.size = 0,
178
.expected = 0,
179
.test_mode = CLONE3_ARGS_NO_TEST,
180
},
181
{
182
.name = "clone3() in a new PID_NS",
183
.flags = CLONE_NEWPID,
184
.size = 0,
185
.expected = 0,
186
.test_mode = CLONE3_ARGS_NO_TEST,
187
.filter = not_root,
188
},
189
{
190
.name = "CLONE_ARGS_SIZE_VER0",
191
.flags = 0,
192
.size = CLONE_ARGS_SIZE_VER0,
193
.expected = 0,
194
.test_mode = CLONE3_ARGS_NO_TEST,
195
},
196
{
197
.name = "CLONE_ARGS_SIZE_VER0 - 8",
198
.flags = 0,
199
.size = CLONE_ARGS_SIZE_VER0 - 8,
200
.expected = -EINVAL,
201
.test_mode = CLONE3_ARGS_NO_TEST,
202
},
203
{
204
.name = "sizeof(struct clone_args) + 8",
205
.flags = 0,
206
.size = sizeof(struct __clone_args) + 8,
207
.expected = 0,
208
.test_mode = CLONE3_ARGS_NO_TEST,
209
},
210
{
211
.name = "exit_signal with highest 32 bits non-zero",
212
.flags = 0,
213
.size = 0,
214
.expected = -EINVAL,
215
.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
216
},
217
{
218
.name = "negative 32-bit exit_signal",
219
.flags = 0,
220
.size = 0,
221
.expected = -EINVAL,
222
.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
223
},
224
{
225
.name = "exit_signal not fitting into CSIGNAL mask",
226
.flags = 0,
227
.size = 0,
228
.expected = -EINVAL,
229
.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
230
},
231
{
232
.name = "NSIG < exit_signal < CSIG",
233
.flags = 0,
234
.size = 0,
235
.expected = -EINVAL,
236
.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
237
},
238
{
239
.name = "Arguments sizeof(struct clone_args) + 8",
240
.flags = 0,
241
.size = sizeof(struct __clone_args) + 8,
242
.expected = 0,
243
.test_mode = CLONE3_ARGS_ALL_0,
244
},
245
{
246
.name = "Arguments sizeof(struct clone_args) + 16",
247
.flags = 0,
248
.size = sizeof(struct __clone_args) + 16,
249
.expected = -E2BIG,
250
.test_mode = CLONE3_ARGS_ALL_0,
251
},
252
{
253
.name = "Arguments sizeof(struct clone_arg) * 2",
254
.flags = 0,
255
.size = sizeof(struct __clone_args) + 16,
256
.expected = -E2BIG,
257
.test_mode = CLONE3_ARGS_ALL_0,
258
},
259
{
260
.name = "Arguments > page size",
261
.flags = 0,
262
.size_function = page_size_plus_8,
263
.expected = -E2BIG,
264
.test_mode = CLONE3_ARGS_NO_TEST,
265
},
266
{
267
.name = "CLONE_ARGS_SIZE_VER0 in a new PID NS",
268
.flags = CLONE_NEWPID,
269
.size = CLONE_ARGS_SIZE_VER0,
270
.expected = 0,
271
.test_mode = CLONE3_ARGS_NO_TEST,
272
.filter = not_root,
273
},
274
{
275
.name = "CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS",
276
.flags = CLONE_NEWPID,
277
.size = CLONE_ARGS_SIZE_VER0 - 8,
278
.expected = -EINVAL,
279
.test_mode = CLONE3_ARGS_NO_TEST,
280
},
281
{
282
.name = "sizeof(struct clone_args) + 8 in a new PID NS",
283
.flags = CLONE_NEWPID,
284
.size = sizeof(struct __clone_args) + 8,
285
.expected = 0,
286
.test_mode = CLONE3_ARGS_NO_TEST,
287
.filter = not_root,
288
},
289
{
290
.name = "Arguments > page size in a new PID NS",
291
.flags = CLONE_NEWPID,
292
.size_function = page_size_plus_8,
293
.expected = -E2BIG,
294
.test_mode = CLONE3_ARGS_NO_TEST,
295
},
296
{
297
.name = "New time NS",
298
.flags = CLONE_NEWTIME,
299
.size = 0,
300
.expected = 0,
301
.test_mode = CLONE3_ARGS_NO_TEST,
302
.filter = no_timenamespace,
303
},
304
{
305
.name = "exit signal (SIGCHLD) in flags",
306
.flags = SIGCHLD,
307
.size = 0,
308
.expected = -EINVAL,
309
.test_mode = CLONE3_ARGS_NO_TEST,
310
},
311
};
312
313
int main(int argc, char *argv[])
314
{
315
size_t size;
316
int i;
317
318
ksft_print_header();
319
ksft_set_plan(ARRAY_SIZE(tests));
320
test_clone3_supported();
321
322
for (i = 0; i < ARRAY_SIZE(tests); i++) {
323
if (tests[i].filter && tests[i].filter()) {
324
ksft_test_result_skip("%s\n", tests[i].name);
325
continue;
326
}
327
328
if (tests[i].size_function)
329
size = tests[i].size_function();
330
else
331
size = tests[i].size;
332
333
ksft_print_msg("Running test '%s'\n", tests[i].name);
334
335
ksft_test_result(test_clone3(tests[i].flags, size,
336
tests[i].expected,
337
tests[i].test_mode),
338
"%s\n", tests[i].name);
339
}
340
341
ksft_finished();
342
}
343
344