xref: /openbmc/linux/tools/testing/selftests/clone3/clone3.c (revision b97d6790d03b763eca08847a9a5869a4291b9f9a)
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