Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.10.11.
  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
 23enum 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
 32static 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_ALL_0:
 56		args.flags = 0;
 57		args.exit_signal = 0;
 58		break;
 59	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG:
 60		args.exit_signal = 0xbadc0ded00000000ULL;
 61		break;
 62	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG:
 63		args.exit_signal = 0x0000000080000000ULL;
 64		break;
 65	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG:
 66		args.exit_signal = 0x0000000000000100ULL;
 67		break;
 68	case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG:
 69		args.exit_signal = 0x00000000000000f0ULL;
 70		break;
 71	}
 72
 73	memcpy(&args_ext.args, &args, sizeof(struct __clone_args));
 74
 75	pid = sys_clone3((struct __clone_args *)&args_ext, size);
 76	if (pid < 0) {
 77		ksft_print_msg("%s - Failed to create new process\n",
 78				strerror(errno));
 79		return -errno;
 80	}
 81
 82	if (pid == 0) {
 83		ksft_print_msg("I am the child, my PID is %d\n", getpid());
 84		_exit(EXIT_SUCCESS);
 85	}
 86
 87	ksft_print_msg("I am the parent (%d). My child's pid is %d\n",
 88			getpid(), pid);
 89
 90	if (waitpid(-1, &status, __WALL) < 0) {
 91		ksft_print_msg("Child returned %s\n", strerror(errno));
 92		return -errno;
 93	}
 94	if (WEXITSTATUS(status))
 95		return WEXITSTATUS(status);
 96
 97	return 0;
 98}
 99
100static void test_clone3(uint64_t flags, size_t size, int expected,
101		       enum test_mode test_mode)
102{
103	int ret;
104
105	ksft_print_msg(
106		"[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n",
107		getpid(), flags, size);
108	ret = call_clone3(flags, size, test_mode);
109	ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n",
110			getpid(), ret, expected);
111	if (ret != expected)
112		ksft_test_result_fail(
113			"[%d] Result (%d) is different than expected (%d)\n",
114			getpid(), ret, expected);
115	else
116		ksft_test_result_pass(
117			"[%d] Result (%d) matches expectation (%d)\n",
118			getpid(), ret, expected);
119}
120
121int main(int argc, char *argv[])
122{
123	pid_t pid;
124
125	uid_t uid = getuid();
126
127	ksft_print_header();
128	ksft_set_plan(17);
129	test_clone3_supported();
130
131	/* Just a simple clone3() should return 0.*/
132	test_clone3(0, 0, 0, CLONE3_ARGS_NO_TEST);
133
134	/* Do a clone3() in a new PID NS.*/
135	if (uid == 0)
136		test_clone3(CLONE_NEWPID, 0, 0, CLONE3_ARGS_NO_TEST);
137	else
138		ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
139
140	/* Do a clone3() with CLONE_ARGS_SIZE_VER0. */
141	test_clone3(0, CLONE_ARGS_SIZE_VER0, 0, CLONE3_ARGS_NO_TEST);
142
143	/* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 */
144	test_clone3(0, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL, CLONE3_ARGS_NO_TEST);
145
146	/* Do a clone3() with sizeof(struct clone_args) + 8 */
147	test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_NO_TEST);
148
149	/* Do a clone3() with exit_signal having highest 32 bits non-zero */
150	test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG);
151
152	/* Do a clone3() with negative 32-bit exit_signal */
153	test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG);
154
155	/* Do a clone3() with exit_signal not fitting into CSIGNAL mask */
156	test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG);
157
158	/* Do a clone3() with NSIG < exit_signal < CSIG */
159	test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG);
160
161	test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_ALL_0);
162
163	test_clone3(0, sizeof(struct __clone_args) + 16, -E2BIG,
164			CLONE3_ARGS_ALL_0);
165
166	test_clone3(0, sizeof(struct __clone_args) * 2, -E2BIG,
167			CLONE3_ARGS_ALL_0);
168
169	/* Do a clone3() with > page size */
170	test_clone3(0, getpagesize() + 8, -E2BIG, CLONE3_ARGS_NO_TEST);
171
172	/* Do a clone3() with CLONE_ARGS_SIZE_VER0 in a new PID NS. */
173	if (uid == 0)
174		test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0, 0,
175				CLONE3_ARGS_NO_TEST);
176	else
177		ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
178
179	/* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS */
180	test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL,
181			CLONE3_ARGS_NO_TEST);
182
183	/* Do a clone3() with sizeof(struct clone_args) + 8 in a new PID NS */
184	if (uid == 0)
185		test_clone3(CLONE_NEWPID, sizeof(struct __clone_args) + 8, 0,
186				CLONE3_ARGS_NO_TEST);
187	else
188		ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
189
190	/* Do a clone3() with > page size in a new PID NS */
191	test_clone3(CLONE_NEWPID, getpagesize() + 8, -E2BIG,
192			CLONE3_ARGS_NO_TEST);
193
194	return !ksft_get_fail_cnt() ? ksft_exit_pass() : ksft_exit_fail();
195}