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