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