Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 /* Based on Christian Brauner's clone3() example */
0004 
0005 #define _GNU_SOURCE
0006 #include <errno.h>
0007 #include <inttypes.h>
0008 #include <linux/types.h>
0009 #include <linux/sched.h>
0010 #include <stdint.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <sys/syscall.h>
0014 #include <sys/types.h>
0015 #include <sys/un.h>
0016 #include <sys/wait.h>
0017 #include <unistd.h>
0018 #include <sched.h>
0019 
0020 #include "../kselftest.h"
0021 #include "clone3_selftests.h"
0022 
0023 enum test_mode {
0024     CLONE3_ARGS_NO_TEST,
0025     CLONE3_ARGS_ALL_0,
0026     CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
0027     CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
0028     CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
0029     CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
0030 };
0031 
0032 static int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode)
0033 {
0034     struct __clone_args args = {
0035         .flags = flags,
0036         .exit_signal = SIGCHLD,
0037     };
0038 
0039     struct clone_args_extended {
0040         struct __clone_args args;
0041         __aligned_u64 excess_space[2];
0042     } args_ext;
0043 
0044     pid_t pid = -1;
0045     int status;
0046 
0047     memset(&args_ext, 0, sizeof(args_ext));
0048     if (size > sizeof(struct __clone_args))
0049         args_ext.excess_space[1] = 1;
0050 
0051     if (size == 0)
0052         size = sizeof(struct __clone_args);
0053 
0054     switch (test_mode) {
0055     case CLONE3_ARGS_NO_TEST:
0056         /*
0057          * Uses default 'flags' and 'SIGCHLD'
0058          * assignment.
0059          */
0060         break;
0061     case CLONE3_ARGS_ALL_0:
0062         args.flags = 0;
0063         args.exit_signal = 0;
0064         break;
0065     case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG:
0066         args.exit_signal = 0xbadc0ded00000000ULL;
0067         break;
0068     case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG:
0069         args.exit_signal = 0x0000000080000000ULL;
0070         break;
0071     case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG:
0072         args.exit_signal = 0x0000000000000100ULL;
0073         break;
0074     case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG:
0075         args.exit_signal = 0x00000000000000f0ULL;
0076         break;
0077     }
0078 
0079     memcpy(&args_ext.args, &args, sizeof(struct __clone_args));
0080 
0081     pid = sys_clone3((struct __clone_args *)&args_ext, size);
0082     if (pid < 0) {
0083         ksft_print_msg("%s - Failed to create new process\n",
0084                 strerror(errno));
0085         return -errno;
0086     }
0087 
0088     if (pid == 0) {
0089         ksft_print_msg("I am the child, my PID is %d\n", getpid());
0090         _exit(EXIT_SUCCESS);
0091     }
0092 
0093     ksft_print_msg("I am the parent (%d). My child's pid is %d\n",
0094             getpid(), pid);
0095 
0096     if (waitpid(-1, &status, __WALL) < 0) {
0097         ksft_print_msg("Child returned %s\n", strerror(errno));
0098         return -errno;
0099     }
0100     if (WEXITSTATUS(status))
0101         return WEXITSTATUS(status);
0102 
0103     return 0;
0104 }
0105 
0106 static void test_clone3(uint64_t flags, size_t size, int expected,
0107                enum test_mode test_mode)
0108 {
0109     int ret;
0110 
0111     ksft_print_msg(
0112         "[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n",
0113         getpid(), flags, size);
0114     ret = call_clone3(flags, size, test_mode);
0115     ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n",
0116             getpid(), ret, expected);
0117     if (ret != expected)
0118         ksft_test_result_fail(
0119             "[%d] Result (%d) is different than expected (%d)\n",
0120             getpid(), ret, expected);
0121     else
0122         ksft_test_result_pass(
0123             "[%d] Result (%d) matches expectation (%d)\n",
0124             getpid(), ret, expected);
0125 }
0126 
0127 int main(int argc, char *argv[])
0128 {
0129     uid_t uid = getuid();
0130 
0131     ksft_print_header();
0132     ksft_set_plan(17);
0133     test_clone3_supported();
0134 
0135     /* Just a simple clone3() should return 0.*/
0136     test_clone3(0, 0, 0, CLONE3_ARGS_NO_TEST);
0137 
0138     /* Do a clone3() in a new PID NS.*/
0139     if (uid == 0)
0140         test_clone3(CLONE_NEWPID, 0, 0, CLONE3_ARGS_NO_TEST);
0141     else
0142         ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
0143 
0144     /* Do a clone3() with CLONE_ARGS_SIZE_VER0. */
0145     test_clone3(0, CLONE_ARGS_SIZE_VER0, 0, CLONE3_ARGS_NO_TEST);
0146 
0147     /* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 */
0148     test_clone3(0, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL, CLONE3_ARGS_NO_TEST);
0149 
0150     /* Do a clone3() with sizeof(struct clone_args) + 8 */
0151     test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_NO_TEST);
0152 
0153     /* Do a clone3() with exit_signal having highest 32 bits non-zero */
0154     test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG);
0155 
0156     /* Do a clone3() with negative 32-bit exit_signal */
0157     test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG);
0158 
0159     /* Do a clone3() with exit_signal not fitting into CSIGNAL mask */
0160     test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG);
0161 
0162     /* Do a clone3() with NSIG < exit_signal < CSIG */
0163     test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG);
0164 
0165     test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_ALL_0);
0166 
0167     test_clone3(0, sizeof(struct __clone_args) + 16, -E2BIG,
0168             CLONE3_ARGS_ALL_0);
0169 
0170     test_clone3(0, sizeof(struct __clone_args) * 2, -E2BIG,
0171             CLONE3_ARGS_ALL_0);
0172 
0173     /* Do a clone3() with > page size */
0174     test_clone3(0, getpagesize() + 8, -E2BIG, CLONE3_ARGS_NO_TEST);
0175 
0176     /* Do a clone3() with CLONE_ARGS_SIZE_VER0 in a new PID NS. */
0177     if (uid == 0)
0178         test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0, 0,
0179                 CLONE3_ARGS_NO_TEST);
0180     else
0181         ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
0182 
0183     /* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS */
0184     test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL,
0185             CLONE3_ARGS_NO_TEST);
0186 
0187     /* Do a clone3() with sizeof(struct clone_args) + 8 in a new PID NS */
0188     if (uid == 0)
0189         test_clone3(CLONE_NEWPID, sizeof(struct __clone_args) + 8, 0,
0190                 CLONE3_ARGS_NO_TEST);
0191     else
0192         ksft_test_result_skip("Skipping clone3() with CLONE_NEWPID\n");
0193 
0194     /* Do a clone3() with > page size in a new PID NS */
0195     test_clone3(CLONE_NEWPID, getpagesize() + 8, -E2BIG,
0196             CLONE3_ARGS_NO_TEST);
0197 
0198     return !ksft_get_fail_cnt() ? ksft_exit_pass() : ksft_exit_fail();
0199 }