brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · e61f079 Raw
343 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/* Based on Christian Brauner's clone3() example */4 5#define _GNU_SOURCE6#include <errno.h>7#include <inttypes.h>8#include <linux/types.h>9#include <linux/sched.h>10#include <stdbool.h>11#include <stdint.h>12#include <stdio.h>13#include <stdlib.h>14#include <sys/syscall.h>15#include <sys/types.h>16#include <sys/un.h>17#include <sys/wait.h>18#include <unistd.h>19#include <sched.h>20 21#include "../kselftest.h"22#include "clone3_selftests.h"23 24enum test_mode {25	CLONE3_ARGS_NO_TEST,26	CLONE3_ARGS_ALL_0,27	CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,28	CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,29	CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,30	CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,31};32 33static int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode)34{35	struct __clone_args args = {36		.flags = flags,37		.exit_signal = SIGCHLD,38	};39 40	struct clone_args_extended {41		struct __clone_args args;42		__aligned_u64 excess_space[2];43	} args_ext;44 45	pid_t pid = -1;46	int status;47 48	memset(&args_ext, 0, sizeof(args_ext));49	if (size > sizeof(struct __clone_args))50		args_ext.excess_space[1] = 1;51 52	if (size == 0)53		size = sizeof(struct __clone_args);54 55	switch (test_mode) {56	case CLONE3_ARGS_NO_TEST:57		/*58		 * Uses default 'flags' and 'SIGCHLD'59		 * assignment.60		 */61		break;62	case CLONE3_ARGS_ALL_0:63		args.flags = 0;64		args.exit_signal = 0;65		break;66	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG:67		args.exit_signal = 0xbadc0ded00000000ULL;68		break;69	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG:70		args.exit_signal = 0x0000000080000000ULL;71		break;72	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG:73		args.exit_signal = 0x0000000000000100ULL;74		break;75	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG:76		args.exit_signal = 0x00000000000000f0ULL;77		break;78	}79 80	memcpy(&args_ext.args, &args, sizeof(struct __clone_args));81 82	pid = sys_clone3((struct __clone_args *)&args_ext, size);83	if (pid < 0) {84		ksft_print_msg("%s - Failed to create new process\n",85				strerror(errno));86		return -errno;87	}88 89	if (pid == 0) {90		ksft_print_msg("I am the child, my PID is %d\n", getpid());91		_exit(EXIT_SUCCESS);92	}93 94	ksft_print_msg("I am the parent (%d). My child's pid is %d\n",95			getpid(), pid);96 97	if (waitpid(-1, &status, __WALL) < 0) {98		ksft_print_msg("waitpid() returned %s\n", strerror(errno));99		return -errno;100	}101	if (!WIFEXITED(status)) {102		ksft_print_msg("Child did not exit normally, status 0x%x\n",103			       status);104		return EXIT_FAILURE;105	}106	if (WEXITSTATUS(status))107		return WEXITSTATUS(status);108 109	return 0;110}111 112static bool test_clone3(uint64_t flags, size_t size, int expected,113			enum test_mode test_mode)114{115	int ret;116 117	ksft_print_msg(118		"[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n",119		getpid(), flags, size);120	ret = call_clone3(flags, size, test_mode);121	ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n",122			getpid(), ret, expected);123	if (ret != expected) {124		ksft_print_msg(125			"[%d] Result (%d) is different than expected (%d)\n",126			getpid(), ret, expected);127		return false;128	}129 130	return true;131}132 133typedef bool (*filter_function)(void);134typedef size_t (*size_function)(void);135 136static bool not_root(void)137{138	if (getuid() != 0) {139		ksft_print_msg("Not running as root\n");140		return true;141	}142 143	return false;144}145 146static bool no_timenamespace(void)147{148	if (not_root())149		return true;150 151	if (!access("/proc/self/ns/time", F_OK))152		return false;153 154	ksft_print_msg("Time namespaces are not supported\n");155	return true;156}157 158static size_t page_size_plus_8(void)159{160	return getpagesize() + 8;161}162 163struct test {164	const char *name;165	uint64_t flags;166	size_t size;167	size_function size_function;168	int expected;169	enum test_mode test_mode;170	filter_function filter;171};172 173static const struct test tests[] = {174	{175		.name = "simple clone3()",176		.flags = 0,177		.size = 0,178		.expected = 0,179		.test_mode = CLONE3_ARGS_NO_TEST,180	},181	{182		.name = "clone3() in a new PID_NS",183		.flags = CLONE_NEWPID,184		.size = 0,185		.expected = 0,186		.test_mode = CLONE3_ARGS_NO_TEST,187		.filter = not_root,188	},189	{190		.name = "CLONE_ARGS_SIZE_VER0",191		.flags = 0,192		.size = CLONE_ARGS_SIZE_VER0,193		.expected = 0,194		.test_mode = CLONE3_ARGS_NO_TEST,195	},196	{197		.name = "CLONE_ARGS_SIZE_VER0 - 8",198		.flags = 0,199		.size = CLONE_ARGS_SIZE_VER0 - 8,200		.expected = -EINVAL,201		.test_mode = CLONE3_ARGS_NO_TEST,202	},203	{204		.name = "sizeof(struct clone_args) + 8",205		.flags = 0,206		.size = sizeof(struct __clone_args) + 8,207		.expected = 0,208		.test_mode = CLONE3_ARGS_NO_TEST,209	},210	{211		.name = "exit_signal with highest 32 bits non-zero",212		.flags = 0,213		.size = 0,214		.expected = -EINVAL,215		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,216	},217	{218		.name = "negative 32-bit exit_signal",219		.flags = 0,220		.size = 0,221		.expected = -EINVAL,222		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,223	},224	{225		.name = "exit_signal not fitting into CSIGNAL mask",226		.flags = 0,227		.size = 0,228		.expected = -EINVAL,229		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,230	},231	{232		.name = "NSIG < exit_signal < CSIG",233		.flags = 0,234		.size = 0,235		.expected = -EINVAL,236		.test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,237	},238	{239		.name = "Arguments sizeof(struct clone_args) + 8",240		.flags = 0,241		.size = sizeof(struct __clone_args) + 8,242		.expected = 0,243		.test_mode = CLONE3_ARGS_ALL_0,244	},245	{246		.name = "Arguments sizeof(struct clone_args) + 16",247		.flags = 0,248		.size = sizeof(struct __clone_args) + 16,249		.expected = -E2BIG,250		.test_mode = CLONE3_ARGS_ALL_0,251	},252	{253		.name = "Arguments sizeof(struct clone_arg) * 2",254		.flags = 0,255		.size = sizeof(struct __clone_args) + 16,256		.expected = -E2BIG,257		.test_mode = CLONE3_ARGS_ALL_0,258	},259	{260		.name = "Arguments > page size",261		.flags = 0,262		.size_function = page_size_plus_8,263		.expected = -E2BIG,264		.test_mode = CLONE3_ARGS_NO_TEST,265	},266	{267		.name = "CLONE_ARGS_SIZE_VER0 in a new PID NS",268		.flags = CLONE_NEWPID,269		.size = CLONE_ARGS_SIZE_VER0,270		.expected = 0,271		.test_mode = CLONE3_ARGS_NO_TEST,272		.filter = not_root,273	},274	{275		.name = "CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS",276		.flags = CLONE_NEWPID,277		.size = CLONE_ARGS_SIZE_VER0 - 8,278		.expected = -EINVAL,279		.test_mode = CLONE3_ARGS_NO_TEST,280	},281	{282		.name = "sizeof(struct clone_args) + 8 in a new PID NS",283		.flags = CLONE_NEWPID,284		.size = sizeof(struct __clone_args) + 8,285		.expected = 0,286		.test_mode = CLONE3_ARGS_NO_TEST,287		.filter = not_root,288	},289	{290		.name = "Arguments > page size in a new PID NS",291		.flags = CLONE_NEWPID,292		.size_function = page_size_plus_8,293		.expected = -E2BIG,294		.test_mode = CLONE3_ARGS_NO_TEST,295	},296	{297		.name = "New time NS",298		.flags = CLONE_NEWTIME,299		.size = 0,300		.expected = 0,301		.test_mode = CLONE3_ARGS_NO_TEST,302		.filter = no_timenamespace,303	},304	{305		.name = "exit signal (SIGCHLD) in flags",306		.flags = SIGCHLD,307		.size = 0,308		.expected = -EINVAL,309		.test_mode = CLONE3_ARGS_NO_TEST,310	},311};312 313int main(int argc, char *argv[])314{315	size_t size;316	int i;317 318	ksft_print_header();319	ksft_set_plan(ARRAY_SIZE(tests));320	test_clone3_supported();321 322	for (i = 0; i < ARRAY_SIZE(tests); i++) {323		if (tests[i].filter && tests[i].filter()) {324			ksft_test_result_skip("%s\n", tests[i].name);325			continue;326		}327 328		if (tests[i].size_function)329			size = tests[i].size_function();330		else331			size = tests[i].size;332 333		ksft_print_msg("Running test '%s'\n", tests[i].name);334 335		ksft_test_result(test_clone3(tests[i].flags, size,336					     tests[i].expected,337					     tests[i].test_mode),338				 "%s\n", tests[i].name);339	}340 341	ksft_finished();342}343