projects/linux·blob master · refs

989 lines · 22.2 KiB

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