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 */ 26 FIXTURE(nsid) { 27 pid_t child_pid; 28 pid_t grandchild_pid; 29 }; 30 31 FIXTURE_SETUP(nsid) { 32 self->child_pid = 0; 33 self->grandchild_pid = 0; 34 } 35 36 FIXTURE_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 52 TEST(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 76 TEST_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 158 TEST(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 182 TEST_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 264 TEST(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 288 TEST_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 370 TEST(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 394 TEST_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 476 TEST(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 500 TEST_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 582 TEST(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 608 TEST_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 708 TEST(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 732 TEST_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 828 TEST(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 869 TEST_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 989 TEST_HARNESS_MAIN 990