1139749Simp// SPDX-License-Identifier: GPL-2.0 2113584Ssimokawa 3103285Sikob/* Based on Christian Brauner's clone3() example */ 4103285Sikob 5103285Sikob#define _GNU_SOURCE 6103285Sikob#include <errno.h> 7103285Sikob#include <inttypes.h> 8103285Sikob#include <linux/types.h> 9103285Sikob#include <linux/sched.h> 10103285Sikob#include <stdbool.h> 11103285Sikob#include <stdint.h> 12103285Sikob#include <stdio.h> 13103285Sikob#include <stdlib.h> 14103285Sikob#include <sys/syscall.h> 15103285Sikob#include <sys/types.h> 16103285Sikob#include <sys/un.h> 17103285Sikob#include <sys/wait.h> 18103285Sikob#include <unistd.h> 19103285Sikob#include <sched.h> 20103285Sikob 21103285Sikob#include "../kselftest.h" 22103285Sikob#include "clone3_selftests.h" 23103285Sikob 24103285Sikobenum test_mode { 25103285Sikob CLONE3_ARGS_NO_TEST, 26103285Sikob CLONE3_ARGS_ALL_0, 27103285Sikob CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG, 28103285Sikob CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG, 29103285Sikob CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG, 30103285Sikob CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG, 31103285Sikob}; 32103285Sikob 33103285Sikobstatic int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode) 34103285Sikob{ 35103285Sikob struct __clone_args args = { 36103285Sikob .flags = flags, 37103285Sikob .exit_signal = SIGCHLD, 38127468Ssimokawa }; 39127468Ssimokawa 40127468Ssimokawa struct clone_args_extended { 41127468Ssimokawa struct __clone_args args; 42103285Sikob __aligned_u64 excess_space[2]; 43103285Sikob } args_ext; 44103285Sikob 45103285Sikob pid_t pid = -1; 46103285Sikob int status; 47103285Sikob 48103285Sikob memset(&args_ext, 0, sizeof(args_ext)); 49113584Ssimokawa if (size > sizeof(struct __clone_args)) 50170374Ssimokawa args_ext.excess_space[1] = 1; 51170374Ssimokawa 52113584Ssimokawa if (size == 0) 53103285Sikob size = sizeof(struct __clone_args); 54103285Sikob 55169130Ssimokawa switch (test_mode) { 56169130Ssimokawa case CLONE3_ARGS_NO_TEST: 57103285Sikob /* 58129585Sdfr * Uses default 'flags' and 'SIGCHLD' 59103285Sikob * assignment. 60129585Sdfr */ 61129585Sdfr break; 62129585Sdfr case CLONE3_ARGS_ALL_0: 63129585Sdfr args.flags = 0; 64103285Sikob args.exit_signal = 0; 65103285Sikob break; 66103285Sikob case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG: 67129585Sdfr args.exit_signal = 0xbadc0ded00000000ULL; 68103285Sikob break; 69106810Ssimokawa case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG: 70129585Sdfr args.exit_signal = 0x0000000080000000ULL; 71103285Sikob break; 72103285Sikob case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG: 73103285Sikob args.exit_signal = 0x0000000000000100ULL; 74110193Ssimokawa break; 75103285Sikob case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG: 76109645Ssimokawa args.exit_signal = 0x00000000000000f0ULL; 77103285Sikob break; 78127468Ssimokawa } 79130585Sphk 80103285Sikob memcpy(&args_ext.args, &args, sizeof(struct __clone_args)); 81103285Sikob 82103285Sikob pid = sys_clone3((struct __clone_args *)&args_ext, size); 83109645Ssimokawa if (pid < 0) { 84103285Sikob ksft_print_msg("%s - Failed to create new process\n", 85103285Sikob strerror(errno)); 86103285Sikob return -errno; 87109645Ssimokawa } 88103285Sikob 89103285Sikob if (pid == 0) { 90103285Sikob ksft_print_msg("I am the child, my PID is %d\n", getpid()); 91124169Ssimokawa _exit(EXIT_SUCCESS); 92124169Ssimokawa } 93103285Sikob 94103285Sikob ksft_print_msg("I am the parent (%d). My child's pid is %d\n", 95103285Sikob getpid(), pid); 96103285Sikob 97103285Sikob if (waitpid(-1, &status, __WALL) < 0) { 98103285Sikob ksft_print_msg("Child returned %s\n", strerror(errno)); 99103285Sikob return -errno; 100103285Sikob } 101103285Sikob if (WEXITSTATUS(status)) 102103285Sikob return WEXITSTATUS(status); 103170374Ssimokawa 104103285Sikob return 0; 105103285Sikob} 106103285Sikob 107103285Sikobstatic bool test_clone3(uint64_t flags, size_t size, int expected, 108103285Sikob enum test_mode test_mode) 109129585Sdfr{ 110103285Sikob int ret; 111103285Sikob 112103285Sikob ksft_print_msg( 113103285Sikob "[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n", 114103285Sikob getpid(), flags, size); 115103285Sikob ret = call_clone3(flags, size, test_mode); 116103285Sikob ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n", 117103285Sikob getpid(), ret, expected); 118103285Sikob if (ret != expected) { 119129585Sdfr ksft_print_msg( 120169806Ssimokawa "[%d] Result (%d) is different than expected (%d)\n", 121116978Ssimokawa getpid(), ret, expected); 122103285Sikob return false; 123103285Sikob } 124103285Sikob 125103285Sikob return true; 126103285Sikob} 127103285Sikob 128103285Sikobtypedef bool (*filter_function)(void); 129103285Sikobtypedef size_t (*size_function)(void); 130103285Sikob 131103285Sikobstatic bool not_root(void) 132109814Ssimokawa{ 133103285Sikob if (getuid() != 0) { 134103285Sikob ksft_print_msg("Not running as root\n"); 135169130Ssimokawa return true; 136171457Ssimokawa } 137171513Ssimokawa 138103285Sikob return false; 139110193Ssimokawa} 140103285Sikob 141103285Sikobstatic bool no_timenamespace(void) 142129585Sdfr{ 143103285Sikob if (not_root()) 144129585Sdfr return true; 145116376Ssimokawa 146116376Ssimokawa if (!access("/proc/self/ns/time", F_OK)) 147116376Ssimokawa return false; 148103285Sikob 149103285Sikob ksft_print_msg("Time namespaces are not supported\n"); 150108853Ssimokawa return true; 151110193Ssimokawa} 152110193Ssimokawa 153170374Ssimokawastatic size_t page_size_plus_8(void) 154129585Sdfr{ 155124169Ssimokawa return getpagesize() + 8; 156129585Sdfr} 157130585Sphk 158124169Ssimokawastruct test { 159124169Ssimokawa const char *name; 160124169Ssimokawa uint64_t flags; 161124169Ssimokawa size_t size; 162124169Ssimokawa size_function size_function; 163124169Ssimokawa int expected; 164124169Ssimokawa enum test_mode test_mode; 165129585Sdfr filter_function filter; 166129585Sdfr}; 167103285Sikob 168113584Ssimokawastatic const struct test tests[] = { 169170374Ssimokawa { 170170374Ssimokawa .name = "simple clone3()", 171170374Ssimokawa .flags = 0, 172170374Ssimokawa .size = 0, 173103285Sikob .expected = 0, 174103285Sikob .test_mode = CLONE3_ARGS_NO_TEST, 175103285Sikob }, 176170374Ssimokawa { 177170374Ssimokawa .name = "clone3() in a new PID_NS", 178170374Ssimokawa .flags = CLONE_NEWPID, 179170374Ssimokawa .size = 0, 180170374Ssimokawa .expected = 0, 181109645Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 182109645Ssimokawa .filter = not_root, 183109645Ssimokawa }, 184109645Ssimokawa { 185109645Ssimokawa .name = "CLONE_ARGS_SIZE_VER0", 186109645Ssimokawa .flags = 0, 187109645Ssimokawa .size = CLONE_ARGS_SIZE_VER0, 188109645Ssimokawa .expected = 0, 189109645Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 190109645Ssimokawa }, 191109645Ssimokawa { 192109645Ssimokawa .name = "CLONE_ARGS_SIZE_VER0 - 8", 193109645Ssimokawa .flags = 0, 194109645Ssimokawa .size = CLONE_ARGS_SIZE_VER0 - 8, 195124169Ssimokawa .expected = -EINVAL, 196118293Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 197169130Ssimokawa }, 198109645Ssimokawa { 199109645Ssimokawa .name = "sizeof(struct clone_args) + 8", 200109645Ssimokawa .flags = 0, 201113584Ssimokawa .size = sizeof(struct __clone_args) + 8, 202109645Ssimokawa .expected = 0, 203109645Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 204109645Ssimokawa }, 205109645Ssimokawa { 206109645Ssimokawa .name = "exit_signal with highest 32 bits non-zero", 207109890Ssimokawa .flags = 0, 208109645Ssimokawa .size = 0, 209109645Ssimokawa .expected = -EINVAL, 210109645Ssimokawa .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG, 211124169Ssimokawa }, 212109645Ssimokawa { 213109645Ssimokawa .name = "negative 32-bit exit_signal", 214109645Ssimokawa .flags = 0, 215113584Ssimokawa .size = 0, 216111942Ssimokawa .expected = -EINVAL, 217109645Ssimokawa .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG, 218109645Ssimokawa }, 219109645Ssimokawa { 220111942Ssimokawa .name = "exit_signal not fitting into CSIGNAL mask", 221109645Ssimokawa .flags = 0, 222109645Ssimokawa .size = 0, 223109645Ssimokawa .expected = -EINVAL, 224120660Ssimokawa .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG, 225120660Ssimokawa }, 226169130Ssimokawa { 227109645Ssimokawa .name = "NSIG < exit_signal < CSIG", 228109645Ssimokawa .flags = 0, 229169130Ssimokawa .size = 0, 230109645Ssimokawa .expected = -EINVAL, 231109645Ssimokawa .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG, 232103285Sikob }, 233103285Sikob { 234103285Sikob .name = "Arguments sizeof(struct clone_args) + 8", 235103285Sikob .flags = 0, 236110577Ssimokawa .size = sizeof(struct __clone_args) + 8, 237113584Ssimokawa .expected = 0, 238170374Ssimokawa .test_mode = CLONE3_ARGS_ALL_0, 239170374Ssimokawa }, 240170374Ssimokawa { 241170374Ssimokawa .name = "Arguments sizeof(struct clone_args) + 16", 242170374Ssimokawa .flags = 0, 243170374Ssimokawa .size = sizeof(struct __clone_args) + 16, 244170374Ssimokawa .expected = -E2BIG, 245170374Ssimokawa .test_mode = CLONE3_ARGS_ALL_0, 246170374Ssimokawa }, 247170374Ssimokawa { 248169119Ssimokawa .name = "Arguments sizeof(struct clone_arg) * 2", 249167632Ssimokawa .flags = 0, 250103285Sikob .size = sizeof(struct __clone_args) + 16, 251120660Ssimokawa .expected = -E2BIG, 252129585Sdfr .test_mode = CLONE3_ARGS_ALL_0, 253129585Sdfr }, 254129585Sdfr { 255103285Sikob .name = "Arguments > page size", 256103285Sikob .flags = 0, 257103285Sikob .size_function = page_size_plus_8, 258169119Ssimokawa .expected = -E2BIG, 259110269Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 260103285Sikob }, 261120660Ssimokawa { 262120660Ssimokawa .name = "CLONE_ARGS_SIZE_VER0 in a new PID NS", 263120660Ssimokawa .flags = CLONE_NEWPID, 264120660Ssimokawa .size = CLONE_ARGS_SIZE_VER0, 265120660Ssimokawa .expected = 0, 266120660Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 267129585Sdfr .filter = not_root, 268120660Ssimokawa }, 269120660Ssimokawa { 270129585Sdfr .name = "CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS", 271124169Ssimokawa .flags = CLONE_NEWPID, 272124169Ssimokawa .size = CLONE_ARGS_SIZE_VER0 - 8, 273124169Ssimokawa .expected = -EINVAL, 274124169Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 275124169Ssimokawa }, 276124169Ssimokawa { 277124169Ssimokawa .name = "sizeof(struct clone_args) + 8 in a new PID NS", 278124169Ssimokawa .flags = CLONE_NEWPID, 279124169Ssimokawa .size = sizeof(struct __clone_args) + 8, 280124169Ssimokawa .expected = 0, 281124169Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 282169130Ssimokawa .filter = not_root, 283169130Ssimokawa }, 284169130Ssimokawa { 285124169Ssimokawa .name = "Arguments > page size in a new PID NS", 286169117Ssimokawa .flags = CLONE_NEWPID, 287129585Sdfr .size_function = page_size_plus_8, 288124169Ssimokawa .expected = -E2BIG, 289124169Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 290170374Ssimokawa }, 291170374Ssimokawa { 292124169Ssimokawa .name = "New time NS", 293124169Ssimokawa .flags = CLONE_NEWTIME, 294124169Ssimokawa .size = 0, 295129585Sdfr .expected = 0, 296124169Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 297124169Ssimokawa .filter = no_timenamespace, 298124169Ssimokawa }, 299148868Srwatson { 300170374Ssimokawa .name = "exit signal (SIGCHLD) in flags", 301103285Sikob .flags = SIGCHLD, 302103285Sikob .size = 0, 303103285Sikob .expected = -EINVAL, 304170400Ssimokawa .test_mode = CLONE3_ARGS_NO_TEST, 305103285Sikob }, 306127468Ssimokawa}; 307127468Ssimokawa 308127468Ssimokawaint main(int argc, char *argv[]) 309103285Sikob{ 310127468Ssimokawa size_t size; 311103285Sikob int i; 312127468Ssimokawa 313127468Ssimokawa ksft_print_header(); 314127468Ssimokawa ksft_set_plan(ARRAY_SIZE(tests)); 315170374Ssimokawa test_clone3_supported(); 316111615Ssimokawa 317111615Ssimokawa for (i = 0; i < ARRAY_SIZE(tests); i++) { 318127468Ssimokawa if (tests[i].filter && tests[i].filter()) { 319120660Ssimokawa ksft_test_result_skip("%s\n", tests[i].name); 320120660Ssimokawa continue; 321120660Ssimokawa } 322120660Ssimokawa 323120660Ssimokawa if (tests[i].size_function) 324120660Ssimokawa size = tests[i].size_function(); 325120660Ssimokawa else 326120660Ssimokawa size = tests[i].size; 327120660Ssimokawa 328120660Ssimokawa ksft_print_msg("Running test '%s'\n", tests[i].name); 329120660Ssimokawa 330120660Ssimokawa ksft_test_result(test_clone3(tests[i].flags, size, 331120660Ssimokawa tests[i].expected, 332120660Ssimokawa tests[i].test_mode), 333120660Ssimokawa "%s\n", tests[i].name); 334121780Ssimokawa } 335120660Ssimokawa 336120660Ssimokawa ksft_finished(); 337110195Ssimokawa} 338110269Ssimokawa