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 /* Grandchild is in the new namespace */ 653 write(pipefd[1], "Y", 1); 654 close(pipefd[1]); 655 pause(); 656 _exit(0); 657 } else if (grandchild > 0) { 658 /* Child writes grandchild PID and waits */ 659 write(pipefd[1], "Y", 1); 660 write(pipefd[1], &grandchild, sizeof(grandchild)); 661 close(pipefd[1]); 662 pause(); /* Keep the parent alive to maintain the grandchild */ 663 _exit(0); 664 } else { 665 _exit(1); 666 } 667 } 668 669 /* Track child for cleanup */ 670 self->child_pid = pid; 671 672 /* Parent process */ 673 close(pipefd[1]); 674 675 char buf; 676 ASSERT_EQ(read(pipefd[0], &buf, 1), 1); 677 678 if (buf == 'S') { 679 /* Child couldn't create namespace, skip test */ 680 close(fd_parent_timens); 681 close(pipefd[0]); 682 SKIP(return, "Cannot create time namespace"); 683 } 684 685 ASSERT_EQ(buf, 'Y'); 686 687 pid_t grandchild_pid; 688 ASSERT_EQ(read(pipefd[0], &grandchild_pid, sizeof(grandchild_pid)), sizeof(grandchild_pid)); 689 self->grandchild_pid = grandchild_pid; 690 close(pipefd[0]); 691 692 /* Open grandchild's time namespace */ 693 char path[256]; 694 snprintf(path, sizeof(path), "/proc/%d/ns/time", grandchild_pid); 695 fd_child_timens = open(path, O_RDONLY); 696 ASSERT_GE(fd_child_timens, 0); 697 698 /* Get child's time namespace ID */ 699 ret = ioctl(fd_child_timens, NS_GET_ID, &child_time_ns_id); 700 ASSERT_EQ(ret, 0); 701 ASSERT_NE(child_time_ns_id, 0); 702 703 /* Parent and child should have different time namespace IDs */ 704 ASSERT_NE(parent_time_ns_id, child_time_ns_id); 705 706 close(fd_parent_timens); 707 close(fd_child_timens); 708 } 709 710 TEST(nsid_pidns_basic) 711 { 712 __u64 pid_ns_id = 0; 713 int fd_pidns; 714 int ret; 715 716 /* Open the current PID namespace */ 717 fd_pidns = open("/proc/self/ns/pid", O_RDONLY); 718 ASSERT_GE(fd_pidns, 0); 719 720 /* Get the PID namespace ID */ 721 ret = ioctl(fd_pidns, NS_GET_ID, &pid_ns_id); 722 ASSERT_EQ(ret, 0); 723 ASSERT_NE(pid_ns_id, 0); 724 725 /* Verify we can get the same ID again */ 726 __u64 pid_ns_id2 = 0; 727 ret = ioctl(fd_pidns, NS_GET_ID, &pid_ns_id2); 728 ASSERT_EQ(ret, 0); 729 ASSERT_EQ(pid_ns_id, pid_ns_id2); 730 731 close(fd_pidns); 732 } 733 734 TEST_F(nsid, pidns_separate) 735 { 736 __u64 parent_pid_ns_id = 0; 737 __u64 child_pid_ns_id = 0; 738 int fd_parent_pidns, fd_child_pidns; 739 int ret; 740 pid_t pid; 741 int pipefd[2]; 742 743 /* Get parent's PID namespace ID */ 744 fd_parent_pidns = open("/proc/self/ns/pid", O_RDONLY); 745 ASSERT_GE(fd_parent_pidns, 0); 746 ret = ioctl(fd_parent_pidns, NS_GET_ID, &parent_pid_ns_id); 747 ASSERT_EQ(ret, 0); 748 ASSERT_NE(parent_pid_ns_id, 0); 749 750 /* Create a pipe for synchronization */ 751 ASSERT_EQ(pipe(pipefd), 0); 752 753 pid = fork(); 754 ASSERT_GE(pid, 0); 755 756 if (pid == 0) { 757 /* Child process */ 758 close(pipefd[0]); 759 760 /* Create new PID namespace */ 761 ret = unshare(CLONE_NEWPID); 762 if (ret != 0) { 763 /* Skip test if we don't have permission */ 764 if (errno == EPERM || errno == EACCES) { 765 write(pipefd[1], "S", 1); /* Signal skip */ 766 _exit(0); 767 } 768 _exit(1); 769 } 770 771 /* Fork a grandchild to actually enter the new namespace */ 772 pid_t grandchild = fork(); 773 if (grandchild == 0) { 774 /* Grandchild is in the new namespace */ 775 write(pipefd[1], "Y", 1); 776 close(pipefd[1]); 777 pause(); 778 _exit(0); 779 } else if (grandchild > 0) { 780 /* Child writes grandchild PID and waits */ 781 write(pipefd[1], "Y", 1); 782 write(pipefd[1], &grandchild, sizeof(grandchild)); 783 close(pipefd[1]); 784 pause(); /* Keep the parent alive to maintain the grandchild */ 785 _exit(0); 786 } else { 787 _exit(1); 788 } 789 } 790 791 /* Track child for cleanup */ 792 self->child_pid = pid; 793 794 /* Parent process */ 795 close(pipefd[1]); 796 797 char buf; 798 ASSERT_EQ(read(pipefd[0], &buf, 1), 1); 799 800 if (buf == 'S') { 801 /* Child couldn't create namespace, skip test */ 802 close(fd_parent_pidns); 803 close(pipefd[0]); 804 SKIP(return, "No permission to create PID namespace"); 805 } 806 807 ASSERT_EQ(buf, 'Y'); 808 809 pid_t grandchild_pid; 810 ASSERT_EQ(read(pipefd[0], &grandchild_pid, sizeof(grandchild_pid)), sizeof(grandchild_pid)); 811 self->grandchild_pid = grandchild_pid; 812 close(pipefd[0]); 813 814 /* Open grandchild's PID namespace */ 815 char path[256]; 816 snprintf(path, sizeof(path), "/proc/%d/ns/pid", grandchild_pid); 817 fd_child_pidns = open(path, O_RDONLY); 818 ASSERT_GE(fd_child_pidns, 0); 819 820 /* Get child's PID namespace ID */ 821 ret = ioctl(fd_child_pidns, NS_GET_ID, &child_pid_ns_id); 822 ASSERT_EQ(ret, 0); 823 ASSERT_NE(child_pid_ns_id, 0); 824 825 /* Parent and child should have different PID namespace IDs */ 826 ASSERT_NE(parent_pid_ns_id, child_pid_ns_id); 827 828 close(fd_parent_pidns); 829 close(fd_child_pidns); 830 } 831 832 TEST(nsid_netns_basic) 833 { 834 __u64 net_ns_id = 0; 835 __u64 netns_cookie = 0; 836 int fd_netns; 837 int sock; 838 socklen_t optlen; 839 int ret; 840 841 /* Open the current network namespace */ 842 fd_netns = open("/proc/self/ns/net", O_RDONLY); 843 ASSERT_GE(fd_netns, 0); 844 845 /* Get the network namespace ID via ioctl */ 846 ret = ioctl(fd_netns, NS_GET_ID, &net_ns_id); 847 ASSERT_EQ(ret, 0); 848 ASSERT_NE(net_ns_id, 0); 849 850 /* Create a socket to get the SO_NETNS_COOKIE */ 851 sock = socket(AF_UNIX, SOCK_STREAM, 0); 852 ASSERT_GE(sock, 0); 853 854 /* Get the network namespace cookie via socket option */ 855 optlen = sizeof(netns_cookie); 856 ret = getsockopt(sock, SOL_SOCKET, SO_NETNS_COOKIE, &netns_cookie, &optlen); 857 ASSERT_EQ(ret, 0); 858 ASSERT_EQ(optlen, sizeof(netns_cookie)); 859 860 /* The namespace ID and cookie should be identical */ 861 ASSERT_EQ(net_ns_id, netns_cookie); 862 863 /* Verify we can get the same ID again */ 864 __u64 net_ns_id2 = 0; 865 ret = ioctl(fd_netns, NS_GET_ID, &net_ns_id2); 866 ASSERT_EQ(ret, 0); 867 ASSERT_EQ(net_ns_id, net_ns_id2); 868 869 close(sock); 870 close(fd_netns); 871 } 872 873 TEST_F(nsid, netns_separate) 874 { 875 __u64 parent_net_ns_id = 0; 876 __u64 parent_netns_cookie = 0; 877 __u64 child_net_ns_id = 0; 878 __u64 child_netns_cookie = 0; 879 int fd_parent_netns, fd_child_netns; 880 int parent_sock, child_sock; 881 socklen_t optlen; 882 int ret; 883 pid_t pid; 884 int pipefd[2]; 885 886 /* Get parent's network namespace ID */ 887 fd_parent_netns = open("/proc/self/ns/net", O_RDONLY); 888 ASSERT_GE(fd_parent_netns, 0); 889 ret = ioctl(fd_parent_netns, NS_GET_ID, &parent_net_ns_id); 890 ASSERT_EQ(ret, 0); 891 ASSERT_NE(parent_net_ns_id, 0); 892 893 /* Get parent's network namespace cookie */ 894 parent_sock = socket(AF_UNIX, SOCK_STREAM, 0); 895 ASSERT_GE(parent_sock, 0); 896 optlen = sizeof(parent_netns_cookie); 897 ret = getsockopt(parent_sock, SOL_SOCKET, SO_NETNS_COOKIE, &parent_netns_cookie, &optlen); 898 ASSERT_EQ(ret, 0); 899 900 /* Verify parent's ID and cookie match */ 901 ASSERT_EQ(parent_net_ns_id, parent_netns_cookie); 902 903 /* Create a pipe for synchronization */ 904 ASSERT_EQ(pipe(pipefd), 0); 905 906 pid = fork(); 907 ASSERT_GE(pid, 0); 908 909 if (pid == 0) { 910 /* Child process */ 911 close(pipefd[0]); 912 913 /* Create new network namespace */ 914 ret = unshare(CLONE_NEWNET); 915 if (ret != 0) { 916 /* Skip test if we don't have permission */ 917 if (errno == EPERM || errno == EACCES) { 918 write(pipefd[1], "S", 1); /* Signal skip */ 919 _exit(0); 920 } 921 _exit(1); 922 } 923 924 /* Signal success */ 925 write(pipefd[1], "Y", 1); 926 close(pipefd[1]); 927 928 /* Keep namespace alive */ 929 pause(); 930 _exit(0); 931 } 932 933 /* Track child for cleanup */ 934 self->child_pid = pid; 935 936 /* Parent process */ 937 close(pipefd[1]); 938 939 char buf; 940 ASSERT_EQ(read(pipefd[0], &buf, 1), 1); 941 close(pipefd[0]); 942 943 if (buf == 'S') { 944 /* Child couldn't create namespace, skip test */ 945 close(fd_parent_netns); 946 close(parent_sock); 947 SKIP(return, "No permission to create network namespace"); 948 } 949 950 ASSERT_EQ(buf, 'Y'); 951 952 /* Open child's network namespace */ 953 char path[256]; 954 snprintf(path, sizeof(path), "/proc/%d/ns/net", pid); 955 fd_child_netns = open(path, O_RDONLY); 956 ASSERT_GE(fd_child_netns, 0); 957 958 /* Get child's network namespace ID */ 959 ret = ioctl(fd_child_netns, NS_GET_ID, &child_net_ns_id); 960 ASSERT_EQ(ret, 0); 961 ASSERT_NE(child_net_ns_id, 0); 962 963 /* Create socket in child's namespace to get cookie */ 964 ret = setns(fd_child_netns, CLONE_NEWNET); 965 if (ret == 0) { 966 child_sock = socket(AF_UNIX, SOCK_STREAM, 0); 967 ASSERT_GE(child_sock, 0); 968 969 optlen = sizeof(child_netns_cookie); 970 ret = getsockopt(child_sock, SOL_SOCKET, SO_NETNS_COOKIE, &child_netns_cookie, &optlen); 971 ASSERT_EQ(ret, 0); 972 973 /* Verify child's ID and cookie match */ 974 ASSERT_EQ(child_net_ns_id, child_netns_cookie); 975 976 close(child_sock); 977 978 /* Return to parent namespace */ 979 setns(fd_parent_netns, CLONE_NEWNET); 980 } 981 982 /* Parent and child should have different network namespace IDs */ 983 ASSERT_NE(parent_net_ns_id, child_net_ns_id); 984 if (child_netns_cookie != 0) { 985 ASSERT_NE(parent_netns_cookie, child_netns_cookie); 986 } 987 988 close(fd_parent_netns); 989 close(fd_child_netns); 990 close(parent_sock); 991 } 992 993 TEST_HARNESS_MAIN 994