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