117a81069SAdrian Reber // SPDX-License-Identifier: GPL-2.0
217a81069SAdrian Reber
317a81069SAdrian Reber /* Based on Christian Brauner's clone3() example */
417a81069SAdrian Reber
517a81069SAdrian Reber #define _GNU_SOURCE
617a81069SAdrian Reber #include <errno.h>
717a81069SAdrian Reber #include <inttypes.h>
817a81069SAdrian Reber #include <linux/types.h>
917a81069SAdrian Reber #include <linux/sched.h>
1017a81069SAdrian Reber #include <stdint.h>
1117a81069SAdrian Reber #include <stdio.h>
1217a81069SAdrian Reber #include <stdlib.h>
1317a81069SAdrian Reber #include <sys/syscall.h>
1417a81069SAdrian Reber #include <sys/types.h>
1517a81069SAdrian Reber #include <sys/un.h>
1617a81069SAdrian Reber #include <sys/wait.h>
1717a81069SAdrian Reber #include <unistd.h>
1817a81069SAdrian Reber #include <sched.h>
1917a81069SAdrian Reber
2017a81069SAdrian Reber #include "../kselftest.h"
2141585bbeSAdrian Reber #include "clone3_selftests.h"
2217a81069SAdrian Reber
2317a81069SAdrian Reber enum test_mode {
2417a81069SAdrian Reber CLONE3_ARGS_NO_TEST,
2517a81069SAdrian Reber CLONE3_ARGS_ALL_0,
2617a81069SAdrian Reber CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
2717a81069SAdrian Reber CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
2817a81069SAdrian Reber CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
2917a81069SAdrian Reber CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
3017a81069SAdrian Reber };
3117a81069SAdrian Reber
call_clone3(uint64_t flags,size_t size,enum test_mode test_mode)3217a81069SAdrian Reber static int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode)
3317a81069SAdrian Reber {
34e953aeaaSKees Cook struct __clone_args args = {
3517a81069SAdrian Reber .flags = flags,
3617a81069SAdrian Reber .exit_signal = SIGCHLD,
3717a81069SAdrian Reber };
3817a81069SAdrian Reber
3917a81069SAdrian Reber struct clone_args_extended {
40e953aeaaSKees Cook struct __clone_args args;
4117a81069SAdrian Reber __aligned_u64 excess_space[2];
4217a81069SAdrian Reber } args_ext;
4317a81069SAdrian Reber
4417a81069SAdrian Reber pid_t pid = -1;
4517a81069SAdrian Reber int status;
4617a81069SAdrian Reber
4717a81069SAdrian Reber memset(&args_ext, 0, sizeof(args_ext));
48e953aeaaSKees Cook if (size > sizeof(struct __clone_args))
4917a81069SAdrian Reber args_ext.excess_space[1] = 1;
5017a81069SAdrian Reber
5117a81069SAdrian Reber if (size == 0)
52e953aeaaSKees Cook size = sizeof(struct __clone_args);
5317a81069SAdrian Reber
5417a81069SAdrian Reber switch (test_mode) {
55a531b0c2SAnders Roxell case CLONE3_ARGS_NO_TEST:
56a531b0c2SAnders Roxell /*
57a531b0c2SAnders Roxell * Uses default 'flags' and 'SIGCHLD'
58a531b0c2SAnders Roxell * assignment.
59a531b0c2SAnders Roxell */
60a531b0c2SAnders Roxell break;
6117a81069SAdrian Reber case CLONE3_ARGS_ALL_0:
6217a81069SAdrian Reber args.flags = 0;
6317a81069SAdrian Reber args.exit_signal = 0;
6417a81069SAdrian Reber break;
6517a81069SAdrian Reber case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG:
6617a81069SAdrian Reber args.exit_signal = 0xbadc0ded00000000ULL;
6717a81069SAdrian Reber break;
6817a81069SAdrian Reber case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG:
6917a81069SAdrian Reber args.exit_signal = 0x0000000080000000ULL;
7017a81069SAdrian Reber break;
7117a81069SAdrian Reber case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG:
7217a81069SAdrian Reber args.exit_signal = 0x0000000000000100ULL;
7317a81069SAdrian Reber break;
7417a81069SAdrian Reber case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG:
7517a81069SAdrian Reber args.exit_signal = 0x00000000000000f0ULL;
7617a81069SAdrian Reber break;
7717a81069SAdrian Reber }
7817a81069SAdrian Reber
79e953aeaaSKees Cook memcpy(&args_ext.args, &args, sizeof(struct __clone_args));
8017a81069SAdrian Reber
81e953aeaaSKees Cook pid = sys_clone3((struct __clone_args *)&args_ext, size);
8217a81069SAdrian Reber if (pid < 0) {
8317a81069SAdrian Reber ksft_print_msg("%s - Failed to create new process\n",
8417a81069SAdrian Reber strerror(errno));
8517a81069SAdrian Reber return -errno;
8617a81069SAdrian Reber }
8717a81069SAdrian Reber
8817a81069SAdrian Reber if (pid == 0) {
8917a81069SAdrian Reber ksft_print_msg("I am the child, my PID is %d\n", getpid());
9017a81069SAdrian Reber _exit(EXIT_SUCCESS);
9117a81069SAdrian Reber }
9217a81069SAdrian Reber
9317a81069SAdrian Reber ksft_print_msg("I am the parent (%d). My child's pid is %d\n",
9417a81069SAdrian Reber getpid(), pid);
9517a81069SAdrian Reber
9617a81069SAdrian Reber if (waitpid(-1, &status, __WALL) < 0) {
9717a81069SAdrian Reber ksft_print_msg("Child returned %s\n", strerror(errno));
9817a81069SAdrian Reber return -errno;
9917a81069SAdrian Reber }
10017a81069SAdrian Reber if (WEXITSTATUS(status))
10117a81069SAdrian Reber return WEXITSTATUS(status);
10217a81069SAdrian Reber
10317a81069SAdrian Reber return 0;
10417a81069SAdrian Reber }
10517a81069SAdrian Reber
test_clone3(uint64_t flags,size_t size,int expected,enum test_mode test_mode)10617a81069SAdrian Reber static void test_clone3(uint64_t flags, size_t size, int expected,
10717a81069SAdrian Reber enum test_mode test_mode)
10817a81069SAdrian Reber {
10917a81069SAdrian Reber int ret;
11017a81069SAdrian Reber
11117a81069SAdrian Reber ksft_print_msg(
11217a81069SAdrian Reber "[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n",
11317a81069SAdrian Reber getpid(), flags, size);
11417a81069SAdrian Reber ret = call_clone3(flags, size, test_mode);
11517a81069SAdrian Reber ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n",
11617a81069SAdrian Reber getpid(), ret, expected);
11717a81069SAdrian Reber if (ret != expected)
11817a81069SAdrian Reber ksft_test_result_fail(
11917a81069SAdrian Reber "[%d] Result (%d) is different than expected (%d)\n",
12017a81069SAdrian Reber getpid(), ret, expected);
12117a81069SAdrian Reber else
12217a81069SAdrian Reber ksft_test_result_pass(
12317a81069SAdrian Reber "[%d] Result (%d) matches expectation (%d)\n",
12417a81069SAdrian Reber getpid(), ret, expected);
12517a81069SAdrian Reber }
12617a81069SAdrian Reber
main(int argc,char * argv[])12717a81069SAdrian Reber int main(int argc, char *argv[])
12817a81069SAdrian Reber {
12917a81069SAdrian Reber uid_t uid = getuid();
13017a81069SAdrian Reber
13117a81069SAdrian Reber ksft_print_header();
132c4f461a1STobias Klauser ksft_set_plan(19);
13351ad5b54SKees Cook test_clone3_supported();
13417a81069SAdrian Reber
13517a81069SAdrian Reber /* Just a simple clone3() should return 0.*/
13617a81069SAdrian Reber test_clone3(0, 0, 0, CLONE3_ARGS_NO_TEST);
13717a81069SAdrian Reber
13817a81069SAdrian Reber /* Do a clone3() in a new PID NS.*/
13917a81069SAdrian Reber if (uid == 0)
14017a81069SAdrian Reber test_clone3(CLONE_NEWPID, 0, 0, CLONE3_ARGS_NO_TEST);
14117a81069SAdrian Reber else
14217a81069SAdrian Reber ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
14317a81069SAdrian Reber
144e953aeaaSKees Cook /* Do a clone3() with CLONE_ARGS_SIZE_VER0. */
145e953aeaaSKees Cook test_clone3(0, CLONE_ARGS_SIZE_VER0, 0, CLONE3_ARGS_NO_TEST);
14617a81069SAdrian Reber
147e953aeaaSKees Cook /* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 */
148e953aeaaSKees Cook test_clone3(0, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL, CLONE3_ARGS_NO_TEST);
14917a81069SAdrian Reber
15017a81069SAdrian Reber /* Do a clone3() with sizeof(struct clone_args) + 8 */
151e953aeaaSKees Cook test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_NO_TEST);
15217a81069SAdrian Reber
15317a81069SAdrian Reber /* Do a clone3() with exit_signal having highest 32 bits non-zero */
15417a81069SAdrian Reber test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG);
15517a81069SAdrian Reber
15617a81069SAdrian Reber /* Do a clone3() with negative 32-bit exit_signal */
15717a81069SAdrian Reber test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG);
15817a81069SAdrian Reber
15917a81069SAdrian Reber /* Do a clone3() with exit_signal not fitting into CSIGNAL mask */
16017a81069SAdrian Reber test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG);
16117a81069SAdrian Reber
16217a81069SAdrian Reber /* Do a clone3() with NSIG < exit_signal < CSIG */
16317a81069SAdrian Reber test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG);
16417a81069SAdrian Reber
165e953aeaaSKees Cook test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_ALL_0);
16617a81069SAdrian Reber
167e953aeaaSKees Cook test_clone3(0, sizeof(struct __clone_args) + 16, -E2BIG,
16817a81069SAdrian Reber CLONE3_ARGS_ALL_0);
16917a81069SAdrian Reber
170e953aeaaSKees Cook test_clone3(0, sizeof(struct __clone_args) * 2, -E2BIG,
17117a81069SAdrian Reber CLONE3_ARGS_ALL_0);
17217a81069SAdrian Reber
17317a81069SAdrian Reber /* Do a clone3() with > page size */
17417a81069SAdrian Reber test_clone3(0, getpagesize() + 8, -E2BIG, CLONE3_ARGS_NO_TEST);
17517a81069SAdrian Reber
176e953aeaaSKees Cook /* Do a clone3() with CLONE_ARGS_SIZE_VER0 in a new PID NS. */
17717a81069SAdrian Reber if (uid == 0)
178e953aeaaSKees Cook test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0, 0,
17917a81069SAdrian Reber CLONE3_ARGS_NO_TEST);
18017a81069SAdrian Reber else
18117a81069SAdrian Reber ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
18217a81069SAdrian Reber
183e953aeaaSKees Cook /* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS */
184e953aeaaSKees Cook test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL,
18517a81069SAdrian Reber CLONE3_ARGS_NO_TEST);
18617a81069SAdrian Reber
18717a81069SAdrian Reber /* Do a clone3() with sizeof(struct clone_args) + 8 in a new PID NS */
18817a81069SAdrian Reber if (uid == 0)
189e953aeaaSKees Cook test_clone3(CLONE_NEWPID, sizeof(struct __clone_args) + 8, 0,
19017a81069SAdrian Reber CLONE3_ARGS_NO_TEST);
19117a81069SAdrian Reber else
19217a81069SAdrian Reber ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
19317a81069SAdrian Reber
19417a81069SAdrian Reber /* Do a clone3() with > page size in a new PID NS */
19517a81069SAdrian Reber test_clone3(CLONE_NEWPID, getpagesize() + 8, -E2BIG,
19617a81069SAdrian Reber CLONE3_ARGS_NO_TEST);
19717a81069SAdrian Reber
198515bddf0STobias Klauser /* Do a clone3() in a new time namespace */
199*4c004ed9STiezhu Yang if (access("/proc/self/ns/time", F_OK) == 0) {
200515bddf0STobias Klauser test_clone3(CLONE_NEWTIME, 0, 0, CLONE3_ARGS_NO_TEST);
201*4c004ed9STiezhu Yang } else {
202*4c004ed9STiezhu Yang ksft_print_msg("Time namespaces are not supported\n");
203*4c004ed9STiezhu Yang ksft_test_result_skip("Skipping clone3() with CLONE_NEWTIME\n");
204*4c004ed9STiezhu Yang }
205515bddf0STobias Klauser
206c4f461a1STobias Klauser /* Do a clone3() with exit signal (SIGCHLD) in flags */
207c4f461a1STobias Klauser test_clone3(SIGCHLD, 0, -EINVAL, CLONE3_ARGS_NO_TEST);
208c4f461a1STobias Klauser
209d95debbdSTobias Klauser ksft_finished();
21017a81069SAdrian Reber }
211