0001
0002
0003
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
0058
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
0136 test_clone3(0, 0, 0, CLONE3_ARGS_NO_TEST);
0137
0138
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
0145 test_clone3(0, CLONE_ARGS_SIZE_VER0, 0, CLONE3_ARGS_NO_TEST);
0146
0147
0148 test_clone3(0, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL, CLONE3_ARGS_NO_TEST);
0149
0150
0151 test_clone3(0, sizeof(struct __clone_args) + 8, 0, CLONE3_ARGS_NO_TEST);
0152
0153
0154 test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG);
0155
0156
0157 test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG);
0158
0159
0160 test_clone3(0, 0, -EINVAL, CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG);
0161
0162
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
0174 test_clone3(0, getpagesize() + 8, -E2BIG, CLONE3_ARGS_NO_TEST);
0175
0176
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
0184 test_clone3(CLONE_NEWPID, CLONE_ARGS_SIZE_VER0 - 8, -EINVAL,
0185 CLONE3_ARGS_NO_TEST);
0186
0187
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
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 }