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 }; 29 30 FIXTURE_SETUP(nsid) { 31 self->child_pid = 0; 32 } 33 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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