1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2026 Christian Brauner <brauner@kernel.org> 4 * 5 * Test for FSMOUNT_NAMESPACE flag. 6 * 7 * Test that fsmount() with FSMOUNT_NAMESPACE creates a new mount 8 * namespace containing the specified mount. 9 */ 10 #define _GNU_SOURCE 11 12 #include <errno.h> 13 #include <fcntl.h> 14 #include <limits.h> 15 #include <linux/nsfs.h> 16 #include <sched.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <sys/ioctl.h> 21 #include <sys/mount.h> 22 #include <sys/stat.h> 23 #include <sys/wait.h> 24 #include <unistd.h> 25 26 #include "../wrappers.h" 27 #include "../statmount/statmount.h" 28 #include "../utils.h" 29 #include "../../kselftest_harness.h" 30 31 #ifndef FSMOUNT_NAMESPACE 32 #define FSMOUNT_NAMESPACE 0x00000002 33 #endif 34 35 #ifndef FSMOUNT_CLOEXEC 36 #define FSMOUNT_CLOEXEC 0x00000001 37 #endif 38 39 #ifndef FSCONFIG_CMD_CREATE 40 #define FSCONFIG_CMD_CREATE 6 41 #endif 42 43 static int get_mnt_ns_id(int fd, uint64_t *mnt_ns_id) 44 { 45 if (ioctl(fd, NS_GET_MNTNS_ID, mnt_ns_id) < 0) 46 return -errno; 47 return 0; 48 } 49 50 static int get_mnt_ns_id_from_path(const char *path, uint64_t *mnt_ns_id) 51 { 52 int fd, ret; 53 54 fd = open(path, O_RDONLY); 55 if (fd < 0) 56 return -errno; 57 58 ret = get_mnt_ns_id(fd, mnt_ns_id); 59 close(fd); 60 return ret; 61 } 62 63 static void log_mount(struct __test_metadata *_metadata, struct statmount *sm) 64 { 65 const char *fs_type = ""; 66 const char *mnt_root = ""; 67 const char *mnt_point = ""; 68 69 if (sm->mask & STATMOUNT_FS_TYPE) 70 fs_type = sm->str + sm->fs_type; 71 if (sm->mask & STATMOUNT_MNT_ROOT) 72 mnt_root = sm->str + sm->mnt_root; 73 if (sm->mask & STATMOUNT_MNT_POINT) 74 mnt_point = sm->str + sm->mnt_point; 75 76 TH_LOG(" mnt_id: %llu, parent_id: %llu, fs_type: %s, root: %s, point: %s", 77 (unsigned long long)sm->mnt_id, 78 (unsigned long long)sm->mnt_parent_id, 79 fs_type, mnt_root, mnt_point); 80 } 81 82 static void dump_mounts(struct __test_metadata *_metadata, uint64_t mnt_ns_id) 83 { 84 uint64_t list[256]; 85 ssize_t nr_mounts; 86 87 nr_mounts = listmount(LSMT_ROOT, mnt_ns_id, 0, list, 256, 0); 88 if (nr_mounts < 0) { 89 TH_LOG("listmount failed: %s", strerror(errno)); 90 return; 91 } 92 93 TH_LOG("Mount namespace %llu contains %zd mount(s):", 94 (unsigned long long)mnt_ns_id, nr_mounts); 95 96 for (ssize_t i = 0; i < nr_mounts; i++) { 97 struct statmount *sm; 98 99 sm = statmount_alloc(list[i], mnt_ns_id, 100 STATMOUNT_MNT_BASIC | 101 STATMOUNT_FS_TYPE | 102 STATMOUNT_MNT_ROOT | 103 STATMOUNT_MNT_POINT, 0); 104 if (!sm) { 105 TH_LOG(" [%zd] mnt_id %llu: statmount failed: %s", 106 i, (unsigned long long)list[i], strerror(errno)); 107 continue; 108 } 109 110 log_mount(_metadata, sm); 111 free(sm); 112 } 113 } 114 115 static int create_tmpfs_fd(void) 116 { 117 int fs_fd, ret; 118 119 fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 120 if (fs_fd < 0) 121 return -errno; 122 123 ret = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); 124 if (ret < 0) { 125 close(fs_fd); 126 return -errno; 127 } 128 129 return fs_fd; 130 } 131 132 FIXTURE(fsmount_ns) 133 { 134 int fd; 135 int fs_fd; 136 uint64_t current_ns_id; 137 }; 138 139 FIXTURE_VARIANT(fsmount_ns) 140 { 141 const char *fstype; 142 unsigned int flags; 143 bool expect_success; 144 bool expect_different_ns; 145 int min_mounts; 146 }; 147 148 FIXTURE_VARIANT_ADD(fsmount_ns, basic_tmpfs) 149 { 150 .fstype = "tmpfs", 151 .flags = FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 152 .expect_success = true, 153 .expect_different_ns = true, 154 .min_mounts = 1, 155 }; 156 157 FIXTURE_VARIANT_ADD(fsmount_ns, cloexec_only) 158 { 159 .fstype = "tmpfs", 160 .flags = FSMOUNT_CLOEXEC, 161 .expect_success = true, 162 .expect_different_ns = false, 163 .min_mounts = 1, 164 }; 165 166 FIXTURE_VARIANT_ADD(fsmount_ns, namespace_only) 167 { 168 .fstype = "tmpfs", 169 .flags = FSMOUNT_NAMESPACE, 170 .expect_success = true, 171 .expect_different_ns = true, 172 .min_mounts = 1, 173 }; 174 175 FIXTURE_SETUP(fsmount_ns) 176 { 177 int ret; 178 179 self->fd = -1; 180 self->fs_fd = -1; 181 182 /* Check if fsopen syscall is supported */ 183 ret = sys_fsopen("tmpfs", 0); 184 if (ret == -1 && errno == ENOSYS) 185 SKIP(return, "fsopen() syscall not supported"); 186 if (ret >= 0) 187 close(ret); 188 189 /* Check if statmount/listmount are supported */ 190 ret = statmount(0, 0, 0, 0, NULL, 0, 0); 191 if (ret == -1 && errno == ENOSYS) 192 SKIP(return, "statmount() syscall not supported"); 193 194 /* Get current mount namespace ID for comparison */ 195 ret = get_mnt_ns_id_from_path("/proc/self/ns/mnt", &self->current_ns_id); 196 if (ret < 0) 197 SKIP(return, "Failed to get current mount namespace ID"); 198 } 199 200 FIXTURE_TEARDOWN(fsmount_ns) 201 { 202 if (self->fd >= 0) 203 close(self->fd); 204 if (self->fs_fd >= 0) 205 close(self->fs_fd); 206 } 207 208 TEST_F(fsmount_ns, create_namespace) 209 { 210 uint64_t new_ns_id; 211 uint64_t list[256]; 212 ssize_t nr_mounts; 213 int ret; 214 215 self->fs_fd = create_tmpfs_fd(); 216 ASSERT_GE(self->fs_fd, 0); 217 218 self->fd = sys_fsmount(self->fs_fd, variant->flags, 0); 219 220 if (!variant->expect_success) { 221 ASSERT_LT(self->fd, 0); 222 return; 223 } 224 225 if (self->fd < 0 && errno == EINVAL) 226 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 227 228 ASSERT_GE(self->fd, 0); 229 230 if (variant->expect_different_ns) { 231 /* Verify we can get the namespace ID from the fd */ 232 ret = get_mnt_ns_id(self->fd, &new_ns_id); 233 ASSERT_EQ(ret, 0); 234 235 /* Verify it's a different namespace */ 236 ASSERT_NE(new_ns_id, self->current_ns_id); 237 238 /* List mounts in the new namespace */ 239 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 240 ASSERT_GE(nr_mounts, 0) { 241 TH_LOG("%m - listmount failed"); 242 } 243 244 /* Verify minimum expected mounts */ 245 ASSERT_GE(nr_mounts, variant->min_mounts); 246 TH_LOG("Namespace contains %zd mounts", nr_mounts); 247 } 248 } 249 250 TEST_F(fsmount_ns, setns_into_namespace) 251 { 252 uint64_t new_ns_id; 253 pid_t pid; 254 int status; 255 int ret; 256 257 /* Only test with FSMOUNT_NAMESPACE flag */ 258 if (!(variant->flags & FSMOUNT_NAMESPACE)) 259 SKIP(return, "setns test only for FSMOUNT_NAMESPACE case"); 260 261 self->fs_fd = create_tmpfs_fd(); 262 ASSERT_GE(self->fs_fd, 0); 263 264 self->fd = sys_fsmount(self->fs_fd, variant->flags, 0); 265 if (self->fd < 0 && errno == EINVAL) 266 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 267 268 ASSERT_GE(self->fd, 0); 269 270 /* Get namespace ID and dump all mounts */ 271 ret = get_mnt_ns_id(self->fd, &new_ns_id); 272 ASSERT_EQ(ret, 0); 273 274 dump_mounts(_metadata, new_ns_id); 275 276 pid = fork(); 277 ASSERT_GE(pid, 0); 278 279 if (pid == 0) { 280 /* Child: try to enter the namespace */ 281 if (setns(self->fd, CLONE_NEWNS) < 0) 282 _exit(1); 283 _exit(0); 284 } 285 286 ASSERT_EQ(waitpid(pid, &status, 0), pid); 287 ASSERT_TRUE(WIFEXITED(status)); 288 ASSERT_EQ(WEXITSTATUS(status), 0); 289 } 290 291 TEST_F(fsmount_ns, verify_mount_properties) 292 { 293 struct statmount sm; 294 uint64_t new_ns_id; 295 uint64_t list[256]; 296 ssize_t nr_mounts; 297 int ret; 298 299 /* Only test with basic FSMOUNT_NAMESPACE flags */ 300 if (variant->flags != (FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC)) 301 SKIP(return, "mount properties test only for basic case"); 302 303 self->fs_fd = create_tmpfs_fd(); 304 ASSERT_GE(self->fs_fd, 0); 305 306 self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 307 if (self->fd < 0 && errno == EINVAL) 308 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 309 310 ASSERT_GE(self->fd, 0); 311 312 ret = get_mnt_ns_id(self->fd, &new_ns_id); 313 ASSERT_EQ(ret, 0); 314 315 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 316 ASSERT_GE(nr_mounts, 1); 317 318 /* Get info about the root mount */ 319 ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 320 ASSERT_EQ(ret, 0); 321 322 TH_LOG("Root mount id: %llu, parent: %llu", 323 (unsigned long long)sm.mnt_id, 324 (unsigned long long)sm.mnt_parent_id); 325 } 326 327 TEST_F(fsmount_ns, verify_tmpfs_type) 328 { 329 struct statmount *sm; 330 uint64_t new_ns_id; 331 uint64_t list[256]; 332 ssize_t nr_mounts; 333 const char *fs_type; 334 int ret; 335 336 /* Only test with basic FSMOUNT_NAMESPACE flags */ 337 if (variant->flags != (FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC)) 338 SKIP(return, "fs type test only for basic case"); 339 340 self->fs_fd = create_tmpfs_fd(); 341 ASSERT_GE(self->fs_fd, 0); 342 343 self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 344 if (self->fd < 0 && errno == EINVAL) 345 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 346 347 ASSERT_GE(self->fd, 0); 348 349 ret = get_mnt_ns_id(self->fd, &new_ns_id); 350 ASSERT_EQ(ret, 0); 351 352 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 353 ASSERT_GE(nr_mounts, 1); 354 355 sm = statmount_alloc(list[0], new_ns_id, STATMOUNT_FS_TYPE, 0); 356 ASSERT_NE(sm, NULL); 357 358 fs_type = sm->str + sm->fs_type; 359 ASSERT_STREQ(fs_type, "tmpfs"); 360 361 free(sm); 362 } 363 364 FIXTURE(fsmount_ns_caps) 365 { 366 bool has_caps; 367 }; 368 369 FIXTURE_SETUP(fsmount_ns_caps) 370 { 371 int ret; 372 373 /* Check if fsopen syscall is supported */ 374 ret = sys_fsopen("tmpfs", 0); 375 if (ret == -1 && errno == ENOSYS) 376 SKIP(return, "fsopen() syscall not supported"); 377 if (ret >= 0) 378 close(ret); 379 380 self->has_caps = (geteuid() == 0); 381 } 382 383 FIXTURE_TEARDOWN(fsmount_ns_caps) 384 { 385 } 386 387 TEST_F(fsmount_ns_caps, requires_cap_sys_admin) 388 { 389 pid_t pid; 390 int status; 391 int fs_fd; 392 393 /* 394 * Prepare the configured filesystem fd as root before forking. 395 * fsopen() requires CAP_SYS_ADMIN in the mount namespace's 396 * user_ns, which won't be available after enter_userns(). 397 */ 398 fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 399 ASSERT_GE(fs_fd, 0); 400 401 ASSERT_EQ(sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0); 402 403 pid = fork(); 404 ASSERT_GE(pid, 0); 405 406 if (pid == 0) { 407 int fd; 408 409 /* Child: drop privileges using utils.h helper */ 410 if (enter_userns() != 0) 411 _exit(2); 412 413 /* Drop all caps using utils.h helper */ 414 if (caps_down() == 0) 415 _exit(3); 416 417 fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 418 close(fs_fd); 419 420 if (fd >= 0) { 421 close(fd); 422 /* Should have failed without caps */ 423 _exit(1); 424 } 425 426 if (errno == EPERM) 427 _exit(0); 428 429 /* EINVAL means FSMOUNT_NAMESPACE not supported */ 430 if (errno == EINVAL) 431 _exit(6); 432 433 /* Unexpected error */ 434 _exit(7); 435 } 436 437 close(fs_fd); 438 ASSERT_EQ(waitpid(pid, &status, 0), pid); 439 ASSERT_TRUE(WIFEXITED(status)); 440 441 switch (WEXITSTATUS(status)) { 442 case 0: 443 /* Expected: EPERM without caps */ 444 break; 445 case 1: 446 ASSERT_FALSE(true) TH_LOG("FSMOUNT_NAMESPACE succeeded without caps"); 447 break; 448 case 2: 449 SKIP(return, "enter_userns failed"); 450 break; 451 case 3: 452 SKIP(return, "caps_down failed"); 453 break; 454 case 6: 455 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 456 break; 457 default: 458 ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)", 459 WEXITSTATUS(status)); 460 break; 461 } 462 } 463 464 FIXTURE(fsmount_ns_userns) 465 { 466 int fd; 467 int fs_fd; 468 }; 469 470 FIXTURE_SETUP(fsmount_ns_userns) 471 { 472 int ret; 473 474 self->fd = -1; 475 self->fs_fd = -1; 476 477 /* Check if fsopen syscall is supported */ 478 ret = sys_fsopen("tmpfs", 0); 479 if (ret == -1 && errno == ENOSYS) 480 SKIP(return, "fsopen() syscall not supported"); 481 if (ret >= 0) 482 close(ret); 483 484 /* Check if statmount/listmount are supported */ 485 ret = statmount(0, 0, 0, 0, NULL, 0, 0); 486 if (ret == -1 && errno == ENOSYS) 487 SKIP(return, "statmount() syscall not supported"); 488 } 489 490 FIXTURE_TEARDOWN(fsmount_ns_userns) 491 { 492 if (self->fd >= 0) 493 close(self->fd); 494 if (self->fs_fd >= 0) 495 close(self->fs_fd); 496 } 497 498 TEST_F(fsmount_ns_userns, create_in_userns) 499 { 500 pid_t pid; 501 int status; 502 503 pid = fork(); 504 ASSERT_GE(pid, 0); 505 506 if (pid == 0) { 507 uint64_t new_ns_id; 508 uint64_t list[256]; 509 ssize_t nr_mounts; 510 int fs_fd, fd; 511 512 /* Create new user namespace (also creates mount namespace) */ 513 if (setup_userns() != 0) 514 _exit(2); 515 516 /* Now we have CAP_SYS_ADMIN in the user namespace */ 517 fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 518 if (fs_fd < 0) 519 _exit(3); 520 521 if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) { 522 close(fs_fd); 523 _exit(4); 524 } 525 526 fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 527 close(fs_fd); 528 529 if (fd < 0) { 530 if (errno == EINVAL) 531 _exit(6); /* FSMOUNT_NAMESPACE not supported */ 532 _exit(1); 533 } 534 535 /* Verify we can get the namespace ID */ 536 if (get_mnt_ns_id(fd, &new_ns_id) != 0) 537 _exit(7); 538 539 /* Verify we can list mounts in the new namespace */ 540 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 541 if (nr_mounts < 0) 542 _exit(8); 543 544 /* Should have at least 1 mount (the tmpfs) */ 545 if (nr_mounts < 1) 546 _exit(9); 547 548 close(fd); 549 _exit(0); 550 } 551 552 ASSERT_EQ(waitpid(pid, &status, 0), pid); 553 ASSERT_TRUE(WIFEXITED(status)); 554 555 switch (WEXITSTATUS(status)) { 556 case 0: 557 /* Success */ 558 break; 559 case 1: 560 ASSERT_FALSE(true) TH_LOG("fsmount(FSMOUNT_NAMESPACE) failed in userns"); 561 break; 562 case 2: 563 SKIP(return, "setup_userns failed"); 564 break; 565 case 3: 566 SKIP(return, "fsopen failed in userns"); 567 break; 568 case 4: 569 SKIP(return, "fsconfig CMD_CREATE failed in userns"); 570 break; 571 case 6: 572 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 573 break; 574 case 7: 575 ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID"); 576 break; 577 case 8: 578 ASSERT_FALSE(true) TH_LOG("listmount failed in new namespace"); 579 break; 580 case 9: 581 ASSERT_FALSE(true) TH_LOG("New namespace has no mounts"); 582 break; 583 default: 584 ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)", 585 WEXITSTATUS(status)); 586 break; 587 } 588 } 589 590 TEST_F(fsmount_ns_userns, setns_in_userns) 591 { 592 pid_t pid; 593 int status; 594 595 pid = fork(); 596 ASSERT_GE(pid, 0); 597 598 if (pid == 0) { 599 uint64_t new_ns_id; 600 int fs_fd, fd; 601 pid_t inner_pid; 602 int inner_status; 603 604 /* Create new user namespace */ 605 if (setup_userns() != 0) 606 _exit(2); 607 608 fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 609 if (fs_fd < 0) 610 _exit(3); 611 612 if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) { 613 close(fs_fd); 614 _exit(4); 615 } 616 617 fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 618 close(fs_fd); 619 620 if (fd < 0) { 621 if (errno == EINVAL) 622 _exit(6); 623 _exit(1); 624 } 625 626 if (get_mnt_ns_id(fd, &new_ns_id) != 0) 627 _exit(7); 628 629 /* Fork again to test setns into the new namespace */ 630 inner_pid = fork(); 631 if (inner_pid < 0) 632 _exit(10); 633 634 if (inner_pid == 0) { 635 /* Inner child: enter the new namespace */ 636 if (setns(fd, CLONE_NEWNS) < 0) 637 _exit(1); 638 _exit(0); 639 } 640 641 if (waitpid(inner_pid, &inner_status, 0) != inner_pid) 642 _exit(11); 643 644 if (!WIFEXITED(inner_status) || WEXITSTATUS(inner_status) != 0) 645 _exit(12); 646 647 close(fd); 648 _exit(0); 649 } 650 651 ASSERT_EQ(waitpid(pid, &status, 0), pid); 652 ASSERT_TRUE(WIFEXITED(status)); 653 654 switch (WEXITSTATUS(status)) { 655 case 0: 656 /* Success */ 657 break; 658 case 1: 659 ASSERT_FALSE(true) TH_LOG("fsmount or setns failed in userns"); 660 break; 661 case 2: 662 SKIP(return, "setup_userns failed"); 663 break; 664 case 3: 665 SKIP(return, "fsopen failed in userns"); 666 break; 667 case 4: 668 SKIP(return, "fsconfig CMD_CREATE failed in userns"); 669 break; 670 case 6: 671 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 672 break; 673 case 7: 674 ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID"); 675 break; 676 case 10: 677 ASSERT_FALSE(true) TH_LOG("Inner fork failed"); 678 break; 679 case 11: 680 ASSERT_FALSE(true) TH_LOG("Inner waitpid failed"); 681 break; 682 case 12: 683 ASSERT_FALSE(true) TH_LOG("setns into new namespace failed"); 684 break; 685 default: 686 ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)", 687 WEXITSTATUS(status)); 688 break; 689 } 690 } 691 692 TEST_F(fsmount_ns_userns, umount_fails_einval) 693 { 694 pid_t pid; 695 int status; 696 697 pid = fork(); 698 ASSERT_GE(pid, 0); 699 700 if (pid == 0) { 701 uint64_t new_ns_id; 702 uint64_t list[256]; 703 ssize_t nr_mounts; 704 int fs_fd, fd; 705 ssize_t i; 706 707 /* Create new user namespace */ 708 if (setup_userns() != 0) 709 _exit(2); 710 711 fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 712 if (fs_fd < 0) 713 _exit(3); 714 715 if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) { 716 close(fs_fd); 717 _exit(4); 718 } 719 720 fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 721 close(fs_fd); 722 723 if (fd < 0) { 724 if (errno == EINVAL) 725 _exit(6); 726 _exit(1); 727 } 728 729 if (get_mnt_ns_id(fd, &new_ns_id) != 0) 730 _exit(7); 731 732 /* Get all mounts in the new namespace */ 733 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, LISTMOUNT_REVERSE); 734 if (nr_mounts < 0) 735 _exit(13); 736 737 if (nr_mounts < 1) 738 _exit(14); 739 740 /* Enter the new namespace */ 741 if (setns(fd, CLONE_NEWNS) < 0) 742 _exit(8); 743 744 for (i = 0; i < nr_mounts; i++) { 745 struct statmount *sm; 746 const char *mnt_point; 747 748 sm = statmount_alloc(list[i], new_ns_id, 749 STATMOUNT_MNT_POINT, 0); 750 if (!sm) 751 _exit(15); 752 753 mnt_point = sm->str + sm->mnt_point; 754 755 if (umount2(mnt_point, MNT_DETACH) == 0) { 756 free(sm); 757 _exit(9); 758 } 759 760 if (errno != EINVAL) { 761 /* Wrong error */ 762 free(sm); 763 _exit(10); 764 } 765 766 free(sm); 767 } 768 769 close(fd); 770 _exit(0); 771 } 772 773 ASSERT_EQ(waitpid(pid, &status, 0), pid); 774 ASSERT_TRUE(WIFEXITED(status)); 775 776 switch (WEXITSTATUS(status)) { 777 case 0: 778 break; 779 case 1: 780 ASSERT_FALSE(true) TH_LOG("fsmount(FSMOUNT_NAMESPACE) failed"); 781 break; 782 case 2: 783 SKIP(return, "setup_userns failed"); 784 break; 785 case 3: 786 SKIP(return, "fsopen failed in userns"); 787 break; 788 case 4: 789 SKIP(return, "fsconfig CMD_CREATE failed in userns"); 790 break; 791 case 6: 792 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 793 break; 794 case 7: 795 ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID"); 796 break; 797 case 8: 798 ASSERT_FALSE(true) TH_LOG("setns into new namespace failed"); 799 break; 800 case 9: 801 ASSERT_FALSE(true) TH_LOG("umount succeeded but should have failed with EINVAL"); 802 break; 803 case 10: 804 ASSERT_FALSE(true) TH_LOG("umount failed with wrong error (expected EINVAL)"); 805 break; 806 case 13: 807 ASSERT_FALSE(true) TH_LOG("listmount failed"); 808 break; 809 case 14: 810 ASSERT_FALSE(true) TH_LOG("No mounts in new namespace"); 811 break; 812 case 15: 813 ASSERT_FALSE(true) TH_LOG("statmount_alloc failed"); 814 break; 815 default: 816 ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)", 817 WEXITSTATUS(status)); 818 break; 819 } 820 } 821 822 TEST_F(fsmount_ns_userns, umount_succeeds) 823 { 824 pid_t pid; 825 int status; 826 827 pid = fork(); 828 ASSERT_GE(pid, 0); 829 830 if (pid == 0) { 831 uint64_t new_ns_id; 832 uint64_t list[256]; 833 ssize_t nr_mounts; 834 int fs_fd, fd; 835 ssize_t i; 836 837 if (unshare(CLONE_NEWNS)) 838 _exit(1); 839 840 if (sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) != 0) 841 _exit(1); 842 843 fs_fd = sys_fsopen("tmpfs", FSOPEN_CLOEXEC); 844 if (fs_fd < 0) 845 _exit(3); 846 847 if (sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) { 848 close(fs_fd); 849 _exit(4); 850 } 851 852 fd = sys_fsmount(fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 0); 853 close(fs_fd); 854 855 if (fd < 0) { 856 if (errno == EINVAL) 857 _exit(6); 858 _exit(1); 859 } 860 861 if (get_mnt_ns_id(fd, &new_ns_id) != 0) 862 _exit(7); 863 864 /* Get all mounts in the new namespace */ 865 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, LISTMOUNT_REVERSE); 866 if (nr_mounts < 0) 867 _exit(13); 868 869 if (nr_mounts < 1) 870 _exit(14); 871 872 /* Enter the new namespace */ 873 if (setns(fd, CLONE_NEWNS) < 0) 874 _exit(8); 875 876 for (i = 0; i < nr_mounts; i++) { 877 struct statmount *sm; 878 const char *mnt_point; 879 880 sm = statmount_alloc(list[i], new_ns_id, 881 STATMOUNT_MNT_POINT, 0); 882 if (!sm) 883 _exit(15); 884 885 mnt_point = sm->str + sm->mnt_point; 886 887 if (umount2(mnt_point, MNT_DETACH) != 0) { 888 free(sm); 889 _exit(9); 890 } 891 892 free(sm); 893 } 894 895 close(fd); 896 _exit(0); 897 } 898 899 ASSERT_EQ(waitpid(pid, &status, 0), pid); 900 ASSERT_TRUE(WIFEXITED(status)); 901 902 switch (WEXITSTATUS(status)) { 903 case 0: 904 break; 905 case 1: 906 ASSERT_FALSE(true) TH_LOG("fsmount(FSMOUNT_NAMESPACE) failed or unshare failed"); 907 break; 908 case 3: 909 SKIP(return, "fsopen failed"); 910 break; 911 case 4: 912 SKIP(return, "fsconfig CMD_CREATE failed"); 913 break; 914 case 6: 915 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 916 break; 917 case 7: 918 ASSERT_FALSE(true) TH_LOG("Failed to get mount namespace ID"); 919 break; 920 case 8: 921 ASSERT_FALSE(true) TH_LOG("setns into new namespace failed"); 922 break; 923 case 9: 924 ASSERT_FALSE(true) TH_LOG("umount failed but should have succeeded"); 925 break; 926 case 13: 927 ASSERT_FALSE(true) TH_LOG("listmount failed"); 928 break; 929 case 14: 930 ASSERT_FALSE(true) TH_LOG("No mounts in new namespace"); 931 break; 932 case 15: 933 ASSERT_FALSE(true) TH_LOG("statmount_alloc failed"); 934 break; 935 default: 936 ASSERT_FALSE(true) TH_LOG("Unexpected error in child (exit %d)", 937 WEXITSTATUS(status)); 938 break; 939 } 940 } 941 942 FIXTURE(fsmount_ns_mount_attrs) 943 { 944 int fd; 945 int fs_fd; 946 }; 947 948 FIXTURE_SETUP(fsmount_ns_mount_attrs) 949 { 950 int ret; 951 952 self->fd = -1; 953 self->fs_fd = -1; 954 955 /* Check if fsopen syscall is supported */ 956 ret = sys_fsopen("tmpfs", 0); 957 if (ret == -1 && errno == ENOSYS) 958 SKIP(return, "fsopen() syscall not supported"); 959 if (ret >= 0) 960 close(ret); 961 962 /* Check if statmount/listmount are supported */ 963 ret = statmount(0, 0, 0, 0, NULL, 0, 0); 964 if (ret == -1 && errno == ENOSYS) 965 SKIP(return, "statmount() syscall not supported"); 966 } 967 968 FIXTURE_TEARDOWN(fsmount_ns_mount_attrs) 969 { 970 if (self->fd >= 0) 971 close(self->fd); 972 if (self->fs_fd >= 0) 973 close(self->fs_fd); 974 } 975 976 TEST_F(fsmount_ns_mount_attrs, readonly) 977 { 978 struct statmount sm; 979 uint64_t new_ns_id; 980 uint64_t list[256]; 981 ssize_t nr_mounts; 982 int ret; 983 984 self->fs_fd = create_tmpfs_fd(); 985 ASSERT_GE(self->fs_fd, 0); 986 987 self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 988 MOUNT_ATTR_RDONLY); 989 if (self->fd < 0 && errno == EINVAL) 990 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 991 992 ASSERT_GE(self->fd, 0); 993 994 ret = get_mnt_ns_id(self->fd, &new_ns_id); 995 ASSERT_EQ(ret, 0); 996 997 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 998 ASSERT_GE(nr_mounts, 1); 999 1000 ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 1001 ASSERT_EQ(ret, 0); 1002 1003 /* Verify the mount is read-only */ 1004 ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_RDONLY); 1005 } 1006 1007 TEST_F(fsmount_ns_mount_attrs, noexec) 1008 { 1009 struct statmount sm; 1010 uint64_t new_ns_id; 1011 uint64_t list[256]; 1012 ssize_t nr_mounts; 1013 int ret; 1014 1015 self->fs_fd = create_tmpfs_fd(); 1016 ASSERT_GE(self->fs_fd, 0); 1017 1018 self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 1019 MOUNT_ATTR_NOEXEC); 1020 if (self->fd < 0 && errno == EINVAL) 1021 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 1022 1023 ASSERT_GE(self->fd, 0); 1024 1025 ret = get_mnt_ns_id(self->fd, &new_ns_id); 1026 ASSERT_EQ(ret, 0); 1027 1028 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 1029 ASSERT_GE(nr_mounts, 1); 1030 1031 ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 1032 ASSERT_EQ(ret, 0); 1033 1034 /* Verify the mount is noexec */ 1035 ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOEXEC); 1036 } 1037 1038 TEST_F(fsmount_ns_mount_attrs, nosuid) 1039 { 1040 struct statmount sm; 1041 uint64_t new_ns_id; 1042 uint64_t list[256]; 1043 ssize_t nr_mounts; 1044 int ret; 1045 1046 self->fs_fd = create_tmpfs_fd(); 1047 ASSERT_GE(self->fs_fd, 0); 1048 1049 self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 1050 MOUNT_ATTR_NOSUID); 1051 if (self->fd < 0 && errno == EINVAL) 1052 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 1053 1054 ASSERT_GE(self->fd, 0); 1055 1056 ret = get_mnt_ns_id(self->fd, &new_ns_id); 1057 ASSERT_EQ(ret, 0); 1058 1059 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 1060 ASSERT_GE(nr_mounts, 1); 1061 1062 ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 1063 ASSERT_EQ(ret, 0); 1064 1065 /* Verify the mount is nosuid */ 1066 ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOSUID); 1067 } 1068 1069 TEST_F(fsmount_ns_mount_attrs, noatime) 1070 { 1071 struct statmount sm; 1072 uint64_t new_ns_id; 1073 uint64_t list[256]; 1074 ssize_t nr_mounts; 1075 int ret; 1076 1077 self->fs_fd = create_tmpfs_fd(); 1078 ASSERT_GE(self->fs_fd, 0); 1079 1080 self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 1081 MOUNT_ATTR_NOATIME); 1082 if (self->fd < 0 && errno == EINVAL) 1083 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 1084 1085 ASSERT_GE(self->fd, 0); 1086 1087 ret = get_mnt_ns_id(self->fd, &new_ns_id); 1088 ASSERT_EQ(ret, 0); 1089 1090 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 1091 ASSERT_GE(nr_mounts, 1); 1092 1093 ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 1094 ASSERT_EQ(ret, 0); 1095 1096 /* Verify the mount is noatime */ 1097 ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOATIME); 1098 } 1099 1100 TEST_F(fsmount_ns_mount_attrs, combined) 1101 { 1102 struct statmount sm; 1103 uint64_t new_ns_id; 1104 uint64_t list[256]; 1105 ssize_t nr_mounts; 1106 int ret; 1107 1108 self->fs_fd = create_tmpfs_fd(); 1109 ASSERT_GE(self->fs_fd, 0); 1110 1111 self->fd = sys_fsmount(self->fs_fd, FSMOUNT_NAMESPACE | FSMOUNT_CLOEXEC, 1112 MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | 1113 MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOATIME); 1114 if (self->fd < 0 && errno == EINVAL) 1115 SKIP(return, "FSMOUNT_NAMESPACE not supported"); 1116 1117 ASSERT_GE(self->fd, 0); 1118 1119 ret = get_mnt_ns_id(self->fd, &new_ns_id); 1120 ASSERT_EQ(ret, 0); 1121 1122 nr_mounts = listmount(LSMT_ROOT, new_ns_id, 0, list, 256, 0); 1123 ASSERT_GE(nr_mounts, 1); 1124 1125 ret = statmount(list[0], new_ns_id, 0, STATMOUNT_MNT_BASIC, &sm, sizeof(sm), 0); 1126 ASSERT_EQ(ret, 0); 1127 1128 /* Verify all attributes are set */ 1129 ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_RDONLY); 1130 ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOEXEC); 1131 ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOSUID); 1132 ASSERT_TRUE(sm.mnt_attr & MOUNT_ATTR_NOATIME); 1133 } 1134 1135 TEST_HARNESS_MAIN 1136