1*7c5219e1SPavel Tikhomirov // SPDX-License-Identifier: GPL-2.0 2*7c5219e1SPavel Tikhomirov #define _GNU_SOURCE 3*7c5219e1SPavel Tikhomirov #include <fcntl.h> 4*7c5219e1SPavel Tikhomirov #include <sched.h> 5*7c5219e1SPavel Tikhomirov #include <stdio.h> 6*7c5219e1SPavel Tikhomirov #include <sys/types.h> 7*7c5219e1SPavel Tikhomirov #include <unistd.h> 8*7c5219e1SPavel Tikhomirov 9*7c5219e1SPavel Tikhomirov #include "kselftest_harness.h" 10*7c5219e1SPavel Tikhomirov #include "../pidfd/pidfd.h" 11*7c5219e1SPavel Tikhomirov 12*7c5219e1SPavel Tikhomirov /* 13*7c5219e1SPavel Tikhomirov * Test that a process can become PID 1 (init) in a new PID namespace 14*7c5219e1SPavel Tikhomirov * created via unshare() and joined via setns(). 15*7c5219e1SPavel Tikhomirov * 16*7c5219e1SPavel Tikhomirov * Flow: 17*7c5219e1SPavel Tikhomirov * 1. Parent creates a pipe for synchronization. 18*7c5219e1SPavel Tikhomirov * 2. Parent forks a child. 19*7c5219e1SPavel Tikhomirov * 3. Parent calls unshare(CLONE_NEWPID) to create a new PID namespace. 20*7c5219e1SPavel Tikhomirov * 4. Parent signals the child via the pipe. 21*7c5219e1SPavel Tikhomirov * 5. Child opens parent's /proc/<ppid>/ns/pid_for_children and calls 22*7c5219e1SPavel Tikhomirov * setns(fd, CLONE_NEWPID) to join the new namespace. 23*7c5219e1SPavel Tikhomirov * 6. Child forks a grandchild. 24*7c5219e1SPavel Tikhomirov * 7. Grandchild verifies getpid() == 1. 25*7c5219e1SPavel Tikhomirov */ 26*7c5219e1SPavel Tikhomirov TEST(pidns_init_via_setns) 27*7c5219e1SPavel Tikhomirov { 28*7c5219e1SPavel Tikhomirov pid_t child, parent_pid; 29*7c5219e1SPavel Tikhomirov int pipe_fd[2]; 30*7c5219e1SPavel Tikhomirov char buf; 31*7c5219e1SPavel Tikhomirov 32*7c5219e1SPavel Tikhomirov if (geteuid()) 33*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, unshare(CLONE_NEWUSER)); 34*7c5219e1SPavel Tikhomirov 35*7c5219e1SPavel Tikhomirov parent_pid = getpid(); 36*7c5219e1SPavel Tikhomirov 37*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, pipe(pipe_fd)); 38*7c5219e1SPavel Tikhomirov 39*7c5219e1SPavel Tikhomirov child = fork(); 40*7c5219e1SPavel Tikhomirov ASSERT_GE(child, 0); 41*7c5219e1SPavel Tikhomirov 42*7c5219e1SPavel Tikhomirov if (child == 0) { 43*7c5219e1SPavel Tikhomirov char path[256]; 44*7c5219e1SPavel Tikhomirov int nsfd; 45*7c5219e1SPavel Tikhomirov pid_t grandchild; 46*7c5219e1SPavel Tikhomirov 47*7c5219e1SPavel Tikhomirov close(pipe_fd[1]); 48*7c5219e1SPavel Tikhomirov 49*7c5219e1SPavel Tikhomirov /* Wait for parent to complete unshare */ 50*7c5219e1SPavel Tikhomirov ASSERT_EQ(1, read_nointr(pipe_fd[0], &buf, 1)); 51*7c5219e1SPavel Tikhomirov close(pipe_fd[0]); 52*7c5219e1SPavel Tikhomirov 53*7c5219e1SPavel Tikhomirov snprintf(path, sizeof(path), 54*7c5219e1SPavel Tikhomirov "/proc/%d/ns/pid_for_children", parent_pid); 55*7c5219e1SPavel Tikhomirov nsfd = open(path, O_RDONLY); 56*7c5219e1SPavel Tikhomirov ASSERT_GE(nsfd, 0); 57*7c5219e1SPavel Tikhomirov 58*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, setns(nsfd, CLONE_NEWPID)); 59*7c5219e1SPavel Tikhomirov close(nsfd); 60*7c5219e1SPavel Tikhomirov 61*7c5219e1SPavel Tikhomirov grandchild = fork(); 62*7c5219e1SPavel Tikhomirov ASSERT_GE(grandchild, 0); 63*7c5219e1SPavel Tikhomirov 64*7c5219e1SPavel Tikhomirov if (grandchild == 0) { 65*7c5219e1SPavel Tikhomirov /* Should be init (PID 1) in the new namespace */ 66*7c5219e1SPavel Tikhomirov if (getpid() != 1) 67*7c5219e1SPavel Tikhomirov _exit(1); 68*7c5219e1SPavel Tikhomirov _exit(0); 69*7c5219e1SPavel Tikhomirov } 70*7c5219e1SPavel Tikhomirov 71*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, wait_for_pid(grandchild)); 72*7c5219e1SPavel Tikhomirov _exit(0); 73*7c5219e1SPavel Tikhomirov } 74*7c5219e1SPavel Tikhomirov 75*7c5219e1SPavel Tikhomirov close(pipe_fd[0]); 76*7c5219e1SPavel Tikhomirov 77*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, unshare(CLONE_NEWPID)); 78*7c5219e1SPavel Tikhomirov 79*7c5219e1SPavel Tikhomirov /* Signal child that the new PID namespace is ready */ 80*7c5219e1SPavel Tikhomirov buf = 0; 81*7c5219e1SPavel Tikhomirov ASSERT_EQ(1, write_nointr(pipe_fd[1], &buf, 1)); 82*7c5219e1SPavel Tikhomirov close(pipe_fd[1]); 83*7c5219e1SPavel Tikhomirov 84*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, wait_for_pid(child)); 85*7c5219e1SPavel Tikhomirov } 86*7c5219e1SPavel Tikhomirov 87*7c5219e1SPavel Tikhomirov /* 88*7c5219e1SPavel Tikhomirov * Similar to pidns_init_via_setns, but: 89*7c5219e1SPavel Tikhomirov * 1. Parent enters a new PID namespace right from the start to be able to 90*7c5219e1SPavel Tikhomirov * later freely use pid 1001 in it. 91*7c5219e1SPavel Tikhomirov * 2. After forking child, parent also calls unshare(CLONE_NEWUSER) 92*7c5219e1SPavel Tikhomirov * before unshare(CLONE_NEWPID) so that new old and new pid namespaces have 93*7c5219e1SPavel Tikhomirov * different user namespace owners. 94*7c5219e1SPavel Tikhomirov * 3. Child uses clone3() with set_tid={1, 1001} instead of fork() and 95*7c5219e1SPavel Tikhomirov * grandchild checks that it gets desired pids . 96*7c5219e1SPavel Tikhomirov * 97*7c5219e1SPavel Tikhomirov * Flow: 98*7c5219e1SPavel Tikhomirov * 1. Test process creates a new PID namespace and forks a wrapper 99*7c5219e1SPavel Tikhomirov * (PID 1 in the outer namespace). 100*7c5219e1SPavel Tikhomirov * 2. Wrapper forks a child. 101*7c5219e1SPavel Tikhomirov * 3. Wrapper calls unshare(CLONE_NEWUSER) + unshare(CLONE_NEWPID) 102*7c5219e1SPavel Tikhomirov * to create an inner PID namespace. 103*7c5219e1SPavel Tikhomirov * 4. Wrapper signals the child via pipe. 104*7c5219e1SPavel Tikhomirov * 5. Child opens wrapper's /proc/<pid>/ns/pid_for_children and calls 105*7c5219e1SPavel Tikhomirov * setns(fd, CLONE_NEWPID) to join the inner namespace. 106*7c5219e1SPavel Tikhomirov * 6. Child calls clone3() with set_tid={1, 1001}. 107*7c5219e1SPavel Tikhomirov * 7. Grandchild verifies its NSpid ends with "1001 1". 108*7c5219e1SPavel Tikhomirov */ 109*7c5219e1SPavel Tikhomirov 110*7c5219e1SPavel Tikhomirov pid_t set_tid[] = {1, 1001}; 111*7c5219e1SPavel Tikhomirov 112*7c5219e1SPavel Tikhomirov static int pidns_init_via_setns_set_tid_grandchild(struct __test_metadata *_metadata) 113*7c5219e1SPavel Tikhomirov { 114*7c5219e1SPavel Tikhomirov char *line = NULL; 115*7c5219e1SPavel Tikhomirov size_t len = 0; 116*7c5219e1SPavel Tikhomirov int found = 0; 117*7c5219e1SPavel Tikhomirov FILE *gf; 118*7c5219e1SPavel Tikhomirov 119*7c5219e1SPavel Tikhomirov gf = fopen("/proc/self/status", "r"); 120*7c5219e1SPavel Tikhomirov ASSERT_NE(gf, NULL); 121*7c5219e1SPavel Tikhomirov 122*7c5219e1SPavel Tikhomirov while (getline(&line, &len, gf) != -1) { 123*7c5219e1SPavel Tikhomirov if (strncmp(line, "NSpid:", 6) != 0) 124*7c5219e1SPavel Tikhomirov continue; 125*7c5219e1SPavel Tikhomirov 126*7c5219e1SPavel Tikhomirov for (int i = 0; i < 2; i++) { 127*7c5219e1SPavel Tikhomirov char *last = strrchr(line, '\t'); 128*7c5219e1SPavel Tikhomirov pid_t pid; 129*7c5219e1SPavel Tikhomirov 130*7c5219e1SPavel Tikhomirov ASSERT_NE(last, NULL); 131*7c5219e1SPavel Tikhomirov ASSERT_EQ(sscanf(last, "%d", &pid), 1); 132*7c5219e1SPavel Tikhomirov ASSERT_EQ(pid, set_tid[i]); 133*7c5219e1SPavel Tikhomirov *last = '\0'; 134*7c5219e1SPavel Tikhomirov } 135*7c5219e1SPavel Tikhomirov 136*7c5219e1SPavel Tikhomirov found = true; 137*7c5219e1SPavel Tikhomirov break; 138*7c5219e1SPavel Tikhomirov } 139*7c5219e1SPavel Tikhomirov 140*7c5219e1SPavel Tikhomirov free(line); 141*7c5219e1SPavel Tikhomirov fclose(gf); 142*7c5219e1SPavel Tikhomirov ASSERT_TRUE(found); 143*7c5219e1SPavel Tikhomirov return 0; 144*7c5219e1SPavel Tikhomirov } 145*7c5219e1SPavel Tikhomirov 146*7c5219e1SPavel Tikhomirov static int pidns_init_via_setns_set_tid_child(struct __test_metadata *_metadata, 147*7c5219e1SPavel Tikhomirov pid_t parent_pid, int pipe_fd[2]) 148*7c5219e1SPavel Tikhomirov { 149*7c5219e1SPavel Tikhomirov struct __clone_args args = { 150*7c5219e1SPavel Tikhomirov .exit_signal = SIGCHLD, 151*7c5219e1SPavel Tikhomirov .set_tid = ptr_to_u64(set_tid), 152*7c5219e1SPavel Tikhomirov .set_tid_size = 2, 153*7c5219e1SPavel Tikhomirov }; 154*7c5219e1SPavel Tikhomirov pid_t grandchild; 155*7c5219e1SPavel Tikhomirov char path[256]; 156*7c5219e1SPavel Tikhomirov char buf; 157*7c5219e1SPavel Tikhomirov int nsfd; 158*7c5219e1SPavel Tikhomirov 159*7c5219e1SPavel Tikhomirov close(pipe_fd[1]); 160*7c5219e1SPavel Tikhomirov 161*7c5219e1SPavel Tikhomirov ASSERT_EQ(1, read_nointr(pipe_fd[0], &buf, 1)); 162*7c5219e1SPavel Tikhomirov close(pipe_fd[0]); 163*7c5219e1SPavel Tikhomirov 164*7c5219e1SPavel Tikhomirov snprintf(path, sizeof(path), 165*7c5219e1SPavel Tikhomirov "/proc/%d/ns/pid_for_children", parent_pid); 166*7c5219e1SPavel Tikhomirov nsfd = open(path, O_RDONLY); 167*7c5219e1SPavel Tikhomirov ASSERT_GE(nsfd, 0); 168*7c5219e1SPavel Tikhomirov 169*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, setns(nsfd, CLONE_NEWPID)); 170*7c5219e1SPavel Tikhomirov close(nsfd); 171*7c5219e1SPavel Tikhomirov 172*7c5219e1SPavel Tikhomirov grandchild = sys_clone3(&args, sizeof(args)); 173*7c5219e1SPavel Tikhomirov ASSERT_GE(grandchild, 0); 174*7c5219e1SPavel Tikhomirov 175*7c5219e1SPavel Tikhomirov if (grandchild == 0) 176*7c5219e1SPavel Tikhomirov _exit(pidns_init_via_setns_set_tid_grandchild(_metadata)); 177*7c5219e1SPavel Tikhomirov 178*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, wait_for_pid(grandchild)); 179*7c5219e1SPavel Tikhomirov return 0; 180*7c5219e1SPavel Tikhomirov } 181*7c5219e1SPavel Tikhomirov 182*7c5219e1SPavel Tikhomirov static int pidns_init_via_setns_set_tid_wrapper(struct __test_metadata *_metadata) 183*7c5219e1SPavel Tikhomirov { 184*7c5219e1SPavel Tikhomirov int pipe_fd[2]; 185*7c5219e1SPavel Tikhomirov pid_t child, parent_pid; 186*7c5219e1SPavel Tikhomirov char buf; 187*7c5219e1SPavel Tikhomirov FILE *f; 188*7c5219e1SPavel Tikhomirov 189*7c5219e1SPavel Tikhomirov /* 190*7c5219e1SPavel Tikhomirov * We are PID 1 inside the new namespace, but /proc is 191*7c5219e1SPavel Tikhomirov * mounted from the host. Read our host-visible PID so 192*7c5219e1SPavel Tikhomirov * the child can reach our pid_for_children via /proc. 193*7c5219e1SPavel Tikhomirov */ 194*7c5219e1SPavel Tikhomirov f = fopen("/proc/self/stat", "r"); 195*7c5219e1SPavel Tikhomirov ASSERT_NE(f, NULL); 196*7c5219e1SPavel Tikhomirov ASSERT_EQ(fscanf(f, "%d", &parent_pid), 1); 197*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, pipe(pipe_fd)); 198*7c5219e1SPavel Tikhomirov 199*7c5219e1SPavel Tikhomirov child = fork(); 200*7c5219e1SPavel Tikhomirov ASSERT_GE(child, 0); 201*7c5219e1SPavel Tikhomirov 202*7c5219e1SPavel Tikhomirov if (child == 0) 203*7c5219e1SPavel Tikhomirov _exit(pidns_init_via_setns_set_tid_child(_metadata, parent_pid, pipe_fd)); 204*7c5219e1SPavel Tikhomirov 205*7c5219e1SPavel Tikhomirov close(pipe_fd[0]); 206*7c5219e1SPavel Tikhomirov 207*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, unshare(CLONE_NEWUSER)); 208*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, unshare(CLONE_NEWPID)); 209*7c5219e1SPavel Tikhomirov 210*7c5219e1SPavel Tikhomirov buf = 0; 211*7c5219e1SPavel Tikhomirov ASSERT_EQ(1, write_nointr(pipe_fd[1], &buf, 1)); 212*7c5219e1SPavel Tikhomirov close(pipe_fd[1]); 213*7c5219e1SPavel Tikhomirov 214*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, wait_for_pid(child)); 215*7c5219e1SPavel Tikhomirov 216*7c5219e1SPavel Tikhomirov fclose(f); 217*7c5219e1SPavel Tikhomirov return 0; 218*7c5219e1SPavel Tikhomirov } 219*7c5219e1SPavel Tikhomirov 220*7c5219e1SPavel Tikhomirov TEST(pidns_init_via_setns_set_tid) 221*7c5219e1SPavel Tikhomirov { 222*7c5219e1SPavel Tikhomirov pid_t wrapper; 223*7c5219e1SPavel Tikhomirov 224*7c5219e1SPavel Tikhomirov if (geteuid()) 225*7c5219e1SPavel Tikhomirov SKIP(return, "This test needs root to run!"); 226*7c5219e1SPavel Tikhomirov 227*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, unshare(CLONE_NEWPID)); 228*7c5219e1SPavel Tikhomirov 229*7c5219e1SPavel Tikhomirov wrapper = fork(); 230*7c5219e1SPavel Tikhomirov ASSERT_GE(wrapper, 0); 231*7c5219e1SPavel Tikhomirov 232*7c5219e1SPavel Tikhomirov if (wrapper == 0) 233*7c5219e1SPavel Tikhomirov _exit(pidns_init_via_setns_set_tid_wrapper(_metadata)); 234*7c5219e1SPavel Tikhomirov 235*7c5219e1SPavel Tikhomirov ASSERT_EQ(0, wait_for_pid(wrapper)); 236*7c5219e1SPavel Tikhomirov } 237*7c5219e1SPavel Tikhomirov 238*7c5219e1SPavel Tikhomirov TEST_HARNESS_MAIN 239