xref: /linux/tools/testing/selftests/pid_namespace/pidns_init_via_setns.c (revision 5c0f43e8535d619ff32400e2e916075109fc7a56)
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