xref: /linux/tools/testing/selftests/pidfd/pidfd_setns_test.c (revision 5f85bd6aeceaecd0ff3a5ee827bf75eb6141ad55)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <limits.h>
7 #include <linux/types.h>
8 #include <sched.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <syscall.h>
14 #include <sys/prctl.h>
15 #include <sys/wait.h>
16 #include <unistd.h>
17 #include <sys/socket.h>
18 #include <sys/stat.h>
19 #include <linux/ioctl.h>
20 
21 #include "pidfd.h"
22 #include "../kselftest_harness.h"
23 
24 #ifndef PIDFS_IOCTL_MAGIC
25 #define PIDFS_IOCTL_MAGIC 0xFF
26 #endif
27 
28 #ifndef PIDFD_GET_CGROUP_NAMESPACE
29 #define PIDFD_GET_CGROUP_NAMESPACE            _IO(PIDFS_IOCTL_MAGIC, 1)
30 #endif
31 
32 #ifndef PIDFD_GET_IPC_NAMESPACE
33 #define PIDFD_GET_IPC_NAMESPACE               _IO(PIDFS_IOCTL_MAGIC, 2)
34 #endif
35 
36 #ifndef PIDFD_GET_MNT_NAMESPACE
37 #define PIDFD_GET_MNT_NAMESPACE               _IO(PIDFS_IOCTL_MAGIC, 3)
38 #endif
39 
40 #ifndef PIDFD_GET_NET_NAMESPACE
41 #define PIDFD_GET_NET_NAMESPACE               _IO(PIDFS_IOCTL_MAGIC, 4)
42 #endif
43 
44 #ifndef PIDFD_GET_PID_NAMESPACE
45 #define PIDFD_GET_PID_NAMESPACE               _IO(PIDFS_IOCTL_MAGIC, 5)
46 #endif
47 
48 #ifndef PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE
49 #define PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE  _IO(PIDFS_IOCTL_MAGIC, 6)
50 #endif
51 
52 #ifndef PIDFD_GET_TIME_NAMESPACE
53 #define PIDFD_GET_TIME_NAMESPACE              _IO(PIDFS_IOCTL_MAGIC, 7)
54 #endif
55 
56 #ifndef PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE
57 #define PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 8)
58 #endif
59 
60 #ifndef PIDFD_GET_USER_NAMESPACE
61 #define PIDFD_GET_USER_NAMESPACE              _IO(PIDFS_IOCTL_MAGIC, 9)
62 #endif
63 
64 #ifndef PIDFD_GET_UTS_NAMESPACE
65 #define PIDFD_GET_UTS_NAMESPACE               _IO(PIDFS_IOCTL_MAGIC, 10)
66 #endif
67 
68 enum {
69 	PIDFD_NS_USER,
70 	PIDFD_NS_MNT,
71 	PIDFD_NS_PID,
72 	PIDFD_NS_UTS,
73 	PIDFD_NS_IPC,
74 	PIDFD_NS_NET,
75 	PIDFD_NS_CGROUP,
76 	PIDFD_NS_PIDCLD,
77 	PIDFD_NS_TIME,
78 	PIDFD_NS_TIMECLD,
79 	PIDFD_NS_MAX
80 };
81 
82 const struct ns_info {
83 	const char *name;
84 	int flag;
85 	unsigned int pidfd_ioctl;
86 } ns_info[] = {
87 	[PIDFD_NS_USER]    = { "user",              CLONE_NEWUSER,   PIDFD_GET_USER_NAMESPACE,              },
88 	[PIDFD_NS_MNT]     = { "mnt",               CLONE_NEWNS,     PIDFD_GET_MNT_NAMESPACE,               },
89 	[PIDFD_NS_PID]     = { "pid",               CLONE_NEWPID,    PIDFD_GET_PID_NAMESPACE,               },
90 	[PIDFD_NS_UTS]     = { "uts",               CLONE_NEWUTS,    PIDFD_GET_UTS_NAMESPACE,               },
91 	[PIDFD_NS_IPC]     = { "ipc",               CLONE_NEWIPC,    PIDFD_GET_IPC_NAMESPACE,               },
92 	[PIDFD_NS_NET]     = { "net",               CLONE_NEWNET,    PIDFD_GET_NET_NAMESPACE,               },
93 	[PIDFD_NS_CGROUP]  = { "cgroup",            CLONE_NEWCGROUP, PIDFD_GET_CGROUP_NAMESPACE,            },
94 	[PIDFD_NS_TIME]	   = { "time",              CLONE_NEWTIME,   PIDFD_GET_TIME_NAMESPACE,              },
95 	[PIDFD_NS_PIDCLD]  = { "pid_for_children",  0,               PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE,  },
96 	[PIDFD_NS_TIMECLD] = { "time_for_children", 0,               PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE, },
97 };
98 
FIXTURE(current_nsset)99 FIXTURE(current_nsset)
100 {
101 	pid_t pid;
102 	int pidfd;
103 	int nsfds[PIDFD_NS_MAX];
104 	int child_pidfd_derived_nsfds[PIDFD_NS_MAX];
105 
106 	pid_t child_pid_exited;
107 	int child_pidfd_exited;
108 
109 	pid_t child_pid1;
110 	int child_pidfd1;
111 	int child_nsfds1[PIDFD_NS_MAX];
112 	int child_pidfd_derived_nsfds1[PIDFD_NS_MAX];
113 
114 	pid_t child_pid2;
115 	int child_pidfd2;
116 	int child_nsfds2[PIDFD_NS_MAX];
117 	int child_pidfd_derived_nsfds2[PIDFD_NS_MAX];
118 };
119 
switch_timens(void)120 static bool switch_timens(void)
121 {
122 	int fd, ret;
123 
124 	if (unshare(CLONE_NEWTIME))
125 		return false;
126 
127 	fd = open("/proc/self/ns/time_for_children", O_RDONLY | O_CLOEXEC);
128 	if (fd < 0)
129 		return false;
130 
131 	ret = setns(fd, CLONE_NEWTIME);
132 	close(fd);
133 	return ret == 0;
134 }
135 
FIXTURE_SETUP(current_nsset)136 FIXTURE_SETUP(current_nsset)
137 {
138 	int i, proc_fd, ret;
139 	int ipc_sockets[2];
140 	char c;
141 
142 	for (i = 0; i < PIDFD_NS_MAX; i++) {
143 		self->nsfds[i]				= -EBADF;
144 		self->child_nsfds1[i]			= -EBADF;
145 		self->child_nsfds2[i]			= -EBADF;
146 		self->child_pidfd_derived_nsfds[i]	= -EBADF;
147 		self->child_pidfd_derived_nsfds1[i]	= -EBADF;
148 		self->child_pidfd_derived_nsfds2[i]	= -EBADF;
149 	}
150 
151 	proc_fd = open("/proc/self/ns", O_DIRECTORY | O_CLOEXEC);
152 	ASSERT_GE(proc_fd, 0) {
153 		TH_LOG("%m - Failed to open /proc/self/ns");
154 	}
155 
156 	self->pid = getpid();
157 	self->pidfd = sys_pidfd_open(self->pid, 0);
158 	EXPECT_GT(self->pidfd, 0) {
159 		TH_LOG("%m - Failed to open pidfd for process %d", self->pid);
160 	}
161 
162 	for (i = 0; i < PIDFD_NS_MAX; i++) {
163 		const struct ns_info *info = &ns_info[i];
164 		self->nsfds[i] = openat(proc_fd, info->name, O_RDONLY | O_CLOEXEC);
165 		if (self->nsfds[i] < 0) {
166 			EXPECT_EQ(errno, ENOENT) {
167 				TH_LOG("%m - Failed to open %s namespace for process %d",
168 				       info->name, self->pid);
169 			}
170 		}
171 
172 		self->child_pidfd_derived_nsfds[i] = ioctl(self->pidfd, info->pidfd_ioctl, 0);
173 		if (self->child_pidfd_derived_nsfds[i] < 0) {
174 			EXPECT_EQ(errno, EOPNOTSUPP) {
175 				TH_LOG("%m - Failed to derive %s namespace from pidfd of process %d",
176 				       info->name, self->pid);
177 			}
178 		}
179 	}
180 
181 	/* Create task that exits right away. */
182 	self->child_pid_exited = create_child(&self->child_pidfd_exited, 0);
183 	EXPECT_GE(self->child_pid_exited, 0);
184 
185 	if (self->child_pid_exited == 0) {
186 		if (self->nsfds[PIDFD_NS_USER] >= 0 && unshare(CLONE_NEWUSER) < 0)
187 			_exit(EXIT_FAILURE);
188 		if (self->nsfds[PIDFD_NS_NET] >= 0 && unshare(CLONE_NEWNET) < 0)
189 			_exit(EXIT_FAILURE);
190 		_exit(EXIT_SUCCESS);
191 	}
192 
193 	ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, NULL, WEXITED | WNOWAIT), 0);
194 
195 	self->pidfd = sys_pidfd_open(self->pid, 0);
196 	EXPECT_GE(self->pidfd, 0) {
197 		TH_LOG("%m - Failed to open pidfd for process %d", self->pid);
198 	}
199 
200 	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
201 	EXPECT_EQ(ret, 0);
202 
203 	/* Create tasks that will be stopped. */
204 	if (self->nsfds[PIDFD_NS_USER] >= 0 && self->nsfds[PIDFD_NS_PID] >= 0)
205 		self->child_pid1 = create_child(&self->child_pidfd1, CLONE_NEWUSER | CLONE_NEWPID);
206 	else if (self->nsfds[PIDFD_NS_PID] >= 0)
207 		self->child_pid1 = create_child(&self->child_pidfd1, CLONE_NEWPID);
208 	else if (self->nsfds[PIDFD_NS_USER] >= 0)
209 		self->child_pid1 = create_child(&self->child_pidfd1, CLONE_NEWUSER);
210 	else
211 		self->child_pid1 = create_child(&self->child_pidfd1, 0);
212 	EXPECT_GE(self->child_pid1, 0);
213 
214 	if (self->child_pid1 == 0) {
215 		close(ipc_sockets[0]);
216 
217 		if (self->nsfds[PIDFD_NS_MNT] >= 0 && unshare(CLONE_NEWNS) < 0) {
218 			TH_LOG("%m - Failed to unshare mount namespace for process %d", self->pid);
219 			_exit(EXIT_FAILURE);
220 		}
221 		if (self->nsfds[PIDFD_NS_CGROUP] >= 0 && unshare(CLONE_NEWCGROUP) < 0) {
222 			TH_LOG("%m - Failed to unshare cgroup namespace for process %d", self->pid);
223 			_exit(EXIT_FAILURE);
224 		}
225 		if (self->nsfds[PIDFD_NS_IPC] >= 0 && unshare(CLONE_NEWIPC) < 0) {
226 			TH_LOG("%m - Failed to unshare ipc namespace for process %d", self->pid);
227 			_exit(EXIT_FAILURE);
228 		}
229 		if (self->nsfds[PIDFD_NS_UTS] >= 0 && unshare(CLONE_NEWUTS) < 0) {
230 			TH_LOG("%m - Failed to unshare uts namespace for process %d", self->pid);
231 			_exit(EXIT_FAILURE);
232 		}
233 		if (self->nsfds[PIDFD_NS_NET] >= 0 && unshare(CLONE_NEWNET) < 0) {
234 			TH_LOG("%m - Failed to unshare net namespace for process %d", self->pid);
235 			_exit(EXIT_FAILURE);
236 		}
237 		if (self->nsfds[PIDFD_NS_TIME] >= 0 && !switch_timens()) {
238 			TH_LOG("%m - Failed to unshare time namespace for process %d", self->pid);
239 			_exit(EXIT_FAILURE);
240 		}
241 
242 		if (write_nointr(ipc_sockets[1], "1", 1) < 0)
243 			_exit(EXIT_FAILURE);
244 
245 		close(ipc_sockets[1]);
246 
247 		pause();
248 		_exit(EXIT_SUCCESS);
249 	}
250 
251 	close(ipc_sockets[1]);
252 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
253 	close(ipc_sockets[0]);
254 
255 	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
256 	EXPECT_EQ(ret, 0);
257 
258 	if (self->nsfds[PIDFD_NS_USER] >= 0 && self->nsfds[PIDFD_NS_PID] >= 0)
259 		self->child_pid2 = create_child(&self->child_pidfd2, CLONE_NEWUSER | CLONE_NEWPID);
260 	else if (self->nsfds[PIDFD_NS_PID] >= 0)
261 		self->child_pid2 = create_child(&self->child_pidfd2, CLONE_NEWPID);
262 	else if (self->nsfds[PIDFD_NS_USER] >= 0)
263 		self->child_pid2 = create_child(&self->child_pidfd2, CLONE_NEWUSER);
264 	else
265 		self->child_pid2 = create_child(&self->child_pidfd2, 0);
266 	EXPECT_GE(self->child_pid2, 0);
267 
268 	if (self->child_pid2 == 0) {
269 		close(ipc_sockets[0]);
270 
271 		if (self->nsfds[PIDFD_NS_MNT] >= 0 && unshare(CLONE_NEWNS) < 0) {
272 			TH_LOG("%m - Failed to unshare mount namespace for process %d", self->pid);
273 			_exit(EXIT_FAILURE);
274 		}
275 		if (self->nsfds[PIDFD_NS_CGROUP] >= 0 && unshare(CLONE_NEWCGROUP) < 0) {
276 			TH_LOG("%m - Failed to unshare cgroup namespace for process %d", self->pid);
277 			_exit(EXIT_FAILURE);
278 		}
279 		if (self->nsfds[PIDFD_NS_IPC] >= 0 && unshare(CLONE_NEWIPC) < 0) {
280 			TH_LOG("%m - Failed to unshare ipc namespace for process %d", self->pid);
281 			_exit(EXIT_FAILURE);
282 		}
283 		if (self->nsfds[PIDFD_NS_UTS] >= 0 && unshare(CLONE_NEWUTS) < 0) {
284 			TH_LOG("%m - Failed to unshare uts namespace for process %d", self->pid);
285 			_exit(EXIT_FAILURE);
286 		}
287 		if (self->nsfds[PIDFD_NS_NET] >= 0 && unshare(CLONE_NEWNET) < 0) {
288 			TH_LOG("%m - Failed to unshare net namespace for process %d", self->pid);
289 			_exit(EXIT_FAILURE);
290 		}
291 		if (self->nsfds[PIDFD_NS_TIME] >= 0 && !switch_timens()) {
292 			TH_LOG("%m - Failed to unshare time namespace for process %d", self->pid);
293 			_exit(EXIT_FAILURE);
294 		}
295 
296 		if (write_nointr(ipc_sockets[1], "1", 1) < 0)
297 			_exit(EXIT_FAILURE);
298 
299 		close(ipc_sockets[1]);
300 
301 		pause();
302 		_exit(EXIT_SUCCESS);
303 	}
304 
305 	close(ipc_sockets[1]);
306 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
307 	close(ipc_sockets[0]);
308 
309 	for (i = 0; i < PIDFD_NS_MAX; i++) {
310 		char p[100];
311 
312 		const struct ns_info *info = &ns_info[i];
313 
314 		self->nsfds[i] = openat(proc_fd, info->name, O_RDONLY | O_CLOEXEC);
315 		if (self->nsfds[i] < 0) {
316 			EXPECT_EQ(errno, ENOENT) {
317 				TH_LOG("%m - Failed to open %s namespace for process %d",
318 				       info->name, self->pid);
319 			}
320 		}
321 
322 		ret = snprintf(p, sizeof(p), "/proc/%d/ns/%s",
323 			       self->child_pid1, info->name);
324 		EXPECT_GT(ret, 0);
325 		EXPECT_LT(ret, sizeof(p));
326 
327 		self->child_nsfds1[i] = open(p, O_RDONLY | O_CLOEXEC);
328 		if (self->child_nsfds1[i] < 0) {
329 			EXPECT_EQ(errno, ENOENT) {
330 				TH_LOG("%m - Failed to open %s namespace for process %d",
331 				       info->name, self->child_pid1);
332 			}
333 		}
334 
335 		ret = snprintf(p, sizeof(p), "/proc/%d/ns/%s",
336 			       self->child_pid2, info->name);
337 		EXPECT_GT(ret, 0);
338 		EXPECT_LT(ret, sizeof(p));
339 
340 		self->child_nsfds2[i] = open(p, O_RDONLY | O_CLOEXEC);
341 		if (self->child_nsfds2[i] < 0) {
342 			EXPECT_EQ(errno, ENOENT) {
343 				TH_LOG("%m - Failed to open %s namespace for process %d",
344 				       info->name, self->child_pid1);
345 			}
346 		}
347 
348 		self->child_pidfd_derived_nsfds1[i] = ioctl(self->child_pidfd1, info->pidfd_ioctl, 0);
349 		if (self->child_pidfd_derived_nsfds1[i] < 0) {
350 			EXPECT_EQ(errno, EOPNOTSUPP) {
351 				TH_LOG("%m - Failed to derive %s namespace from pidfd of process %d",
352 				       info->name, self->child_pid1);
353 			}
354 		}
355 
356 		self->child_pidfd_derived_nsfds2[i] = ioctl(self->child_pidfd2, info->pidfd_ioctl, 0);
357 		if (self->child_pidfd_derived_nsfds2[i] < 0) {
358 			EXPECT_EQ(errno, EOPNOTSUPP) {
359 				TH_LOG("%m - Failed to derive %s namespace from pidfd of process %d",
360 				       info->name, self->child_pid2);
361 			}
362 		}
363 	}
364 
365 	close(proc_fd);
366 }
367 
FIXTURE_TEARDOWN(current_nsset)368 FIXTURE_TEARDOWN(current_nsset)
369 {
370 	int i;
371 
372 	ASSERT_EQ(sys_pidfd_send_signal(self->child_pidfd1,
373 					SIGKILL, NULL, 0), 0);
374 	ASSERT_EQ(sys_pidfd_send_signal(self->child_pidfd2,
375 					SIGKILL, NULL, 0), 0);
376 
377 	for (i = 0; i < PIDFD_NS_MAX; i++) {
378 		if (self->nsfds[i] >= 0)
379 			close(self->nsfds[i]);
380 		if (self->child_nsfds1[i] >= 0)
381 			close(self->child_nsfds1[i]);
382 		if (self->child_nsfds2[i] >= 0)
383 			close(self->child_nsfds2[i]);
384 		if (self->child_pidfd_derived_nsfds[i] >= 0)
385 			close(self->child_pidfd_derived_nsfds[i]);
386 		if (self->child_pidfd_derived_nsfds1[i] >= 0)
387 			close(self->child_pidfd_derived_nsfds1[i]);
388 		if (self->child_pidfd_derived_nsfds2[i] >= 0)
389 			close(self->child_pidfd_derived_nsfds2[i]);
390 	}
391 
392 	if (self->child_pidfd1 >= 0)
393 		EXPECT_EQ(0, close(self->child_pidfd1));
394 	if (self->child_pidfd2 >= 0)
395 		EXPECT_EQ(0, close(self->child_pidfd2));
396 	ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, NULL, WEXITED), 0);
397 	ASSERT_EQ(sys_waitid(P_PID, self->child_pid1, NULL, WEXITED), 0);
398 	ASSERT_EQ(sys_waitid(P_PID, self->child_pid2, NULL, WEXITED), 0);
399 }
400 
preserve_ns(const int pid,const char * ns)401 static int preserve_ns(const int pid, const char *ns)
402 {
403 	int ret;
404 	char path[50];
405 
406 	ret = snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns);
407 	if (ret < 0 || (size_t)ret >= sizeof(path))
408 		return -EIO;
409 
410 	return open(path, O_RDONLY | O_CLOEXEC);
411 }
412 
in_same_namespace(int ns_fd1,pid_t pid2,const char * ns)413 static int in_same_namespace(int ns_fd1, pid_t pid2, const char *ns)
414 {
415 	int ns_fd2 = -EBADF;
416 	int ret = -1;
417 	struct stat ns_st1, ns_st2;
418 
419 	ret = fstat(ns_fd1, &ns_st1);
420 	if (ret < 0)
421 		return -1;
422 
423 	ns_fd2 = preserve_ns(pid2, ns);
424 	if (ns_fd2 < 0)
425 		return -1;
426 
427 	ret = fstat(ns_fd2, &ns_st2);
428 	close(ns_fd2);
429 	if (ret < 0)
430 		return -1;
431 
432 	/* processes are in the same namespace */
433 	if ((ns_st1.st_dev == ns_st2.st_dev) &&
434 	    (ns_st1.st_ino == ns_st2.st_ino))
435 		return 1;
436 
437 	/* processes are in different namespaces */
438 	return 0;
439 }
440 
441 /* Test that we can't pass garbage to the kernel. */
TEST_F(current_nsset,invalid_flags)442 TEST_F(current_nsset, invalid_flags)
443 {
444 	ASSERT_NE(setns(self->pidfd, 0), 0);
445 	EXPECT_EQ(errno, EINVAL);
446 
447 	ASSERT_NE(setns(self->pidfd, -1), 0);
448 	EXPECT_EQ(errno, EINVAL);
449 
450 	ASSERT_NE(setns(self->pidfd, CLONE_VM), 0);
451 	EXPECT_EQ(errno, EINVAL);
452 
453 	ASSERT_NE(setns(self->pidfd, CLONE_NEWUSER | CLONE_VM), 0);
454 	EXPECT_EQ(errno, EINVAL);
455 }
456 
457 /* Test that we can't attach to a task that has already exited. */
TEST_F(current_nsset,pidfd_exited_child)458 TEST_F(current_nsset, pidfd_exited_child)
459 {
460 	int i;
461 	pid_t pid;
462 
463 	ASSERT_NE(setns(self->child_pidfd_exited, CLONE_NEWUSER | CLONE_NEWNET),
464 		  0);
465 	EXPECT_EQ(errno, ESRCH);
466 
467 	pid = getpid();
468 	for (i = 0; i < PIDFD_NS_MAX; i++) {
469 		const struct ns_info *info = &ns_info[i];
470 		/* Verify that we haven't changed any namespaces. */
471 		if (self->nsfds[i] >= 0)
472 			ASSERT_EQ(in_same_namespace(self->nsfds[i], pid, info->name), 1);
473 	}
474 }
475 
TEST_F(current_nsset,pidfd_incremental_setns)476 TEST_F(current_nsset, pidfd_incremental_setns)
477 {
478 	int i;
479 	pid_t pid;
480 
481 	pid = getpid();
482 	for (i = 0; i < PIDFD_NS_MAX; i++) {
483 		const struct ns_info *info = &ns_info[i];
484 		int nsfd;
485 
486 		if (self->child_nsfds1[i] < 0)
487 			continue;
488 
489 		if (info->flag) {
490 			ASSERT_EQ(setns(self->child_pidfd1, info->flag), 0) {
491 				TH_LOG("%m - Failed to setns to %s namespace of %d via pidfd %d",
492 				       info->name, self->child_pid1,
493 				       self->child_pidfd1);
494 			}
495 		}
496 
497 		/* Verify that we have changed to the correct namespaces. */
498 		if (info->flag == CLONE_NEWPID)
499 			nsfd = self->nsfds[i];
500 		else
501 			nsfd = self->child_nsfds1[i];
502 		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
503 			TH_LOG("setns failed to place us correctly into %s namespace of %d via pidfd %d",
504 			       info->name, self->child_pid1,
505 			       self->child_pidfd1);
506 		}
507 		TH_LOG("Managed to correctly setns to %s namespace of %d via pidfd %d",
508 		       info->name, self->child_pid1, self->child_pidfd1);
509 	}
510 }
511 
TEST_F(current_nsset,nsfd_incremental_setns)512 TEST_F(current_nsset, nsfd_incremental_setns)
513 {
514 	int i;
515 	pid_t pid;
516 
517 	pid = getpid();
518 	for (i = 0; i < PIDFD_NS_MAX; i++) {
519 		const struct ns_info *info = &ns_info[i];
520 		int nsfd;
521 
522 		if (self->child_nsfds1[i] < 0)
523 			continue;
524 
525 		if (info->flag) {
526 			ASSERT_EQ(setns(self->child_nsfds1[i], info->flag), 0) {
527 				TH_LOG("%m - Failed to setns to %s namespace of %d via nsfd %d",
528 				       info->name, self->child_pid1,
529 				       self->child_nsfds1[i]);
530 			}
531 		}
532 
533 		/* Verify that we have changed to the correct namespaces. */
534 		if (info->flag == CLONE_NEWPID)
535 			nsfd = self->nsfds[i];
536 		else
537 			nsfd = self->child_nsfds1[i];
538 		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
539 			TH_LOG("setns failed to place us correctly into %s namespace of %d via nsfd %d",
540 			       info->name, self->child_pid1,
541 			       self->child_nsfds1[i]);
542 		}
543 		TH_LOG("Managed to correctly setns to %s namespace of %d via nsfd %d",
544 		       info->name, self->child_pid1, self->child_nsfds1[i]);
545 	}
546 }
547 
TEST_F(current_nsset,pidfd_derived_nsfd_incremental_setns)548 TEST_F(current_nsset, pidfd_derived_nsfd_incremental_setns)
549 {
550 	int i;
551 	pid_t pid;
552 
553 	pid = getpid();
554 	for (i = 0; i < PIDFD_NS_MAX; i++) {
555 		const struct ns_info *info = &ns_info[i];
556 		int nsfd;
557 
558 		if (self->child_pidfd_derived_nsfds1[i] < 0)
559 			continue;
560 
561 		if (info->flag) {
562 			ASSERT_EQ(setns(self->child_pidfd_derived_nsfds1[i], info->flag), 0) {
563 				TH_LOG("%m - Failed to setns to %s namespace of %d via nsfd %d",
564 				       info->name, self->child_pid1,
565 				       self->child_pidfd_derived_nsfds1[i]);
566 			}
567 		}
568 
569 		/* Verify that we have changed to the correct namespaces. */
570 		if (info->flag == CLONE_NEWPID)
571 			nsfd = self->child_pidfd_derived_nsfds[i];
572 		else
573 			nsfd = self->child_pidfd_derived_nsfds1[i];
574 		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
575 			TH_LOG("setns failed to place us correctly into %s namespace of %d via nsfd %d",
576 			       info->name, self->child_pid1,
577 			       self->child_pidfd_derived_nsfds1[i]);
578 		}
579 		TH_LOG("Managed to correctly setns to %s namespace of %d via nsfd %d",
580 		       info->name, self->child_pid1, self->child_pidfd_derived_nsfds1[i]);
581 	}
582 }
583 
TEST_F(current_nsset,pidfd_one_shot_setns)584 TEST_F(current_nsset, pidfd_one_shot_setns)
585 {
586 	unsigned flags = 0;
587 	int i;
588 	pid_t pid;
589 
590 	for (i = 0; i < PIDFD_NS_MAX; i++) {
591 		const struct ns_info *info = &ns_info[i];
592 
593 		if (self->child_nsfds1[i] < 0)
594 			continue;
595 
596 		flags |= info->flag;
597 		TH_LOG("Adding %s namespace of %d to list of namespaces to attach to",
598 		       info->name, self->child_pid1);
599 	}
600 
601 	ASSERT_EQ(setns(self->child_pidfd1, flags), 0) {
602 		TH_LOG("%m - Failed to setns to namespaces of %d",
603 		       self->child_pid1);
604 	}
605 
606 	pid = getpid();
607 	for (i = 0; i < PIDFD_NS_MAX; i++) {
608 		const struct ns_info *info = &ns_info[i];
609 		int nsfd;
610 
611 		if (self->child_nsfds1[i] < 0)
612 			continue;
613 
614 		/* Verify that we have changed to the correct namespaces. */
615 		if (info->flag == CLONE_NEWPID)
616 			nsfd = self->nsfds[i];
617 		else
618 			nsfd = self->child_nsfds1[i];
619 		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
620 			TH_LOG("setns failed to place us correctly into %s namespace of %d",
621 			       info->name, self->child_pid1);
622 		}
623 		TH_LOG("Managed to correctly setns to %s namespace of %d",
624 		       info->name, self->child_pid1);
625 	}
626 }
627 
TEST_F(current_nsset,no_foul_play)628 TEST_F(current_nsset, no_foul_play)
629 {
630 	unsigned flags = 0;
631 	int i;
632 
633 	for (i = 0; i < PIDFD_NS_MAX; i++) {
634 		const struct ns_info *info = &ns_info[i];
635 
636 		if (self->child_nsfds1[i] < 0)
637 			continue;
638 
639 		flags |= info->flag;
640 		if (info->flag) /* No use logging pid_for_children. */
641 			TH_LOG("Adding %s namespace of %d to list of namespaces to attach to",
642 			       info->name, self->child_pid1);
643 	}
644 
645 	ASSERT_EQ(setns(self->child_pidfd1, flags), 0) {
646 		TH_LOG("%m - Failed to setns to namespaces of %d vid pidfd %d",
647 		       self->child_pid1, self->child_pidfd1);
648 	}
649 
650 	/*
651 	 * Can't setns to a user namespace outside of our hierarchy since we
652 	 * don't have caps in there and didn't create it. That means that under
653 	 * no circumstances should we be able to setns to any of the other
654 	 * ones since they aren't owned by our user namespace.
655 	 */
656 	for (i = 0; i < PIDFD_NS_MAX; i++) {
657 		const struct ns_info *info = &ns_info[i];
658 
659 		if (self->child_nsfds2[i] < 0 || !info->flag)
660 			continue;
661 
662 		ASSERT_NE(setns(self->child_pidfd2, info->flag), 0) {
663 			TH_LOG("Managed to setns to %s namespace of %d via pidfd %d",
664 			       info->name, self->child_pid2,
665 			       self->child_pidfd2);
666 		}
667 		TH_LOG("%m - Correctly failed to setns to %s namespace of %d via pidfd %d",
668 		       info->name, self->child_pid2,
669 		       self->child_pidfd2);
670 
671 		ASSERT_NE(setns(self->child_nsfds2[i], info->flag), 0) {
672 			TH_LOG("Managed to setns to %s namespace of %d via nsfd %d",
673 			       info->name, self->child_pid2,
674 			       self->child_nsfds2[i]);
675 		}
676 		TH_LOG("%m - Correctly failed to setns to %s namespace of %d via nsfd %d",
677 		       info->name, self->child_pid2,
678 		       self->child_nsfds2[i]);
679 	}
680 
681 	/*
682 	 * Can't setns to a user namespace outside of our hierarchy since we
683 	 * don't have caps in there and didn't create it. That means that under
684 	 * no circumstances should we be able to setns to any of the other
685 	 * ones since they aren't owned by our user namespace.
686 	 */
687 	for (i = 0; i < PIDFD_NS_MAX; i++) {
688 		const struct ns_info *info = &ns_info[i];
689 
690 		if (self->child_pidfd_derived_nsfds2[i] < 0 || !info->flag)
691 			continue;
692 
693 		ASSERT_NE(setns(self->child_pidfd_derived_nsfds2[i], info->flag), 0) {
694 			TH_LOG("Managed to setns to %s namespace of %d via nsfd %d",
695 			       info->name, self->child_pid2,
696 			       self->child_pidfd_derived_nsfds2[i]);
697 		}
698 		TH_LOG("%m - Correctly failed to setns to %s namespace of %d via nsfd %d",
699 		       info->name, self->child_pid2,
700 		       self->child_pidfd_derived_nsfds2[i]);
701 	}
702 }
703 
TEST(setns_einval)704 TEST(setns_einval)
705 {
706 	int fd;
707 
708 	fd = sys_memfd_create("rostock", 0);
709 	EXPECT_GT(fd, 0);
710 
711 	ASSERT_NE(setns(fd, 0), 0);
712 	EXPECT_EQ(errno, EINVAL);
713 	close(fd);
714 }
715 
716 TEST_HARNESS_MAIN
717