1 // SPDX-License-Identifier: GPL-2.0
3 /* Based on Christian Brauner's clone3() example */
8 #include <linux/types.h>
9 #include <linux/sched.h>
13 #include <sys/syscall.h>
14 #include <sys/types.h>
20 #include "../kselftest.h"
21 #include "clone3_selftests.h"
24 * Different sizes of struct clone_args
26 #ifndef CLONE3_ARGS_SIZE_V0
27 #define CLONE3_ARGS_SIZE_V0 64
33 CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG
,
34 CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG
,
35 CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG
,
36 CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG
,
39 static int call_clone3(uint64_t flags
, size_t size
, enum test_mode test_mode
)
41 struct clone_args args
= {
43 .exit_signal
= SIGCHLD
,
46 struct clone_args_extended
{
47 struct clone_args args
;
48 __aligned_u64 excess_space
[2];
54 memset(&args_ext
, 0, sizeof(args_ext
));
55 if (size
> sizeof(struct clone_args
))
56 args_ext
.excess_space
[1] = 1;
59 size
= sizeof(struct clone_args
);
62 case CLONE3_ARGS_ALL_0
:
66 case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG
:
67 args
.exit_signal
= 0xbadc0ded00000000ULL
;
69 case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG
:
70 args
.exit_signal
= 0x0000000080000000ULL
;
72 case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG
:
73 args
.exit_signal
= 0x0000000000000100ULL
;
75 case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG
:
76 args
.exit_signal
= 0x00000000000000f0ULL
;
80 memcpy(&args_ext
.args
, &args
, sizeof(struct clone_args
));
82 pid
= sys_clone3((struct clone_args
*)&args_ext
, size
);
84 ksft_print_msg("%s - Failed to create new process\n",
90 ksft_print_msg("I am the child, my PID is %d\n", getpid());
94 ksft_print_msg("I am the parent (%d). My child's pid is %d\n",
97 if (waitpid(-1, &status
, __WALL
) < 0) {
98 ksft_print_msg("Child returned %s\n", strerror(errno
));
101 if (WEXITSTATUS(status
))
102 return WEXITSTATUS(status
);
107 static void test_clone3(uint64_t flags
, size_t size
, int expected
,
108 enum test_mode test_mode
)
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
);
119 ksft_test_result_fail(
120 "[%d] Result (%d) is different than expected (%d)\n",
121 getpid(), ret
, expected
);
123 ksft_test_result_pass(
124 "[%d] Result (%d) matches expectation (%d)\n",
125 getpid(), ret
, expected
);
128 int main(int argc
, char *argv
[])
132 uid_t uid
= getuid();
134 test_clone3_supported();
138 /* Just a simple clone3() should return 0.*/
139 test_clone3(0, 0, 0, CLONE3_ARGS_NO_TEST
);
141 /* Do a clone3() in a new PID NS.*/
143 test_clone3(CLONE_NEWPID
, 0, 0, CLONE3_ARGS_NO_TEST
);
145 ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
147 /* Do a clone3() with CLONE3_ARGS_SIZE_V0. */
148 test_clone3(0, CLONE3_ARGS_SIZE_V0
, 0, CLONE3_ARGS_NO_TEST
);
150 /* Do a clone3() with CLONE3_ARGS_SIZE_V0 - 8 */
151 test_clone3(0, CLONE3_ARGS_SIZE_V0
- 8, -EINVAL
, CLONE3_ARGS_NO_TEST
);
153 /* Do a clone3() with sizeof(struct clone_args) + 8 */
154 test_clone3(0, sizeof(struct clone_args
) + 8, 0, CLONE3_ARGS_NO_TEST
);
156 /* Do a clone3() with exit_signal having highest 32 bits non-zero */
157 test_clone3(0, 0, -EINVAL
, CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG
);
159 /* Do a clone3() with negative 32-bit exit_signal */
160 test_clone3(0, 0, -EINVAL
, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG
);
162 /* Do a clone3() with exit_signal not fitting into CSIGNAL mask */
163 test_clone3(0, 0, -EINVAL
, CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG
);
165 /* Do a clone3() with NSIG < exit_signal < CSIG */
166 test_clone3(0, 0, -EINVAL
, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG
);
168 test_clone3(0, sizeof(struct clone_args
) + 8, 0, CLONE3_ARGS_ALL_0
);
170 test_clone3(0, sizeof(struct clone_args
) + 16, -E2BIG
,
173 test_clone3(0, sizeof(struct clone_args
) * 2, -E2BIG
,
176 /* Do a clone3() with > page size */
177 test_clone3(0, getpagesize() + 8, -E2BIG
, CLONE3_ARGS_NO_TEST
);
179 /* Do a clone3() with CLONE3_ARGS_SIZE_V0 in a new PID NS. */
181 test_clone3(CLONE_NEWPID
, CLONE3_ARGS_SIZE_V0
, 0,
182 CLONE3_ARGS_NO_TEST
);
184 ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
186 /* Do a clone3() with CLONE3_ARGS_SIZE_V0 - 8 in a new PID NS */
187 test_clone3(CLONE_NEWPID
, CLONE3_ARGS_SIZE_V0
- 8, -EINVAL
,
188 CLONE3_ARGS_NO_TEST
);
190 /* Do a clone3() with sizeof(struct clone_args) + 8 in a new PID NS */
192 test_clone3(CLONE_NEWPID
, sizeof(struct clone_args
) + 8, 0,
193 CLONE3_ARGS_NO_TEST
);
195 ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
197 /* Do a clone3() with > page size in a new PID NS */
198 test_clone3(CLONE_NEWPID
, getpagesize() + 8, -E2BIG
,
199 CLONE3_ARGS_NO_TEST
);
201 return !ksft_get_fail_cnt() ? ksft_exit_pass() : ksft_exit_fail();