]> Git Repo - linux.git/blob - tools/testing/selftests/clone3/clone3.c
scsi: zfcp: Trace when request remove fails after qdio send fails
[linux.git] / tools / testing / selftests / clone3 / clone3.c
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 <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <sys/syscall.h>
14 #include <sys/types.h>
15 #include <sys/un.h>
16 #include <sys/wait.h>
17 #include <unistd.h>
18 #include <sched.h>
19
20 #include "../kselftest.h"
21 #include "clone3_selftests.h"
22
23 enum test_mode {
24         CLONE3_ARGS_NO_TEST,
25         CLONE3_ARGS_ALL_0,
26         CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
27         CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
28         CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
29         CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
30 };
31
32 static int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode)
33 {
34         struct __clone_args args = {
35                 .flags = flags,
36                 .exit_signal = SIGCHLD,
37         };
38
39         struct clone_args_extended {
40                 struct __clone_args args;
41                 __aligned_u64 excess_space[2];
42         } args_ext;
43
44         pid_t pid = -1;
45         int status;
46
47         memset(&args_ext, 0, sizeof(args_ext));
48         if (size > sizeof(struct __clone_args))
49                 args_ext.excess_space[1] = 1;
50
51         if (size == 0)
52                 size = sizeof(struct __clone_args);
53
54         switch (test_mode) {
55         case CLONE3_ARGS_NO_TEST:
56                 /*
57                  * Uses default 'flags' and 'SIGCHLD'
58                  * assignment.
59                  */
60                 break;
61         case CLONE3_ARGS_ALL_0:
62                 args.flags = 0;
63                 args.exit_signal = 0;
64                 break;
65         case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG:
66                 args.exit_signal = 0xbadc0ded00000000ULL;
67                 break;
68         case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG:
69                 args.exit_signal = 0x0000000080000000ULL;
70                 break;
71         case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG:
72                 args.exit_signal = 0x0000000000000100ULL;
73                 break;
74         case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG:
75                 args.exit_signal = 0x00000000000000f0ULL;
76                 break;
77         }
78
79         memcpy(&args_ext.args, &args, sizeof(struct __clone_args));
80
81         pid = sys_clone3((struct __clone_args *)&args_ext, size);
82         if (pid < 0) {
83                 ksft_print_msg("%s - Failed to create new process\n",
84                                 strerror(errno));
85                 return -errno;
86         }
87
88         if (pid == 0) {
89                 ksft_print_msg("I am the child, my PID is %d\n", getpid());
90                 _exit(EXIT_SUCCESS);
91         }
92
93         ksft_print_msg("I am the parent (%d). My child's pid is %d\n",
94                         getpid(), pid);
95
96         if (waitpid(-1, &status, __WALL) < 0) {
97                 ksft_print_msg("Child returned %s\n", strerror(errno));
98                 return -errno;
99         }
100         if (WEXITSTATUS(status))
101                 return WEXITSTATUS(status);
102
103         return 0;
104 }
105
106 static void test_clone3(uint64_t flags, size_t size, int expected,
107                        enum test_mode test_mode)
108 {
109         int ret;
110
111         ksft_print_msg(
112                 "[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n",
113                 getpid(), flags, size);
114         ret = call_clone3(flags, size, test_mode);
115         ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n",
116                         getpid(), ret, expected);
117         if (ret != expected)
118                 ksft_test_result_fail(
119                         "[%d] Result (%d) is different than expected (%d)\n",
120                         getpid(), ret, expected);
121         else
122                 ksft_test_result_pass(
123                         "[%d] Result (%d) matches expectation (%d)\n",
124                         getpid(), ret, expected);
125 }
126
127 int main(int argc, char *argv[])
128 {
129         uid_t uid = getuid();
130
131         ksft_print_header();
132         ksft_set_plan(17);
133         test_clone3_supported();
134
135         /* Just a simple clone3() should return 0.*/
136         test_clone3(0, 0, 0, CLONE3_ARGS_NO_TEST);
137
138         /* Do a clone3() in a new PID NS.*/
139         if (uid == 0)
140                 test_clone3(CLONE_NEWPID, 0, 0, CLONE3_ARGS_NO_TEST);
141         else
142                 ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
143
144         /* Do a clone3() with CLONE_ARGS_SIZE_VER0. */
145         test_clone3(0, CLONE_ARGS_SIZE_VER0, 0, CLONE3_ARGS_NO_TEST);
146
147         /* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 */
148         test_clone3(0, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL, CLONE3_ARGS_NO_TEST);
149
150         /* Do a clone3() with sizeof(struct clone_args) + 8 */
151         test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_NO_TEST);
152
153         /* Do a clone3() with exit_signal having highest 32 bits non-zero */
154         test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG);
155
156         /* Do a clone3() with negative 32-bit exit_signal */
157         test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG);
158
159         /* Do a clone3() with exit_signal not fitting into CSIGNAL mask */
160         test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG);
161
162         /* Do a clone3() with NSIG < exit_signal < CSIG */
163         test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG);
164
165         test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_ALL_0);
166
167         test_clone3(0, sizeof(struct __clone_args) + 16, -E2BIG,
168                         CLONE3_ARGS_ALL_0);
169
170         test_clone3(0, sizeof(struct __clone_args) * 2, -E2BIG,
171                         CLONE3_ARGS_ALL_0);
172
173         /* Do a clone3() with > page size */
174         test_clone3(0, getpagesize() + 8, -E2BIG, CLONE3_ARGS_NO_TEST);
175
176         /* Do a clone3() with CLONE_ARGS_SIZE_VER0 in a new PID NS. */
177         if (uid == 0)
178                 test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0, 0,
179                                 CLONE3_ARGS_NO_TEST);
180         else
181                 ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
182
183         /* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS */
184         test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL,
185                         CLONE3_ARGS_NO_TEST);
186
187         /* Do a clone3() with sizeof(struct clone_args) + 8 in a new PID NS */
188         if (uid == 0)
189                 test_clone3(CLONE_NEWPID, sizeof(struct __clone_args) + 8, 0,
190                                 CLONE3_ARGS_NO_TEST);
191         else
192                 ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
193
194         /* Do a clone3() with > page size in a new PID NS */
195         test_clone3(CLONE_NEWPID, getpagesize() + 8, -E2BIG,
196                         CLONE3_ARGS_NO_TEST);
197
198         return !ksft_get_fail_cnt() ? ksft_exit_pass() : ksft_exit_fail();
199 }
This page took 0.039635 seconds and 4 git commands to generate.