xref: /linux/tools/testing/selftests/namespaces/nsid_test.c (revision 18b19abc3709b109676ffd1f48dcd332c2e477d4)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <assert.h>
4 #include <fcntl.h>
5 #include <inttypes.h>
6 #include <libgen.h>
7 #include <limits.h>
8 #include <pthread.h>
9 #include <string.h>
10 #include <sys/mount.h>
11 #include <poll.h>
12 #include <sys/epoll.h>
13 #include <sys/resource.h>
14 #include <sys/stat.h>
15 #include <sys/socket.h>
16 #include <sys/un.h>
17 #include <unistd.h>
18 #include <linux/fs.h>
19 #include <linux/limits.h>
20 #include <linux/nsfs.h>
21 #include "../kselftest_harness.h"
22 
TEST(nsid_mntns_basic)23 TEST(nsid_mntns_basic)
24 {
25 	__u64 mnt_ns_id = 0;
26 	int fd_mntns;
27 	int ret;
28 
29 	/* Open the current mount namespace */
30 	fd_mntns = open("/proc/self/ns/mnt", O_RDONLY);
31 	ASSERT_GE(fd_mntns, 0);
32 
33 	/* Get the mount namespace ID */
34 	ret = ioctl(fd_mntns, NS_GET_MNTNS_ID, &mnt_ns_id);
35 	ASSERT_EQ(ret, 0);
36 	ASSERT_NE(mnt_ns_id, 0);
37 
38 	/* Verify we can get the same ID again */
39 	__u64 mnt_ns_id2 = 0;
40 	ret = ioctl(fd_mntns, NS_GET_ID, &mnt_ns_id2);
41 	ASSERT_EQ(ret, 0);
42 	ASSERT_EQ(mnt_ns_id, mnt_ns_id2);
43 
44 	close(fd_mntns);
45 }
46 
TEST(nsid_mntns_separate)47 TEST(nsid_mntns_separate)
48 {
49 	__u64 parent_mnt_ns_id = 0;
50 	__u64 child_mnt_ns_id = 0;
51 	int fd_parent_mntns, fd_child_mntns;
52 	int ret;
53 	pid_t pid;
54 	int pipefd[2];
55 
56 	/* Get parent's mount namespace ID */
57 	fd_parent_mntns = open("/proc/self/ns/mnt", O_RDONLY);
58 	ASSERT_GE(fd_parent_mntns, 0);
59 	ret = ioctl(fd_parent_mntns, NS_GET_ID, &parent_mnt_ns_id);
60 	ASSERT_EQ(ret, 0);
61 	ASSERT_NE(parent_mnt_ns_id, 0);
62 
63 	/* Create a pipe for synchronization */
64 	ASSERT_EQ(pipe(pipefd), 0);
65 
66 	pid = fork();
67 	ASSERT_GE(pid, 0);
68 
69 	if (pid == 0) {
70 		/* Child process */
71 		close(pipefd[0]);
72 
73 		/* Create new mount namespace */
74 		ret = unshare(CLONE_NEWNS);
75 		if (ret != 0) {
76 			/* Skip test if we don't have permission */
77 			if (errno == EPERM || errno == EACCES) {
78 				write(pipefd[1], "S", 1); /* Signal skip */
79 				_exit(0);
80 			}
81 			_exit(1);
82 		}
83 
84 		/* Signal success */
85 		write(pipefd[1], "Y", 1);
86 		close(pipefd[1]);
87 
88 		/* Keep namespace alive */
89 		pause();
90 		_exit(0);
91 	}
92 
93 	/* Parent process */
94 	close(pipefd[1]);
95 
96 	char buf;
97 	ASSERT_EQ(read(pipefd[0], &buf, 1), 1);
98 	close(pipefd[0]);
99 
100 	if (buf == 'S') {
101 		/* Child couldn't create namespace, skip test */
102 		kill(pid, SIGTERM);
103 		waitpid(pid, NULL, 0);
104 		close(fd_parent_mntns);
105 		SKIP(return, "No permission to create mount namespace");
106 	}
107 
108 	ASSERT_EQ(buf, 'Y');
109 
110 	/* Open child's mount namespace */
111 	char path[256];
112 	snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
113 	fd_child_mntns = open(path, O_RDONLY);
114 	ASSERT_GE(fd_child_mntns, 0);
115 
116 	/* Get child's mount namespace ID */
117 	ret = ioctl(fd_child_mntns, NS_GET_ID, &child_mnt_ns_id);
118 	ASSERT_EQ(ret, 0);
119 	ASSERT_NE(child_mnt_ns_id, 0);
120 
121 	/* Parent and child should have different mount namespace IDs */
122 	ASSERT_NE(parent_mnt_ns_id, child_mnt_ns_id);
123 
124 	close(fd_parent_mntns);
125 	close(fd_child_mntns);
126 
127 	/* Clean up child process */
128 	kill(pid, SIGTERM);
129 	waitpid(pid, NULL, 0);
130 }
131 
TEST(nsid_cgroupns_basic)132 TEST(nsid_cgroupns_basic)
133 {
134 	__u64 cgroup_ns_id = 0;
135 	int fd_cgroupns;
136 	int ret;
137 
138 	/* Open the current cgroup namespace */
139 	fd_cgroupns = open("/proc/self/ns/cgroup", O_RDONLY);
140 	ASSERT_GE(fd_cgroupns, 0);
141 
142 	/* Get the cgroup namespace ID */
143 	ret = ioctl(fd_cgroupns, NS_GET_ID, &cgroup_ns_id);
144 	ASSERT_EQ(ret, 0);
145 	ASSERT_NE(cgroup_ns_id, 0);
146 
147 	/* Verify we can get the same ID again */
148 	__u64 cgroup_ns_id2 = 0;
149 	ret = ioctl(fd_cgroupns, NS_GET_ID, &cgroup_ns_id2);
150 	ASSERT_EQ(ret, 0);
151 	ASSERT_EQ(cgroup_ns_id, cgroup_ns_id2);
152 
153 	close(fd_cgroupns);
154 }
155 
TEST(nsid_cgroupns_separate)156 TEST(nsid_cgroupns_separate)
157 {
158 	__u64 parent_cgroup_ns_id = 0;
159 	__u64 child_cgroup_ns_id = 0;
160 	int fd_parent_cgroupns, fd_child_cgroupns;
161 	int ret;
162 	pid_t pid;
163 	int pipefd[2];
164 
165 	/* Get parent's cgroup namespace ID */
166 	fd_parent_cgroupns = open("/proc/self/ns/cgroup", O_RDONLY);
167 	ASSERT_GE(fd_parent_cgroupns, 0);
168 	ret = ioctl(fd_parent_cgroupns, NS_GET_ID, &parent_cgroup_ns_id);
169 	ASSERT_EQ(ret, 0);
170 	ASSERT_NE(parent_cgroup_ns_id, 0);
171 
172 	/* Create a pipe for synchronization */
173 	ASSERT_EQ(pipe(pipefd), 0);
174 
175 	pid = fork();
176 	ASSERT_GE(pid, 0);
177 
178 	if (pid == 0) {
179 		/* Child process */
180 		close(pipefd[0]);
181 
182 		/* Create new cgroup namespace */
183 		ret = unshare(CLONE_NEWCGROUP);
184 		if (ret != 0) {
185 			/* Skip test if we don't have permission */
186 			if (errno == EPERM || errno == EACCES) {
187 				write(pipefd[1], "S", 1); /* Signal skip */
188 				_exit(0);
189 			}
190 			_exit(1);
191 		}
192 
193 		/* Signal success */
194 		write(pipefd[1], "Y", 1);
195 		close(pipefd[1]);
196 
197 		/* Keep namespace alive */
198 		pause();
199 		_exit(0);
200 	}
201 
202 	/* Parent process */
203 	close(pipefd[1]);
204 
205 	char buf;
206 	ASSERT_EQ(read(pipefd[0], &buf, 1), 1);
207 	close(pipefd[0]);
208 
209 	if (buf == 'S') {
210 		/* Child couldn't create namespace, skip test */
211 		kill(pid, SIGTERM);
212 		waitpid(pid, NULL, 0);
213 		close(fd_parent_cgroupns);
214 		SKIP(return, "No permission to create cgroup namespace");
215 	}
216 
217 	ASSERT_EQ(buf, 'Y');
218 
219 	/* Open child's cgroup namespace */
220 	char path[256];
221 	snprintf(path, sizeof(path), "/proc/%d/ns/cgroup", pid);
222 	fd_child_cgroupns = open(path, O_RDONLY);
223 	ASSERT_GE(fd_child_cgroupns, 0);
224 
225 	/* Get child's cgroup namespace ID */
226 	ret = ioctl(fd_child_cgroupns, NS_GET_ID, &child_cgroup_ns_id);
227 	ASSERT_EQ(ret, 0);
228 	ASSERT_NE(child_cgroup_ns_id, 0);
229 
230 	/* Parent and child should have different cgroup namespace IDs */
231 	ASSERT_NE(parent_cgroup_ns_id, child_cgroup_ns_id);
232 
233 	close(fd_parent_cgroupns);
234 	close(fd_child_cgroupns);
235 
236 	/* Clean up child process */
237 	kill(pid, SIGTERM);
238 	waitpid(pid, NULL, 0);
239 }
240 
TEST(nsid_ipcns_basic)241 TEST(nsid_ipcns_basic)
242 {
243 	__u64 ipc_ns_id = 0;
244 	int fd_ipcns;
245 	int ret;
246 
247 	/* Open the current IPC namespace */
248 	fd_ipcns = open("/proc/self/ns/ipc", O_RDONLY);
249 	ASSERT_GE(fd_ipcns, 0);
250 
251 	/* Get the IPC namespace ID */
252 	ret = ioctl(fd_ipcns, NS_GET_ID, &ipc_ns_id);
253 	ASSERT_EQ(ret, 0);
254 	ASSERT_NE(ipc_ns_id, 0);
255 
256 	/* Verify we can get the same ID again */
257 	__u64 ipc_ns_id2 = 0;
258 	ret = ioctl(fd_ipcns, NS_GET_ID, &ipc_ns_id2);
259 	ASSERT_EQ(ret, 0);
260 	ASSERT_EQ(ipc_ns_id, ipc_ns_id2);
261 
262 	close(fd_ipcns);
263 }
264 
TEST(nsid_ipcns_separate)265 TEST(nsid_ipcns_separate)
266 {
267 	__u64 parent_ipc_ns_id = 0;
268 	__u64 child_ipc_ns_id = 0;
269 	int fd_parent_ipcns, fd_child_ipcns;
270 	int ret;
271 	pid_t pid;
272 	int pipefd[2];
273 
274 	/* Get parent's IPC namespace ID */
275 	fd_parent_ipcns = open("/proc/self/ns/ipc", O_RDONLY);
276 	ASSERT_GE(fd_parent_ipcns, 0);
277 	ret = ioctl(fd_parent_ipcns, NS_GET_ID, &parent_ipc_ns_id);
278 	ASSERT_EQ(ret, 0);
279 	ASSERT_NE(parent_ipc_ns_id, 0);
280 
281 	/* Create a pipe for synchronization */
282 	ASSERT_EQ(pipe(pipefd), 0);
283 
284 	pid = fork();
285 	ASSERT_GE(pid, 0);
286 
287 	if (pid == 0) {
288 		/* Child process */
289 		close(pipefd[0]);
290 
291 		/* Create new IPC namespace */
292 		ret = unshare(CLONE_NEWIPC);
293 		if (ret != 0) {
294 			/* Skip test if we don't have permission */
295 			if (errno == EPERM || errno == EACCES) {
296 				write(pipefd[1], "S", 1); /* Signal skip */
297 				_exit(0);
298 			}
299 			_exit(1);
300 		}
301 
302 		/* Signal success */
303 		write(pipefd[1], "Y", 1);
304 		close(pipefd[1]);
305 
306 		/* Keep namespace alive */
307 		pause();
308 		_exit(0);
309 	}
310 
311 	/* Parent process */
312 	close(pipefd[1]);
313 
314 	char buf;
315 	ASSERT_EQ(read(pipefd[0], &buf, 1), 1);
316 	close(pipefd[0]);
317 
318 	if (buf == 'S') {
319 		/* Child couldn't create namespace, skip test */
320 		kill(pid, SIGTERM);
321 		waitpid(pid, NULL, 0);
322 		close(fd_parent_ipcns);
323 		SKIP(return, "No permission to create IPC namespace");
324 	}
325 
326 	ASSERT_EQ(buf, 'Y');
327 
328 	/* Open child's IPC namespace */
329 	char path[256];
330 	snprintf(path, sizeof(path), "/proc/%d/ns/ipc", pid);
331 	fd_child_ipcns = open(path, O_RDONLY);
332 	ASSERT_GE(fd_child_ipcns, 0);
333 
334 	/* Get child's IPC namespace ID */
335 	ret = ioctl(fd_child_ipcns, NS_GET_ID, &child_ipc_ns_id);
336 	ASSERT_EQ(ret, 0);
337 	ASSERT_NE(child_ipc_ns_id, 0);
338 
339 	/* Parent and child should have different IPC namespace IDs */
340 	ASSERT_NE(parent_ipc_ns_id, child_ipc_ns_id);
341 
342 	close(fd_parent_ipcns);
343 	close(fd_child_ipcns);
344 
345 	/* Clean up child process */
346 	kill(pid, SIGTERM);
347 	waitpid(pid, NULL, 0);
348 }
349 
TEST(nsid_utsns_basic)350 TEST(nsid_utsns_basic)
351 {
352 	__u64 uts_ns_id = 0;
353 	int fd_utsns;
354 	int ret;
355 
356 	/* Open the current UTS namespace */
357 	fd_utsns = open("/proc/self/ns/uts", O_RDONLY);
358 	ASSERT_GE(fd_utsns, 0);
359 
360 	/* Get the UTS namespace ID */
361 	ret = ioctl(fd_utsns, NS_GET_ID, &uts_ns_id);
362 	ASSERT_EQ(ret, 0);
363 	ASSERT_NE(uts_ns_id, 0);
364 
365 	/* Verify we can get the same ID again */
366 	__u64 uts_ns_id2 = 0;
367 	ret = ioctl(fd_utsns, NS_GET_ID, &uts_ns_id2);
368 	ASSERT_EQ(ret, 0);
369 	ASSERT_EQ(uts_ns_id, uts_ns_id2);
370 
371 	close(fd_utsns);
372 }
373 
TEST(nsid_utsns_separate)374 TEST(nsid_utsns_separate)
375 {
376 	__u64 parent_uts_ns_id = 0;
377 	__u64 child_uts_ns_id = 0;
378 	int fd_parent_utsns, fd_child_utsns;
379 	int ret;
380 	pid_t pid;
381 	int pipefd[2];
382 
383 	/* Get parent's UTS namespace ID */
384 	fd_parent_utsns = open("/proc/self/ns/uts", O_RDONLY);
385 	ASSERT_GE(fd_parent_utsns, 0);
386 	ret = ioctl(fd_parent_utsns, NS_GET_ID, &parent_uts_ns_id);
387 	ASSERT_EQ(ret, 0);
388 	ASSERT_NE(parent_uts_ns_id, 0);
389 
390 	/* Create a pipe for synchronization */
391 	ASSERT_EQ(pipe(pipefd), 0);
392 
393 	pid = fork();
394 	ASSERT_GE(pid, 0);
395 
396 	if (pid == 0) {
397 		/* Child process */
398 		close(pipefd[0]);
399 
400 		/* Create new UTS namespace */
401 		ret = unshare(CLONE_NEWUTS);
402 		if (ret != 0) {
403 			/* Skip test if we don't have permission */
404 			if (errno == EPERM || errno == EACCES) {
405 				write(pipefd[1], "S", 1); /* Signal skip */
406 				_exit(0);
407 			}
408 			_exit(1);
409 		}
410 
411 		/* Signal success */
412 		write(pipefd[1], "Y", 1);
413 		close(pipefd[1]);
414 
415 		/* Keep namespace alive */
416 		pause();
417 		_exit(0);
418 	}
419 
420 	/* Parent process */
421 	close(pipefd[1]);
422 
423 	char buf;
424 	ASSERT_EQ(read(pipefd[0], &buf, 1), 1);
425 	close(pipefd[0]);
426 
427 	if (buf == 'S') {
428 		/* Child couldn't create namespace, skip test */
429 		kill(pid, SIGTERM);
430 		waitpid(pid, NULL, 0);
431 		close(fd_parent_utsns);
432 		SKIP(return, "No permission to create UTS namespace");
433 	}
434 
435 	ASSERT_EQ(buf, 'Y');
436 
437 	/* Open child's UTS namespace */
438 	char path[256];
439 	snprintf(path, sizeof(path), "/proc/%d/ns/uts", pid);
440 	fd_child_utsns = open(path, O_RDONLY);
441 	ASSERT_GE(fd_child_utsns, 0);
442 
443 	/* Get child's UTS namespace ID */
444 	ret = ioctl(fd_child_utsns, NS_GET_ID, &child_uts_ns_id);
445 	ASSERT_EQ(ret, 0);
446 	ASSERT_NE(child_uts_ns_id, 0);
447 
448 	/* Parent and child should have different UTS namespace IDs */
449 	ASSERT_NE(parent_uts_ns_id, child_uts_ns_id);
450 
451 	close(fd_parent_utsns);
452 	close(fd_child_utsns);
453 
454 	/* Clean up child process */
455 	kill(pid, SIGTERM);
456 	waitpid(pid, NULL, 0);
457 }
458 
TEST(nsid_userns_basic)459 TEST(nsid_userns_basic)
460 {
461 	__u64 user_ns_id = 0;
462 	int fd_userns;
463 	int ret;
464 
465 	/* Open the current user namespace */
466 	fd_userns = open("/proc/self/ns/user", O_RDONLY);
467 	ASSERT_GE(fd_userns, 0);
468 
469 	/* Get the user namespace ID */
470 	ret = ioctl(fd_userns, NS_GET_ID, &user_ns_id);
471 	ASSERT_EQ(ret, 0);
472 	ASSERT_NE(user_ns_id, 0);
473 
474 	/* Verify we can get the same ID again */
475 	__u64 user_ns_id2 = 0;
476 	ret = ioctl(fd_userns, NS_GET_ID, &user_ns_id2);
477 	ASSERT_EQ(ret, 0);
478 	ASSERT_EQ(user_ns_id, user_ns_id2);
479 
480 	close(fd_userns);
481 }
482 
TEST(nsid_userns_separate)483 TEST(nsid_userns_separate)
484 {
485 	__u64 parent_user_ns_id = 0;
486 	__u64 child_user_ns_id = 0;
487 	int fd_parent_userns, fd_child_userns;
488 	int ret;
489 	pid_t pid;
490 	int pipefd[2];
491 
492 	/* Get parent's user namespace ID */
493 	fd_parent_userns = open("/proc/self/ns/user", O_RDONLY);
494 	ASSERT_GE(fd_parent_userns, 0);
495 	ret = ioctl(fd_parent_userns, NS_GET_ID, &parent_user_ns_id);
496 	ASSERT_EQ(ret, 0);
497 	ASSERT_NE(parent_user_ns_id, 0);
498 
499 	/* Create a pipe for synchronization */
500 	ASSERT_EQ(pipe(pipefd), 0);
501 
502 	pid = fork();
503 	ASSERT_GE(pid, 0);
504 
505 	if (pid == 0) {
506 		/* Child process */
507 		close(pipefd[0]);
508 
509 		/* Create new user namespace */
510 		ret = unshare(CLONE_NEWUSER);
511 		if (ret != 0) {
512 			/* Skip test if we don't have permission */
513 			if (errno == EPERM || errno == EACCES) {
514 				write(pipefd[1], "S", 1); /* Signal skip */
515 				_exit(0);
516 			}
517 			_exit(1);
518 		}
519 
520 		/* Signal success */
521 		write(pipefd[1], "Y", 1);
522 		close(pipefd[1]);
523 
524 		/* Keep namespace alive */
525 		pause();
526 		_exit(0);
527 	}
528 
529 	/* Parent process */
530 	close(pipefd[1]);
531 
532 	char buf;
533 	ASSERT_EQ(read(pipefd[0], &buf, 1), 1);
534 	close(pipefd[0]);
535 
536 	if (buf == 'S') {
537 		/* Child couldn't create namespace, skip test */
538 		kill(pid, SIGTERM);
539 		waitpid(pid, NULL, 0);
540 		close(fd_parent_userns);
541 		SKIP(return, "No permission to create user namespace");
542 	}
543 
544 	ASSERT_EQ(buf, 'Y');
545 
546 	/* Open child's user namespace */
547 	char path[256];
548 	snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
549 	fd_child_userns = open(path, O_RDONLY);
550 	ASSERT_GE(fd_child_userns, 0);
551 
552 	/* Get child's user namespace ID */
553 	ret = ioctl(fd_child_userns, NS_GET_ID, &child_user_ns_id);
554 	ASSERT_EQ(ret, 0);
555 	ASSERT_NE(child_user_ns_id, 0);
556 
557 	/* Parent and child should have different user namespace IDs */
558 	ASSERT_NE(parent_user_ns_id, child_user_ns_id);
559 
560 	close(fd_parent_userns);
561 	close(fd_child_userns);
562 
563 	/* Clean up child process */
564 	kill(pid, SIGTERM);
565 	waitpid(pid, NULL, 0);
566 }
567 
TEST(nsid_timens_basic)568 TEST(nsid_timens_basic)
569 {
570 	__u64 time_ns_id = 0;
571 	int fd_timens;
572 	int ret;
573 
574 	/* Open the current time namespace */
575 	fd_timens = open("/proc/self/ns/time", O_RDONLY);
576 	if (fd_timens < 0) {
577 		SKIP(return, "Time namespaces not supported");
578 	}
579 
580 	/* Get the time namespace ID */
581 	ret = ioctl(fd_timens, NS_GET_ID, &time_ns_id);
582 	ASSERT_EQ(ret, 0);
583 	ASSERT_NE(time_ns_id, 0);
584 
585 	/* Verify we can get the same ID again */
586 	__u64 time_ns_id2 = 0;
587 	ret = ioctl(fd_timens, NS_GET_ID, &time_ns_id2);
588 	ASSERT_EQ(ret, 0);
589 	ASSERT_EQ(time_ns_id, time_ns_id2);
590 
591 	close(fd_timens);
592 }
593 
TEST(nsid_timens_separate)594 TEST(nsid_timens_separate)
595 {
596 	__u64 parent_time_ns_id = 0;
597 	__u64 child_time_ns_id = 0;
598 	int fd_parent_timens, fd_child_timens;
599 	int ret;
600 	pid_t pid;
601 	int pipefd[2];
602 
603 	/* Open the current time namespace */
604 	fd_parent_timens = open("/proc/self/ns/time", O_RDONLY);
605 	if (fd_parent_timens < 0) {
606 		SKIP(return, "Time namespaces not supported");
607 	}
608 
609 	/* Get parent's time namespace ID */
610 	ret = ioctl(fd_parent_timens, NS_GET_ID, &parent_time_ns_id);
611 	ASSERT_EQ(ret, 0);
612 	ASSERT_NE(parent_time_ns_id, 0);
613 
614 	/* Create a pipe for synchronization */
615 	ASSERT_EQ(pipe(pipefd), 0);
616 
617 	pid = fork();
618 	ASSERT_GE(pid, 0);
619 
620 	if (pid == 0) {
621 		/* Child process */
622 		close(pipefd[0]);
623 
624 		/* Create new time namespace */
625 		ret = unshare(CLONE_NEWTIME);
626 		if (ret != 0) {
627 			/* Skip test if we don't have permission */
628 			if (errno == EPERM || errno == EACCES || errno == EINVAL) {
629 				write(pipefd[1], "S", 1); /* Signal skip */
630 				_exit(0);
631 			}
632 			_exit(1);
633 		}
634 
635 		/* Fork a grandchild to actually enter the new namespace */
636 		pid_t grandchild = fork();
637 		if (grandchild == 0) {
638 			/* Grandchild is in the new namespace */
639 			write(pipefd[1], "Y", 1);
640 			close(pipefd[1]);
641 			pause();
642 			_exit(0);
643 		} else if (grandchild > 0) {
644 			/* Child writes grandchild PID and waits */
645 			write(pipefd[1], "Y", 1);
646 			write(pipefd[1], &grandchild, sizeof(grandchild));
647 			close(pipefd[1]);
648 			pause(); /* Keep the parent alive to maintain the grandchild */
649 			_exit(0);
650 		} else {
651 			_exit(1);
652 		}
653 	}
654 
655 	/* Parent process */
656 	close(pipefd[1]);
657 
658 	char buf;
659 	ASSERT_EQ(read(pipefd[0], &buf, 1), 1);
660 
661 	if (buf == 'S') {
662 		/* Child couldn't create namespace, skip test */
663 		kill(pid, SIGTERM);
664 		waitpid(pid, NULL, 0);
665 		close(fd_parent_timens);
666 		close(pipefd[0]);
667 		SKIP(return, "Cannot create time namespace");
668 	}
669 
670 	ASSERT_EQ(buf, 'Y');
671 
672 	pid_t grandchild_pid;
673 	ASSERT_EQ(read(pipefd[0], &grandchild_pid, sizeof(grandchild_pid)), sizeof(grandchild_pid));
674 	close(pipefd[0]);
675 
676 	/* Open grandchild's time namespace */
677 	char path[256];
678 	snprintf(path, sizeof(path), "/proc/%d/ns/time", grandchild_pid);
679 	fd_child_timens = open(path, O_RDONLY);
680 	ASSERT_GE(fd_child_timens, 0);
681 
682 	/* Get child's time namespace ID */
683 	ret = ioctl(fd_child_timens, NS_GET_ID, &child_time_ns_id);
684 	ASSERT_EQ(ret, 0);
685 	ASSERT_NE(child_time_ns_id, 0);
686 
687 	/* Parent and child should have different time namespace IDs */
688 	ASSERT_NE(parent_time_ns_id, child_time_ns_id);
689 
690 	close(fd_parent_timens);
691 	close(fd_child_timens);
692 
693 	/* Clean up child process */
694 	kill(pid, SIGTERM);
695 	waitpid(pid, NULL, 0);
696 }
697 
TEST(nsid_pidns_basic)698 TEST(nsid_pidns_basic)
699 {
700 	__u64 pid_ns_id = 0;
701 	int fd_pidns;
702 	int ret;
703 
704 	/* Open the current PID namespace */
705 	fd_pidns = open("/proc/self/ns/pid", O_RDONLY);
706 	ASSERT_GE(fd_pidns, 0);
707 
708 	/* Get the PID namespace ID */
709 	ret = ioctl(fd_pidns, NS_GET_ID, &pid_ns_id);
710 	ASSERT_EQ(ret, 0);
711 	ASSERT_NE(pid_ns_id, 0);
712 
713 	/* Verify we can get the same ID again */
714 	__u64 pid_ns_id2 = 0;
715 	ret = ioctl(fd_pidns, NS_GET_ID, &pid_ns_id2);
716 	ASSERT_EQ(ret, 0);
717 	ASSERT_EQ(pid_ns_id, pid_ns_id2);
718 
719 	close(fd_pidns);
720 }
721 
TEST(nsid_pidns_separate)722 TEST(nsid_pidns_separate)
723 {
724 	__u64 parent_pid_ns_id = 0;
725 	__u64 child_pid_ns_id = 0;
726 	int fd_parent_pidns, fd_child_pidns;
727 	int ret;
728 	pid_t pid;
729 	int pipefd[2];
730 
731 	/* Get parent's PID namespace ID */
732 	fd_parent_pidns = open("/proc/self/ns/pid", O_RDONLY);
733 	ASSERT_GE(fd_parent_pidns, 0);
734 	ret = ioctl(fd_parent_pidns, NS_GET_ID, &parent_pid_ns_id);
735 	ASSERT_EQ(ret, 0);
736 	ASSERT_NE(parent_pid_ns_id, 0);
737 
738 	/* Create a pipe for synchronization */
739 	ASSERT_EQ(pipe(pipefd), 0);
740 
741 	pid = fork();
742 	ASSERT_GE(pid, 0);
743 
744 	if (pid == 0) {
745 		/* Child process */
746 		close(pipefd[0]);
747 
748 		/* Create new PID namespace */
749 		ret = unshare(CLONE_NEWPID);
750 		if (ret != 0) {
751 			/* Skip test if we don't have permission */
752 			if (errno == EPERM || errno == EACCES) {
753 				write(pipefd[1], "S", 1); /* Signal skip */
754 				_exit(0);
755 			}
756 			_exit(1);
757 		}
758 
759 		/* Fork a grandchild to actually enter the new namespace */
760 		pid_t grandchild = fork();
761 		if (grandchild == 0) {
762 			/* Grandchild is in the new namespace */
763 			write(pipefd[1], "Y", 1);
764 			close(pipefd[1]);
765 			pause();
766 			_exit(0);
767 		} else if (grandchild > 0) {
768 			/* Child writes grandchild PID and waits */
769 			write(pipefd[1], "Y", 1);
770 			write(pipefd[1], &grandchild, sizeof(grandchild));
771 			close(pipefd[1]);
772 			pause(); /* Keep the parent alive to maintain the grandchild */
773 			_exit(0);
774 		} else {
775 			_exit(1);
776 		}
777 	}
778 
779 	/* Parent process */
780 	close(pipefd[1]);
781 
782 	char buf;
783 	ASSERT_EQ(read(pipefd[0], &buf, 1), 1);
784 
785 	if (buf == 'S') {
786 		/* Child couldn't create namespace, skip test */
787 		kill(pid, SIGTERM);
788 		waitpid(pid, NULL, 0);
789 		close(fd_parent_pidns);
790 		close(pipefd[0]);
791 		SKIP(return, "No permission to create PID namespace");
792 	}
793 
794 	ASSERT_EQ(buf, 'Y');
795 
796 	pid_t grandchild_pid;
797 	ASSERT_EQ(read(pipefd[0], &grandchild_pid, sizeof(grandchild_pid)), sizeof(grandchild_pid));
798 	close(pipefd[0]);
799 
800 	/* Open grandchild's PID namespace */
801 	char path[256];
802 	snprintf(path, sizeof(path), "/proc/%d/ns/pid", grandchild_pid);
803 	fd_child_pidns = open(path, O_RDONLY);
804 	ASSERT_GE(fd_child_pidns, 0);
805 
806 	/* Get child's PID namespace ID */
807 	ret = ioctl(fd_child_pidns, NS_GET_ID, &child_pid_ns_id);
808 	ASSERT_EQ(ret, 0);
809 	ASSERT_NE(child_pid_ns_id, 0);
810 
811 	/* Parent and child should have different PID namespace IDs */
812 	ASSERT_NE(parent_pid_ns_id, child_pid_ns_id);
813 
814 	close(fd_parent_pidns);
815 	close(fd_child_pidns);
816 
817 	/* Clean up child process */
818 	kill(pid, SIGTERM);
819 	waitpid(pid, NULL, 0);
820 }
821 
TEST(nsid_netns_basic)822 TEST(nsid_netns_basic)
823 {
824 	__u64 net_ns_id = 0;
825 	__u64 netns_cookie = 0;
826 	int fd_netns;
827 	int sock;
828 	socklen_t optlen;
829 	int ret;
830 
831 	/* Open the current network namespace */
832 	fd_netns = open("/proc/self/ns/net", O_RDONLY);
833 	ASSERT_GE(fd_netns, 0);
834 
835 	/* Get the network namespace ID via ioctl */
836 	ret = ioctl(fd_netns, NS_GET_ID, &net_ns_id);
837 	ASSERT_EQ(ret, 0);
838 	ASSERT_NE(net_ns_id, 0);
839 
840 	/* Create a socket to get the SO_NETNS_COOKIE */
841 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
842 	ASSERT_GE(sock, 0);
843 
844 	/* Get the network namespace cookie via socket option */
845 	optlen = sizeof(netns_cookie);
846 	ret = getsockopt(sock, SOL_SOCKET, SO_NETNS_COOKIE, &netns_cookie, &optlen);
847 	ASSERT_EQ(ret, 0);
848 	ASSERT_EQ(optlen, sizeof(netns_cookie));
849 
850 	/* The namespace ID and cookie should be identical */
851 	ASSERT_EQ(net_ns_id, netns_cookie);
852 
853 	/* Verify we can get the same ID again */
854 	__u64 net_ns_id2 = 0;
855 	ret = ioctl(fd_netns, NS_GET_ID, &net_ns_id2);
856 	ASSERT_EQ(ret, 0);
857 	ASSERT_EQ(net_ns_id, net_ns_id2);
858 
859 	close(sock);
860 	close(fd_netns);
861 }
862 
TEST(nsid_netns_separate)863 TEST(nsid_netns_separate)
864 {
865 	__u64 parent_net_ns_id = 0;
866 	__u64 parent_netns_cookie = 0;
867 	__u64 child_net_ns_id = 0;
868 	__u64 child_netns_cookie = 0;
869 	int fd_parent_netns, fd_child_netns;
870 	int parent_sock, child_sock;
871 	socklen_t optlen;
872 	int ret;
873 	pid_t pid;
874 	int pipefd[2];
875 
876 	/* Get parent's network namespace ID */
877 	fd_parent_netns = open("/proc/self/ns/net", O_RDONLY);
878 	ASSERT_GE(fd_parent_netns, 0);
879 	ret = ioctl(fd_parent_netns, NS_GET_ID, &parent_net_ns_id);
880 	ASSERT_EQ(ret, 0);
881 	ASSERT_NE(parent_net_ns_id, 0);
882 
883 	/* Get parent's network namespace cookie */
884 	parent_sock = socket(AF_UNIX, SOCK_STREAM, 0);
885 	ASSERT_GE(parent_sock, 0);
886 	optlen = sizeof(parent_netns_cookie);
887 	ret = getsockopt(parent_sock, SOL_SOCKET, SO_NETNS_COOKIE, &parent_netns_cookie, &optlen);
888 	ASSERT_EQ(ret, 0);
889 
890 	/* Verify parent's ID and cookie match */
891 	ASSERT_EQ(parent_net_ns_id, parent_netns_cookie);
892 
893 	/* Create a pipe for synchronization */
894 	ASSERT_EQ(pipe(pipefd), 0);
895 
896 	pid = fork();
897 	ASSERT_GE(pid, 0);
898 
899 	if (pid == 0) {
900 		/* Child process */
901 		close(pipefd[0]);
902 
903 		/* Create new network namespace */
904 		ret = unshare(CLONE_NEWNET);
905 		if (ret != 0) {
906 			/* Skip test if we don't have permission */
907 			if (errno == EPERM || errno == EACCES) {
908 				write(pipefd[1], "S", 1); /* Signal skip */
909 				_exit(0);
910 			}
911 			_exit(1);
912 		}
913 
914 		/* Signal success */
915 		write(pipefd[1], "Y", 1);
916 		close(pipefd[1]);
917 
918 		/* Keep namespace alive */
919 		pause();
920 		_exit(0);
921 	}
922 
923 	/* Parent process */
924 	close(pipefd[1]);
925 
926 	char buf;
927 	ASSERT_EQ(read(pipefd[0], &buf, 1), 1);
928 	close(pipefd[0]);
929 
930 	if (buf == 'S') {
931 		/* Child couldn't create namespace, skip test */
932 		kill(pid, SIGTERM);
933 		waitpid(pid, NULL, 0);
934 		close(fd_parent_netns);
935 		close(parent_sock);
936 		SKIP(return, "No permission to create network namespace");
937 	}
938 
939 	ASSERT_EQ(buf, 'Y');
940 
941 	/* Open child's network namespace */
942 	char path[256];
943 	snprintf(path, sizeof(path), "/proc/%d/ns/net", pid);
944 	fd_child_netns = open(path, O_RDONLY);
945 	ASSERT_GE(fd_child_netns, 0);
946 
947 	/* Get child's network namespace ID */
948 	ret = ioctl(fd_child_netns, NS_GET_ID, &child_net_ns_id);
949 	ASSERT_EQ(ret, 0);
950 	ASSERT_NE(child_net_ns_id, 0);
951 
952 	/* Create socket in child's namespace to get cookie */
953 	ret = setns(fd_child_netns, CLONE_NEWNET);
954 	if (ret == 0) {
955 		child_sock = socket(AF_UNIX, SOCK_STREAM, 0);
956 		ASSERT_GE(child_sock, 0);
957 
958 		optlen = sizeof(child_netns_cookie);
959 		ret = getsockopt(child_sock, SOL_SOCKET, SO_NETNS_COOKIE, &child_netns_cookie, &optlen);
960 		ASSERT_EQ(ret, 0);
961 
962 		/* Verify child's ID and cookie match */
963 		ASSERT_EQ(child_net_ns_id, child_netns_cookie);
964 
965 		close(child_sock);
966 
967 		/* Return to parent namespace */
968 		setns(fd_parent_netns, CLONE_NEWNET);
969 	}
970 
971 	/* Parent and child should have different network namespace IDs */
972 	ASSERT_NE(parent_net_ns_id, child_net_ns_id);
973 	if (child_netns_cookie != 0) {
974 		ASSERT_NE(parent_netns_cookie, child_netns_cookie);
975 	}
976 
977 	close(fd_parent_netns);
978 	close(fd_child_netns);
979 	close(parent_sock);
980 
981 	/* Clean up child process */
982 	kill(pid, SIGTERM);
983 	waitpid(pid, NULL, 0);
984 }
985 
986 TEST_HARNESS_MAIN
987