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