cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clone3.c (5382B)


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