1*2ec5a070SSahaj Chaudhari // SPDX-License-Identifier: GPL-2.0
2*2ec5a070SSahaj Chaudhari #define _GNU_SOURCE
3*2ec5a070SSahaj Chaudhari
4*2ec5a070SSahaj Chaudhari #include <errno.h>
5*2ec5a070SSahaj Chaudhari #include <fcntl.h>
6*2ec5a070SSahaj Chaudhari #include <sched.h>
7*2ec5a070SSahaj Chaudhari #include <signal.h>
8*2ec5a070SSahaj Chaudhari #include <stdio.h>
9*2ec5a070SSahaj Chaudhari #include <sys/mman.h>
10*2ec5a070SSahaj Chaudhari #include <sys/types.h>
11*2ec5a070SSahaj Chaudhari #include <sys/wait.h>
12*2ec5a070SSahaj Chaudhari #include <unistd.h>
13*2ec5a070SSahaj Chaudhari
14*2ec5a070SSahaj Chaudhari #include "kselftest_harness.h"
15*2ec5a070SSahaj Chaudhari
16*2ec5a070SSahaj Chaudhari #define STACK_SIZE (1024 * 1024)
17*2ec5a070SSahaj Chaudhari
18*2ec5a070SSahaj Chaudhari struct pidns_init_args {
19*2ec5a070SSahaj Chaudhari int ready_read;
20*2ec5a070SSahaj Chaudhari int ready_write;
21*2ec5a070SSahaj Chaudhari int release_read;
22*2ec5a070SSahaj Chaudhari int release_write;
23*2ec5a070SSahaj Chaudhari };
24*2ec5a070SSahaj Chaudhari
pidns_init(void * data)25*2ec5a070SSahaj Chaudhari static int pidns_init(void *data)
26*2ec5a070SSahaj Chaudhari {
27*2ec5a070SSahaj Chaudhari struct pidns_init_args *args = data;
28*2ec5a070SSahaj Chaudhari char release;
29*2ec5a070SSahaj Chaudhari int error = 0;
30*2ec5a070SSahaj Chaudhari
31*2ec5a070SSahaj Chaudhari close(args->ready_read);
32*2ec5a070SSahaj Chaudhari close(args->release_write);
33*2ec5a070SSahaj Chaudhari if (unshare(CLONE_NEWPID))
34*2ec5a070SSahaj Chaudhari error = errno;
35*2ec5a070SSahaj Chaudhari if (write(args->ready_write, &error, sizeof(error)) != sizeof(error))
36*2ec5a070SSahaj Chaudhari return 1;
37*2ec5a070SSahaj Chaudhari close(args->ready_write);
38*2ec5a070SSahaj Chaudhari if (error)
39*2ec5a070SSahaj Chaudhari return 0;
40*2ec5a070SSahaj Chaudhari if (read(args->release_read, &release, sizeof(release)) != sizeof(release))
41*2ec5a070SSahaj Chaudhari return 1;
42*2ec5a070SSahaj Chaudhari close(args->release_read);
43*2ec5a070SSahaj Chaudhari return 0;
44*2ec5a070SSahaj Chaudhari }
45*2ec5a070SSahaj Chaudhari
create_unborn_pidns(void)46*2ec5a070SSahaj Chaudhari static int create_unborn_pidns(void)
47*2ec5a070SSahaj Chaudhari {
48*2ec5a070SSahaj Chaudhari struct pidns_init_args args;
49*2ec5a070SSahaj Chaudhari char path[64], release = 0;
50*2ec5a070SSahaj Chaudhari void *stack;
51*2ec5a070SSahaj Chaudhari pid_t child;
52*2ec5a070SSahaj Chaudhari int ready[2], release_pipe[2], error, status, nsfd = -1;
53*2ec5a070SSahaj Chaudhari ssize_t n;
54*2ec5a070SSahaj Chaudhari
55*2ec5a070SSahaj Chaudhari if (pipe(ready))
56*2ec5a070SSahaj Chaudhari return -1;
57*2ec5a070SSahaj Chaudhari if (pipe(release_pipe)) {
58*2ec5a070SSahaj Chaudhari error = errno;
59*2ec5a070SSahaj Chaudhari close(ready[0]);
60*2ec5a070SSahaj Chaudhari close(ready[1]);
61*2ec5a070SSahaj Chaudhari errno = error;
62*2ec5a070SSahaj Chaudhari return -1;
63*2ec5a070SSahaj Chaudhari }
64*2ec5a070SSahaj Chaudhari
65*2ec5a070SSahaj Chaudhari stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
66*2ec5a070SSahaj Chaudhari MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
67*2ec5a070SSahaj Chaudhari if (stack == MAP_FAILED) {
68*2ec5a070SSahaj Chaudhari error = errno;
69*2ec5a070SSahaj Chaudhari close(ready[0]);
70*2ec5a070SSahaj Chaudhari close(ready[1]);
71*2ec5a070SSahaj Chaudhari close(release_pipe[0]);
72*2ec5a070SSahaj Chaudhari close(release_pipe[1]);
73*2ec5a070SSahaj Chaudhari errno = error;
74*2ec5a070SSahaj Chaudhari return -1;
75*2ec5a070SSahaj Chaudhari }
76*2ec5a070SSahaj Chaudhari
77*2ec5a070SSahaj Chaudhari args = (struct pidns_init_args) {
78*2ec5a070SSahaj Chaudhari .ready_read = ready[0],
79*2ec5a070SSahaj Chaudhari .ready_write = ready[1],
80*2ec5a070SSahaj Chaudhari .release_read = release_pipe[0],
81*2ec5a070SSahaj Chaudhari .release_write = release_pipe[1],
82*2ec5a070SSahaj Chaudhari };
83*2ec5a070SSahaj Chaudhari child = clone(pidns_init, stack + STACK_SIZE, CLONE_NEWPID | SIGCHLD,
84*2ec5a070SSahaj Chaudhari &args);
85*2ec5a070SSahaj Chaudhari if (child < 0)
86*2ec5a070SSahaj Chaudhari goto err_munmap;
87*2ec5a070SSahaj Chaudhari
88*2ec5a070SSahaj Chaudhari close(ready[1]);
89*2ec5a070SSahaj Chaudhari close(release_pipe[0]);
90*2ec5a070SSahaj Chaudhari n = read(ready[0], &error, sizeof(error));
91*2ec5a070SSahaj Chaudhari if (n != sizeof(error)) {
92*2ec5a070SSahaj Chaudhari error = n < 0 ? errno : EIO;
93*2ec5a070SSahaj Chaudhari goto release_child;
94*2ec5a070SSahaj Chaudhari }
95*2ec5a070SSahaj Chaudhari if (error)
96*2ec5a070SSahaj Chaudhari goto release_child;
97*2ec5a070SSahaj Chaudhari
98*2ec5a070SSahaj Chaudhari snprintf(path, sizeof(path), "/proc/%d/ns/pid_for_children", child);
99*2ec5a070SSahaj Chaudhari nsfd = open(path, O_RDONLY | O_CLOEXEC);
100*2ec5a070SSahaj Chaudhari if (nsfd < 0) {
101*2ec5a070SSahaj Chaudhari error = errno;
102*2ec5a070SSahaj Chaudhari goto release_child;
103*2ec5a070SSahaj Chaudhari }
104*2ec5a070SSahaj Chaudhari
105*2ec5a070SSahaj Chaudhari release_child:
106*2ec5a070SSahaj Chaudhari write(release_pipe[1], &release, sizeof(release));
107*2ec5a070SSahaj Chaudhari close(release_pipe[1]);
108*2ec5a070SSahaj Chaudhari close(ready[0]);
109*2ec5a070SSahaj Chaudhari if (waitpid(child, &status, 0) != child || !WIFEXITED(status) ||
110*2ec5a070SSahaj Chaudhari WEXITSTATUS(status)) {
111*2ec5a070SSahaj Chaudhari if (!error)
112*2ec5a070SSahaj Chaudhari error = ECHILD;
113*2ec5a070SSahaj Chaudhari if (nsfd >= 0)
114*2ec5a070SSahaj Chaudhari close(nsfd);
115*2ec5a070SSahaj Chaudhari nsfd = -1;
116*2ec5a070SSahaj Chaudhari }
117*2ec5a070SSahaj Chaudhari munmap(stack, STACK_SIZE);
118*2ec5a070SSahaj Chaudhari if (error) {
119*2ec5a070SSahaj Chaudhari errno = error;
120*2ec5a070SSahaj Chaudhari return -1;
121*2ec5a070SSahaj Chaudhari }
122*2ec5a070SSahaj Chaudhari return nsfd;
123*2ec5a070SSahaj Chaudhari
124*2ec5a070SSahaj Chaudhari err_munmap:
125*2ec5a070SSahaj Chaudhari error = errno;
126*2ec5a070SSahaj Chaudhari munmap(stack, STACK_SIZE);
127*2ec5a070SSahaj Chaudhari close(ready[0]);
128*2ec5a070SSahaj Chaudhari close(ready[1]);
129*2ec5a070SSahaj Chaudhari close(release_pipe[0]);
130*2ec5a070SSahaj Chaudhari close(release_pipe[1]);
131*2ec5a070SSahaj Chaudhari errno = error;
132*2ec5a070SSahaj Chaudhari return -1;
133*2ec5a070SSahaj Chaudhari }
134*2ec5a070SSahaj Chaudhari
TEST(pidns_dead_ancestor_rejects_fork)135*2ec5a070SSahaj Chaudhari TEST(pidns_dead_ancestor_rejects_fork)
136*2ec5a070SSahaj Chaudhari {
137*2ec5a070SSahaj Chaudhari int original_fd, target_fd, fork_errno, ret;
138*2ec5a070SSahaj Chaudhari pid_t child;
139*2ec5a070SSahaj Chaudhari
140*2ec5a070SSahaj Chaudhari target_fd = create_unborn_pidns();
141*2ec5a070SSahaj Chaudhari if (target_fd < 0) {
142*2ec5a070SSahaj Chaudhari if (errno == ENOENT)
143*2ec5a070SSahaj Chaudhari SKIP(return, "PID namespace handle unavailable through procfs\n");
144*2ec5a070SSahaj Chaudhari if (errno == EPERM || errno == EACCES || errno == EINVAL)
145*2ec5a070SSahaj Chaudhari SKIP(return, "PID namespace creation requires privileges\n");
146*2ec5a070SSahaj Chaudhari ASSERT_GE(target_fd, 0);
147*2ec5a070SSahaj Chaudhari }
148*2ec5a070SSahaj Chaudhari
149*2ec5a070SSahaj Chaudhari original_fd = open("/proc/self/ns/pid_for_children", O_RDONLY | O_CLOEXEC);
150*2ec5a070SSahaj Chaudhari ASSERT_GE(original_fd, 0);
151*2ec5a070SSahaj Chaudhari ret = setns(target_fd, CLONE_NEWPID);
152*2ec5a070SSahaj Chaudhari if (ret) {
153*2ec5a070SSahaj Chaudhari if (errno == EPERM || errno == EACCES)
154*2ec5a070SSahaj Chaudhari SKIP(return, "setns into PID namespace requires privileges\n");
155*2ec5a070SSahaj Chaudhari }
156*2ec5a070SSahaj Chaudhari ASSERT_EQ(0, ret);
157*2ec5a070SSahaj Chaudhari
158*2ec5a070SSahaj Chaudhari child = fork();
159*2ec5a070SSahaj Chaudhari fork_errno = errno;
160*2ec5a070SSahaj Chaudhari if (child == 0)
161*2ec5a070SSahaj Chaudhari _exit(0);
162*2ec5a070SSahaj Chaudhari
163*2ec5a070SSahaj Chaudhari if (child > 0)
164*2ec5a070SSahaj Chaudhari ASSERT_EQ(child, waitpid(child, NULL, 0));
165*2ec5a070SSahaj Chaudhari ret = setns(original_fd, CLONE_NEWPID);
166*2ec5a070SSahaj Chaudhari close(original_fd);
167*2ec5a070SSahaj Chaudhari close(target_fd);
168*2ec5a070SSahaj Chaudhari ASSERT_EQ(0, ret);
169*2ec5a070SSahaj Chaudhari
170*2ec5a070SSahaj Chaudhari ASSERT_EQ(-1, child);
171*2ec5a070SSahaj Chaudhari ASSERT_EQ(ENOMEM, fork_errno);
172*2ec5a070SSahaj Chaudhari }
173*2ec5a070SSahaj Chaudhari
174*2ec5a070SSahaj Chaudhari TEST_HARNESS_MAIN
175