419 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * Based on Christian Brauner's clone3() example.5 * These tests are assuming to be running in the host's6 * PID namespace.7 */8 9#define _GNU_SOURCE10#include <errno.h>11#include <linux/types.h>12#include <linux/sched.h>13#include <stdio.h>14#include <stdlib.h>15#include <stdbool.h>16#include <sys/syscall.h>17#include <sys/types.h>18#include <sys/un.h>19#include <sys/wait.h>20#include <unistd.h>21#include <sched.h>22 23#include "../kselftest.h"24#include "clone3_selftests.h"25 26#define MAX_PID_NS_LEVEL 3227 28static int pipe_1[2];29static int pipe_2[2];30 31static void child_exit(int ret)32{33 fflush(stdout);34 fflush(stderr);35 _exit(ret);36}37 38static int call_clone3_set_tid(pid_t *set_tid,39 size_t set_tid_size,40 int flags,41 int expected_pid,42 bool wait_for_it)43{44 int status;45 pid_t pid = -1;46 47 struct __clone_args args = {48 .flags = flags,49 .exit_signal = SIGCHLD,50 .set_tid = ptr_to_u64(set_tid),51 .set_tid_size = set_tid_size,52 };53 54 pid = sys_clone3(&args, sizeof(args));55 if (pid < 0) {56 ksft_print_msg("%s - Failed to create new process\n",57 strerror(errno));58 return -errno;59 }60 61 if (pid == 0) {62 int ret;63 char tmp = 0;64 int exit_code = EXIT_SUCCESS;65 66 ksft_print_msg("I am the child, my PID is %d (expected %d)\n",67 getpid(), set_tid[0]);68 if (wait_for_it) {69 ksft_print_msg("[%d] Child is ready and waiting\n",70 getpid());71 72 /* Signal the parent that the child is ready */73 close(pipe_1[0]);74 ret = write(pipe_1[1], &tmp, 1);75 if (ret != 1) {76 ksft_print_msg(77 "Writing to pipe returned %d", ret);78 exit_code = EXIT_FAILURE;79 }80 close(pipe_1[1]);81 close(pipe_2[1]);82 ret = read(pipe_2[0], &tmp, 1);83 if (ret != 1) {84 ksft_print_msg(85 "Reading from pipe returned %d", ret);86 exit_code = EXIT_FAILURE;87 }88 close(pipe_2[0]);89 }90 91 if (set_tid[0] != getpid())92 child_exit(EXIT_FAILURE);93 child_exit(exit_code);94 }95 96 if (expected_pid == 0 || expected_pid == pid) {97 ksft_print_msg("I am the parent (%d). My child's pid is %d\n",98 getpid(), pid);99 } else {100 ksft_print_msg(101 "Expected child pid %d does not match actual pid %d\n",102 expected_pid, pid);103 return -1;104 }105 106 if (waitpid(pid, &status, 0) < 0) {107 ksft_print_msg("Child returned %s\n", strerror(errno));108 return -errno;109 }110 111 if (!WIFEXITED(status))112 return -1;113 114 return WEXITSTATUS(status);115}116 117static void test_clone3_set_tid(const char *desc,118 pid_t *set_tid,119 size_t set_tid_size,120 int flags,121 int expected,122 int expected_pid,123 bool wait_for_it)124{125 int ret;126 127 ksft_print_msg(128 "[%d] Trying clone3() with CLONE_SET_TID to %d and 0x%x\n",129 getpid(), set_tid[0], flags);130 ret = call_clone3_set_tid(set_tid, set_tid_size, flags, expected_pid,131 wait_for_it);132 ksft_print_msg(133 "[%d] clone3() with CLONE_SET_TID %d says: %d - expected %d\n",134 getpid(), set_tid[0], ret, expected);135 136 ksft_test_result(ret == expected, "%s with %zu TIDs and flags 0x%x\n",137 desc, set_tid_size, flags);138}139 140int main(int argc, char *argv[])141{142 FILE *f;143 char buf;144 char *line;145 int status;146 int ret = -1;147 size_t len = 0;148 int pid_max = 0;149 uid_t uid = getuid();150 char proc_path[100] = {0};151 pid_t pid, ns1, ns2, ns3, ns_pid;152 pid_t set_tid[MAX_PID_NS_LEVEL * 2];153 154 ksft_print_header();155 ksft_set_plan(29);156 test_clone3_supported();157 158 if (pipe(pipe_1) < 0 || pipe(pipe_2) < 0)159 ksft_exit_fail_msg("pipe() failed\n");160 161 f = fopen("/proc/sys/kernel/pid_max", "r");162 if (f == NULL)163 ksft_exit_fail_msg(164 "%s - Could not open /proc/sys/kernel/pid_max\n",165 strerror(errno));166 fscanf(f, "%d", &pid_max);167 fclose(f);168 ksft_print_msg("/proc/sys/kernel/pid_max %d\n", pid_max);169 170 /* Try invalid settings */171 memset(&set_tid, 0, sizeof(set_tid));172 test_clone3_set_tid("invalid size, 0 TID",173 set_tid, MAX_PID_NS_LEVEL + 1, 0, -EINVAL, 0, 0);174 175 test_clone3_set_tid("invalid size, 0 TID",176 set_tid, MAX_PID_NS_LEVEL * 2, 0, -EINVAL, 0, 0);177 178 test_clone3_set_tid("invalid size, 0 TID",179 set_tid, MAX_PID_NS_LEVEL * 2 + 1, 0,180 -EINVAL, 0, 0);181 182 test_clone3_set_tid("invalid size, 0 TID",183 set_tid, MAX_PID_NS_LEVEL * 42, 0, -EINVAL, 0, 0);184 185 /*186 * This can actually work if this test running in a MAX_PID_NS_LEVEL - 1187 * nested PID namespace.188 */189 test_clone3_set_tid("invalid size, 0 TID",190 set_tid, MAX_PID_NS_LEVEL - 1, 0, -EINVAL, 0, 0);191 192 memset(&set_tid, 0xff, sizeof(set_tid));193 test_clone3_set_tid("invalid size, TID all 1s",194 set_tid, MAX_PID_NS_LEVEL + 1, 0, -EINVAL, 0, 0);195 196 test_clone3_set_tid("invalid size, TID all 1s",197 set_tid, MAX_PID_NS_LEVEL * 2, 0, -EINVAL, 0, 0);198 199 test_clone3_set_tid("invalid size, TID all 1s",200 set_tid, MAX_PID_NS_LEVEL * 2 + 1, 0,201 -EINVAL, 0, 0);202 203 test_clone3_set_tid("invalid size, TID all 1s",204 set_tid, MAX_PID_NS_LEVEL * 42, 0, -EINVAL, 0, 0);205 206 /*207 * This can actually work if this test running in a MAX_PID_NS_LEVEL - 1208 * nested PID namespace.209 */210 test_clone3_set_tid("invalid size, TID all 1s",211 set_tid, MAX_PID_NS_LEVEL - 1, 0, -EINVAL, 0, 0);212 213 memset(&set_tid, 0, sizeof(set_tid));214 /* Try with an invalid PID */215 set_tid[0] = 0;216 test_clone3_set_tid("valid size, 0 TID",217 set_tid, 1, 0, -EINVAL, 0, 0);218 219 set_tid[0] = -1;220 test_clone3_set_tid("valid size, -1 TID",221 set_tid, 1, 0, -EINVAL, 0, 0);222 223 /* Claim that the set_tid array actually contains 2 elements. */224 test_clone3_set_tid("2 TIDs, -1 and 0",225 set_tid, 2, 0, -EINVAL, 0, 0);226 227 /* Try it in a new PID namespace */228 if (uid == 0)229 test_clone3_set_tid("valid size, -1 TID",230 set_tid, 1, CLONE_NEWPID, -EINVAL, 0, 0);231 else232 ksft_test_result_skip("Clone3() with set_tid requires root\n");233 234 /* Try with a valid PID (1) this should return -EEXIST. */235 set_tid[0] = 1;236 if (uid == 0)237 test_clone3_set_tid("duplicate PID 1",238 set_tid, 1, 0, -EEXIST, 0, 0);239 else240 ksft_test_result_skip("Clone3() with set_tid requires root\n");241 242 /* Try it in a new PID namespace */243 if (uid == 0)244 test_clone3_set_tid("duplicate PID 1",245 set_tid, 1, CLONE_NEWPID, 0, 0, 0);246 else247 ksft_test_result_skip("Clone3() with set_tid requires root\n");248 249 /* pid_max should fail everywhere */250 set_tid[0] = pid_max;251 test_clone3_set_tid("set TID to maximum",252 set_tid, 1, 0, -EINVAL, 0, 0);253 254 if (uid == 0)255 test_clone3_set_tid("set TID to maximum",256 set_tid, 1, CLONE_NEWPID, -EINVAL, 0, 0);257 else258 ksft_test_result_skip("Clone3() with set_tid requires root\n");259 260 if (uid != 0) {261 /*262 * All remaining tests require root. Tell the framework263 * that all those tests are skipped as non-root.264 */265 ksft_cnt.ksft_xskip += ksft_plan - ksft_test_num();266 goto out;267 }268 269 /* Find the current active PID */270 pid = fork();271 if (pid == 0) {272 ksft_print_msg("Child has PID %d\n", getpid());273 child_exit(EXIT_SUCCESS);274 }275 if (waitpid(pid, &status, 0) < 0)276 ksft_exit_fail_msg("Waiting for child %d failed", pid);277 278 /* After the child has finished, its PID should be free. */279 set_tid[0] = pid;280 test_clone3_set_tid("reallocate child TID",281 set_tid, 1, 0, 0, 0, 0);282 283 /* This should fail as there is no PID 1 in that namespace */284 test_clone3_set_tid("duplicate child TID",285 set_tid, 1, CLONE_NEWPID, -EINVAL, 0, 0);286 287 /*288 * Creating a process with PID 1 in the newly created most nested289 * PID namespace and PID 'pid' in the parent PID namespace. This290 * needs to work.291 */292 set_tid[0] = 1;293 set_tid[1] = pid;294 test_clone3_set_tid("create PID 1 in new NS",295 set_tid, 2, CLONE_NEWPID, 0, pid, 0);296 297 ksft_print_msg("unshare PID namespace\n");298 if (unshare(CLONE_NEWPID) == -1)299 ksft_exit_fail_msg("unshare(CLONE_NEWPID) failed: %s\n",300 strerror(errno));301 302 set_tid[0] = pid;303 304 /* This should fail as there is no PID 1 in that namespace */305 test_clone3_set_tid("duplicate PID 1",306 set_tid, 1, 0, -EINVAL, 0, 0);307 308 /* Let's create a PID 1 */309 ns_pid = fork();310 if (ns_pid == 0) {311 /*312 * This and the next test cases check that all pid-s are313 * released on error paths.314 */315 set_tid[0] = 43;316 set_tid[1] = -1;317 test_clone3_set_tid("check leak on invalid TID -1",318 set_tid, 2, 0, -EINVAL, 0, 0);319 320 set_tid[0] = 43;321 set_tid[1] = pid;322 test_clone3_set_tid("check leak on invalid specific TID",323 set_tid, 2, 0, 0, 43, 0);324 325 ksft_print_msg("Child in PID namespace has PID %d\n", getpid());326 set_tid[0] = 2;327 test_clone3_set_tid("create PID 2 in child NS",328 set_tid, 1, 0, 0, 2, 0);329 330 set_tid[0] = 1;331 set_tid[1] = -1;332 set_tid[2] = pid;333 /* This should fail as there is invalid PID at level '1'. */334 test_clone3_set_tid("fail due to invalid TID at level 1",335 set_tid, 3, CLONE_NEWPID, -EINVAL, 0, 0);336 337 set_tid[0] = 1;338 set_tid[1] = 42;339 set_tid[2] = pid;340 /*341 * This should fail as there are not enough active PID342 * namespaces. Again assuming this is running in the host's343 * PID namespace. Not yet nested.344 */345 test_clone3_set_tid("fail due to too few active PID NSs",346 set_tid, 4, CLONE_NEWPID, -EINVAL, 0, 0);347 348 /*349 * This should work and from the parent we should see350 * something like 'NSpid: pid 42 1'.351 */352 test_clone3_set_tid("verify that we have 3 PID NSs",353 set_tid, 3, CLONE_NEWPID, 0, 42, true);354 355 child_exit(ksft_cnt.ksft_fail);356 }357 358 close(pipe_1[1]);359 close(pipe_2[0]);360 while (read(pipe_1[0], &buf, 1) > 0) {361 ksft_print_msg("[%d] Child is ready and waiting\n", getpid());362 break;363 }364 365 snprintf(proc_path, sizeof(proc_path), "/proc/%d/status", pid);366 f = fopen(proc_path, "r");367 if (f == NULL)368 ksft_exit_fail_msg(369 "%s - Could not open %s\n",370 strerror(errno), proc_path);371 372 while (getline(&line, &len, f) != -1) {373 if (strstr(line, "NSpid")) {374 int i;375 376 /* Verify that all generated PIDs are as expected. */377 i = sscanf(line, "NSpid:\t%d\t%d\t%d",378 &ns3, &ns2, &ns1);379 if (i != 3) {380 ksft_print_msg(381 "Unexpected 'NSPid:' entry: %s",382 line);383 ns1 = ns2 = ns3 = 0;384 }385 break;386 }387 }388 fclose(f);389 free(line);390 close(pipe_2[0]);391 392 /* Tell the clone3()'d child to finish. */393 write(pipe_2[1], &buf, 1);394 close(pipe_2[1]);395 396 if (waitpid(ns_pid, &status, 0) < 0) {397 ksft_print_msg("Child returned %s\n", strerror(errno));398 ret = -errno;399 goto out;400 }401 402 if (!WIFEXITED(status))403 ksft_test_result_fail("Child error\n");404 405 ksft_cnt.ksft_pass += 6 - (ksft_cnt.ksft_fail - WEXITSTATUS(status));406 ksft_cnt.ksft_fail = WEXITSTATUS(status);407 408 ksft_print_msg("Expecting PIDs %d, 42, 1\n", pid);409 ksft_print_msg("Have PIDs in namespaces: %d, %d, %d\n", ns3, ns2, ns1);410 ksft_test_result(ns3 == pid && ns2 == 42 && ns1 == 1,411 "PIDs in all namespaces as expected\n");412out:413 ret = 0;414 415 if (ret)416 ksft_exit_fail();417 ksft_exit_pass();418}419