xref: /linux/tools/testing/selftests/pid_namespace/pidns_dead_ancestor.c (revision 018cf9bf786d501a27963dca6777f169f978e2a5)
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