18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci/* Based on Christian Brauner's clone3() example */
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#define _GNU_SOURCE
68c2ecf20Sopenharmony_ci#include <errno.h>
78c2ecf20Sopenharmony_ci#include <inttypes.h>
88c2ecf20Sopenharmony_ci#include <linux/types.h>
98c2ecf20Sopenharmony_ci#include <linux/sched.h>
108c2ecf20Sopenharmony_ci#include <stdint.h>
118c2ecf20Sopenharmony_ci#include <stdio.h>
128c2ecf20Sopenharmony_ci#include <stdlib.h>
138c2ecf20Sopenharmony_ci#include <sys/syscall.h>
148c2ecf20Sopenharmony_ci#include <sys/types.h>
158c2ecf20Sopenharmony_ci#include <sys/un.h>
168c2ecf20Sopenharmony_ci#include <sys/wait.h>
178c2ecf20Sopenharmony_ci#include <unistd.h>
188c2ecf20Sopenharmony_ci#include <sched.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "../kselftest.h"
218c2ecf20Sopenharmony_ci#include "clone3_selftests.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cienum test_mode {
248c2ecf20Sopenharmony_ci	CLONE3_ARGS_NO_TEST,
258c2ecf20Sopenharmony_ci	CLONE3_ARGS_ALL_0,
268c2ecf20Sopenharmony_ci	CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
278c2ecf20Sopenharmony_ci	CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
288c2ecf20Sopenharmony_ci	CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
298c2ecf20Sopenharmony_ci	CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct __clone_args args = {
358c2ecf20Sopenharmony_ci		.flags = flags,
368c2ecf20Sopenharmony_ci		.exit_signal = SIGCHLD,
378c2ecf20Sopenharmony_ci	};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	struct clone_args_extended {
408c2ecf20Sopenharmony_ci		struct __clone_args args;
418c2ecf20Sopenharmony_ci		__aligned_u64 excess_space[2];
428c2ecf20Sopenharmony_ci	} args_ext;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	pid_t pid = -1;
458c2ecf20Sopenharmony_ci	int status;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	memset(&args_ext, 0, sizeof(args_ext));
488c2ecf20Sopenharmony_ci	if (size > sizeof(struct __clone_args))
498c2ecf20Sopenharmony_ci		args_ext.excess_space[1] = 1;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	if (size == 0)
528c2ecf20Sopenharmony_ci		size = sizeof(struct __clone_args);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	switch (test_mode) {
558c2ecf20Sopenharmony_ci	case CLONE3_ARGS_NO_TEST:
568c2ecf20Sopenharmony_ci		/*
578c2ecf20Sopenharmony_ci		 * Uses default 'flags' and 'SIGCHLD'
588c2ecf20Sopenharmony_ci		 * assignment.
598c2ecf20Sopenharmony_ci		 */
608c2ecf20Sopenharmony_ci		break;
618c2ecf20Sopenharmony_ci	case CLONE3_ARGS_ALL_0:
628c2ecf20Sopenharmony_ci		args.flags = 0;
638c2ecf20Sopenharmony_ci		args.exit_signal = 0;
648c2ecf20Sopenharmony_ci		break;
658c2ecf20Sopenharmony_ci	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG:
668c2ecf20Sopenharmony_ci		args.exit_signal = 0xbadc0ded00000000ULL;
678c2ecf20Sopenharmony_ci		break;
688c2ecf20Sopenharmony_ci	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG:
698c2ecf20Sopenharmony_ci		args.exit_signal = 0x0000000080000000ULL;
708c2ecf20Sopenharmony_ci		break;
718c2ecf20Sopenharmony_ci	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG:
728c2ecf20Sopenharmony_ci		args.exit_signal = 0x0000000000000100ULL;
738c2ecf20Sopenharmony_ci		break;
748c2ecf20Sopenharmony_ci	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG:
758c2ecf20Sopenharmony_ci		args.exit_signal = 0x00000000000000f0ULL;
768c2ecf20Sopenharmony_ci		break;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	memcpy(&args_ext.args, &args, sizeof(struct __clone_args));
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	pid = sys_clone3((struct __clone_args *)&args_ext, size);
828c2ecf20Sopenharmony_ci	if (pid < 0) {
838c2ecf20Sopenharmony_ci		ksft_print_msg("%s - Failed to create new process\n",
848c2ecf20Sopenharmony_ci				strerror(errno));
858c2ecf20Sopenharmony_ci		return -errno;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (pid == 0) {
898c2ecf20Sopenharmony_ci		ksft_print_msg("I am the child, my PID is %d\n", getpid());
908c2ecf20Sopenharmony_ci		_exit(EXIT_SUCCESS);
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	ksft_print_msg("I am the parent (%d). My child's pid is %d\n",
948c2ecf20Sopenharmony_ci			getpid(), pid);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (waitpid(-1, &status, __WALL) < 0) {
978c2ecf20Sopenharmony_ci		ksft_print_msg("Child returned %s\n", strerror(errno));
988c2ecf20Sopenharmony_ci		return -errno;
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci	if (WEXITSTATUS(status))
1018c2ecf20Sopenharmony_ci		return WEXITSTATUS(status);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic void test_clone3(uint64_t flags, size_t size, int expected,
1078c2ecf20Sopenharmony_ci		       enum test_mode test_mode)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	int ret;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	ksft_print_msg(
1128c2ecf20Sopenharmony_ci		"[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n",
1138c2ecf20Sopenharmony_ci		getpid(), flags, size);
1148c2ecf20Sopenharmony_ci	ret = call_clone3(flags, size, test_mode);
1158c2ecf20Sopenharmony_ci	ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n",
1168c2ecf20Sopenharmony_ci			getpid(), ret, expected);
1178c2ecf20Sopenharmony_ci	if (ret != expected)
1188c2ecf20Sopenharmony_ci		ksft_test_result_fail(
1198c2ecf20Sopenharmony_ci			"[%d] Result (%d) is different than expected (%d)\n",
1208c2ecf20Sopenharmony_ci			getpid(), ret, expected);
1218c2ecf20Sopenharmony_ci	else
1228c2ecf20Sopenharmony_ci		ksft_test_result_pass(
1238c2ecf20Sopenharmony_ci			"[%d] Result (%d) matches expectation (%d)\n",
1248c2ecf20Sopenharmony_ci			getpid(), ret, expected);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ciint main(int argc, char *argv[])
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	uid_t uid = getuid();
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	ksft_print_header();
1328c2ecf20Sopenharmony_ci	ksft_set_plan(17);
1338c2ecf20Sopenharmony_ci	test_clone3_supported();
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* Just a simple clone3() should return 0.*/
1368c2ecf20Sopenharmony_ci	test_clone3(0, 0, 0, CLONE3_ARGS_NO_TEST);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* Do a clone3() in a new PID NS.*/
1398c2ecf20Sopenharmony_ci	if (uid == 0)
1408c2ecf20Sopenharmony_ci		test_clone3(CLONE_NEWPID, 0, 0, CLONE3_ARGS_NO_TEST);
1418c2ecf20Sopenharmony_ci	else
1428c2ecf20Sopenharmony_ci		ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* Do a clone3() with CLONE_ARGS_SIZE_VER0. */
1458c2ecf20Sopenharmony_ci	test_clone3(0, CLONE_ARGS_SIZE_VER0, 0, CLONE3_ARGS_NO_TEST);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 */
1488c2ecf20Sopenharmony_ci	test_clone3(0, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL, CLONE3_ARGS_NO_TEST);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* Do a clone3() with sizeof(struct clone_args) + 8 */
1518c2ecf20Sopenharmony_ci	test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_NO_TEST);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	/* Do a clone3() with exit_signal having highest 32 bits non-zero */
1548c2ecf20Sopenharmony_ci	test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	/* Do a clone3() with negative 32-bit exit_signal */
1578c2ecf20Sopenharmony_ci	test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* Do a clone3() with exit_signal not fitting into CSIGNAL mask */
1608c2ecf20Sopenharmony_ci	test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* Do a clone3() with NSIG < exit_signal < CSIG */
1638c2ecf20Sopenharmony_ci	test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_ALL_0);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	test_clone3(0, sizeof(struct __clone_args) + 16, -E2BIG,
1688c2ecf20Sopenharmony_ci			CLONE3_ARGS_ALL_0);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	test_clone3(0, sizeof(struct __clone_args) * 2, -E2BIG,
1718c2ecf20Sopenharmony_ci			CLONE3_ARGS_ALL_0);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* Do a clone3() with > page size */
1748c2ecf20Sopenharmony_ci	test_clone3(0, getpagesize() + 8, -E2BIG, CLONE3_ARGS_NO_TEST);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	/* Do a clone3() with CLONE_ARGS_SIZE_VER0 in a new PID NS. */
1778c2ecf20Sopenharmony_ci	if (uid == 0)
1788c2ecf20Sopenharmony_ci		test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0, 0,
1798c2ecf20Sopenharmony_ci				CLONE3_ARGS_NO_TEST);
1808c2ecf20Sopenharmony_ci	else
1818c2ecf20Sopenharmony_ci		ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS */
1848c2ecf20Sopenharmony_ci	test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL,
1858c2ecf20Sopenharmony_ci			CLONE3_ARGS_NO_TEST);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/* Do a clone3() with sizeof(struct clone_args) + 8 in a new PID NS */
1888c2ecf20Sopenharmony_ci	if (uid == 0)
1898c2ecf20Sopenharmony_ci		test_clone3(CLONE_NEWPID, sizeof(struct __clone_args) + 8, 0,
1908c2ecf20Sopenharmony_ci				CLONE3_ARGS_NO_TEST);
1918c2ecf20Sopenharmony_ci	else
1928c2ecf20Sopenharmony_ci		ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/* Do a clone3() with > page size in a new PID NS */
1958c2ecf20Sopenharmony_ci	test_clone3(CLONE_NEWPID, getpagesize() + 8, -E2BIG,
1968c2ecf20Sopenharmony_ci			CLONE3_ARGS_NO_TEST);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	return !ksft_get_fail_cnt() ? ksft_exit_pass() : ksft_exit_fail();
1998c2ecf20Sopenharmony_ci}
200