1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 #include <sched.h> 4 #include <stdio.h> 5 #include <errno.h> 6 #include <pthread.h> 7 #include <string.h> 8 #include <sys/stat.h> 9 #include <sys/types.h> 10 #include <sys/mount.h> 11 #include <sys/wait.h> 12 #include <sys/vfs.h> 13 #include <sys/statvfs.h> 14 #include <sys/sysinfo.h> 15 #include <stdlib.h> 16 #include <unistd.h> 17 #include <fcntl.h> 18 #include <grp.h> 19 #include <stdbool.h> 20 #include <stdarg.h> 21 #include <linux/mount.h> 22 23 #include "../filesystems/wrappers.h" 24 #include "../kselftest_harness.h" 25 26 #ifndef CLONE_NEWNS 27 #define CLONE_NEWNS 0x00020000 28 #endif 29 30 #ifndef CLONE_NEWUSER 31 #define CLONE_NEWUSER 0x10000000 32 #endif 33 34 #ifndef MS_REC 35 #define MS_REC 16384 36 #endif 37 38 #ifndef MS_RELATIME 39 #define MS_RELATIME (1 << 21) 40 #endif 41 42 #ifndef MS_STRICTATIME 43 #define MS_STRICTATIME (1 << 24) 44 #endif 45 46 #ifndef MOUNT_ATTR_RDONLY 47 #define MOUNT_ATTR_RDONLY 0x00000001 48 #endif 49 50 #ifndef MOUNT_ATTR_NOSUID 51 #define MOUNT_ATTR_NOSUID 0x00000002 52 #endif 53 54 #ifndef MOUNT_ATTR_NOEXEC 55 #define MOUNT_ATTR_NOEXEC 0x00000008 56 #endif 57 58 #ifndef MOUNT_ATTR_NODIRATIME 59 #define MOUNT_ATTR_NODIRATIME 0x00000080 60 #endif 61 62 #ifndef MOUNT_ATTR__ATIME 63 #define MOUNT_ATTR__ATIME 0x00000070 64 #endif 65 66 #ifndef MOUNT_ATTR_RELATIME 67 #define MOUNT_ATTR_RELATIME 0x00000000 68 #endif 69 70 #ifndef MOUNT_ATTR_NOATIME 71 #define MOUNT_ATTR_NOATIME 0x00000010 72 #endif 73 74 #ifndef MOUNT_ATTR_STRICTATIME 75 #define MOUNT_ATTR_STRICTATIME 0x00000020 76 #endif 77 78 #ifndef AT_RECURSIVE 79 #define AT_RECURSIVE 0x8000 80 #endif 81 82 #ifndef MS_SHARED 83 #define MS_SHARED (1 << 20) 84 #endif 85 86 #define DEFAULT_THREADS 4 87 #define ptr_to_int(p) ((int)((intptr_t)(p))) 88 #define int_to_ptr(u) ((void *)((intptr_t)(u))) 89 90 #ifndef __NR_mount_setattr 91 #if defined __alpha__ 92 #define __NR_mount_setattr 552 93 #elif defined _MIPS_SIM 94 #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ 95 #define __NR_mount_setattr (442 + 4000) 96 #endif 97 #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */ 98 #define __NR_mount_setattr (442 + 6000) 99 #endif 100 #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ 101 #define __NR_mount_setattr (442 + 5000) 102 #endif 103 #elif defined __ia64__ 104 #define __NR_mount_setattr (442 + 1024) 105 #else 106 #define __NR_mount_setattr 442 107 #endif 108 #endif 109 110 #ifndef __NR_open_tree_attr 111 #if defined __alpha__ 112 #define __NR_open_tree_attr 577 113 #elif defined _MIPS_SIM 114 #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ 115 #define __NR_open_tree_attr (467 + 4000) 116 #endif 117 #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */ 118 #define __NR_open_tree_attr (467 + 6000) 119 #endif 120 #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ 121 #define __NR_open_tree_attr (467 + 5000) 122 #endif 123 #elif defined __ia64__ 124 #define __NR_open_tree_attr (467 + 1024) 125 #else 126 #define __NR_open_tree_attr 467 127 #endif 128 #endif 129 130 #ifndef MOUNT_ATTR_IDMAP 131 #define MOUNT_ATTR_IDMAP 0x00100000 132 #endif 133 134 #ifndef MOUNT_ATTR_NOSYMFOLLOW 135 #define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 136 #endif 137 138 static inline int sys_mount_setattr(int dfd, const char *path, unsigned int flags, 139 struct mount_attr *attr, size_t size) 140 { 141 return syscall(__NR_mount_setattr, dfd, path, flags, attr, size); 142 } 143 144 static inline int sys_open_tree_attr(int dfd, const char *path, unsigned int flags, 145 struct mount_attr *attr, size_t size) 146 { 147 return syscall(__NR_open_tree_attr, dfd, path, flags, attr, size); 148 } 149 150 static ssize_t write_nointr(int fd, const void *buf, size_t count) 151 { 152 ssize_t ret; 153 154 do { 155 ret = write(fd, buf, count); 156 } while (ret < 0 && errno == EINTR); 157 158 return ret; 159 } 160 161 static int write_file(const char *path, const void *buf, size_t count) 162 { 163 int fd; 164 ssize_t ret; 165 166 fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW); 167 if (fd < 0) 168 return -1; 169 170 ret = write_nointr(fd, buf, count); 171 close(fd); 172 if (ret < 0 || (size_t)ret != count) 173 return -1; 174 175 return 0; 176 } 177 178 static int create_and_enter_userns(void) 179 { 180 uid_t uid; 181 gid_t gid; 182 char map[100]; 183 184 uid = getuid(); 185 gid = getgid(); 186 187 if (unshare(CLONE_NEWUSER)) 188 return -1; 189 190 if (write_file("/proc/self/setgroups", "deny", sizeof("deny") - 1) && 191 errno != ENOENT) 192 return -1; 193 194 snprintf(map, sizeof(map), "0 %d 1", uid); 195 if (write_file("/proc/self/uid_map", map, strlen(map))) 196 return -1; 197 198 199 snprintf(map, sizeof(map), "0 %d 1", gid); 200 if (write_file("/proc/self/gid_map", map, strlen(map))) 201 return -1; 202 203 if (setgid(0)) 204 return -1; 205 206 if (setuid(0)) 207 return -1; 208 209 return 0; 210 } 211 212 static int prepare_unpriv_mountns(void) 213 { 214 if (create_and_enter_userns()) 215 return -1; 216 217 if (unshare(CLONE_NEWNS)) 218 return -1; 219 220 if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0)) 221 return -1; 222 223 return 0; 224 } 225 226 #ifndef ST_NOSYMFOLLOW 227 #define ST_NOSYMFOLLOW 0x2000 /* do not follow symlinks */ 228 #endif 229 230 static int read_mnt_flags(const char *path) 231 { 232 int ret; 233 struct statvfs stat; 234 unsigned int mnt_flags; 235 236 ret = statvfs(path, &stat); 237 if (ret != 0) 238 return -EINVAL; 239 240 if (stat.f_flag & ~(ST_RDONLY | ST_NOSUID | ST_NODEV | ST_NOEXEC | 241 ST_NOATIME | ST_NODIRATIME | ST_RELATIME | 242 ST_SYNCHRONOUS | ST_MANDLOCK | ST_NOSYMFOLLOW)) 243 return -EINVAL; 244 245 mnt_flags = 0; 246 if (stat.f_flag & ST_RDONLY) 247 mnt_flags |= MS_RDONLY; 248 if (stat.f_flag & ST_NOSUID) 249 mnt_flags |= MS_NOSUID; 250 if (stat.f_flag & ST_NODEV) 251 mnt_flags |= MS_NODEV; 252 if (stat.f_flag & ST_NOEXEC) 253 mnt_flags |= MS_NOEXEC; 254 if (stat.f_flag & ST_NOATIME) 255 mnt_flags |= MS_NOATIME; 256 if (stat.f_flag & ST_NODIRATIME) 257 mnt_flags |= MS_NODIRATIME; 258 if (stat.f_flag & ST_RELATIME) 259 mnt_flags |= MS_RELATIME; 260 if (stat.f_flag & ST_SYNCHRONOUS) 261 mnt_flags |= MS_SYNCHRONOUS; 262 if (stat.f_flag & ST_MANDLOCK) 263 mnt_flags |= ST_MANDLOCK; 264 if (stat.f_flag & ST_NOSYMFOLLOW) 265 mnt_flags |= ST_NOSYMFOLLOW; 266 267 return mnt_flags; 268 } 269 270 static char *get_field(char *src, int nfields) 271 { 272 int i; 273 char *p = src; 274 275 for (i = 0; i < nfields; i++) { 276 while (*p && *p != ' ' && *p != '\t') 277 p++; 278 279 if (!*p) 280 break; 281 282 p++; 283 } 284 285 return p; 286 } 287 288 static void null_endofword(char *word) 289 { 290 while (*word && *word != ' ' && *word != '\t') 291 word++; 292 *word = '\0'; 293 } 294 295 static bool is_shared_mount(const char *path) 296 { 297 size_t len = 0; 298 char *line = NULL; 299 FILE *f = NULL; 300 301 f = fopen("/proc/self/mountinfo", "re"); 302 if (!f) 303 return false; 304 305 while (getline(&line, &len, f) != -1) { 306 char *opts, *target; 307 308 target = get_field(line, 4); 309 if (!target) 310 continue; 311 312 opts = get_field(target, 2); 313 if (!opts) 314 continue; 315 316 null_endofword(target); 317 318 if (strcmp(target, path) != 0) 319 continue; 320 321 null_endofword(opts); 322 if (strstr(opts, "shared:")) 323 return true; 324 } 325 326 free(line); 327 fclose(f); 328 329 return false; 330 } 331 332 static void *mount_setattr_thread(void *data) 333 { 334 struct mount_attr attr = { 335 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID, 336 .attr_clr = 0, 337 .propagation = MS_SHARED, 338 }; 339 340 if (sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr))) 341 pthread_exit(int_to_ptr(-1)); 342 343 pthread_exit(int_to_ptr(0)); 344 } 345 346 /* Attempt to de-conflict with the selftests tree. */ 347 #ifndef SKIP 348 #define SKIP(s, ...) XFAIL(s, ##__VA_ARGS__) 349 #endif 350 351 static bool mount_setattr_supported(void) 352 { 353 int ret; 354 355 ret = sys_mount_setattr(-EBADF, "", AT_EMPTY_PATH, NULL, 0); 356 if (ret < 0 && errno == ENOSYS) 357 return false; 358 359 return true; 360 } 361 362 FIXTURE(mount_setattr) { 363 }; 364 365 #define NOSYMFOLLOW_TARGET "/mnt/A/AA/data" 366 #define NOSYMFOLLOW_SYMLINK "/mnt/A/AA/symlink" 367 368 FIXTURE_SETUP(mount_setattr) 369 { 370 int fd = -EBADF; 371 372 if (!mount_setattr_supported()) 373 SKIP(return, "mount_setattr syscall not supported"); 374 375 ASSERT_EQ(prepare_unpriv_mountns(), 0); 376 377 (void)umount2("/mnt", MNT_DETACH); 378 (void)umount2("/tmp", MNT_DETACH); 379 380 ASSERT_EQ(mount("testing", "/tmp", "tmpfs", MS_NOATIME | MS_NODEV, 381 "size=100000,mode=700"), 0); 382 383 ASSERT_EQ(mkdir("/tmp/B", 0777), 0); 384 385 ASSERT_EQ(mount("testing", "/tmp/B", "tmpfs", MS_NOATIME | MS_NODEV, 386 "size=100000,mode=700"), 0); 387 388 ASSERT_EQ(mkdir("/tmp/B/BB", 0777), 0); 389 390 ASSERT_EQ(mkdir("/tmp/target1", 0777), 0); 391 392 ASSERT_EQ(mkdir("/tmp/target2", 0777), 0); 393 394 ASSERT_EQ(mount("testing", "/tmp/B/BB", "tmpfs", MS_NOATIME | MS_NODEV, 395 "size=100000,mode=700"), 0); 396 397 ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV, 398 "size=100000,mode=700"), 0); 399 400 ASSERT_EQ(mkdir("/mnt/A", 0777), 0); 401 402 ASSERT_EQ(mount("testing", "/mnt/A", "tmpfs", MS_NOATIME | MS_NODEV, 403 "size=100000,mode=700"), 0); 404 405 ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0); 406 407 ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0); 408 409 ASSERT_EQ(mkdir("/mnt/B", 0777), 0); 410 411 ASSERT_EQ(mount("testing", "/mnt/B", "ramfs", 412 MS_NOATIME | MS_NODEV | MS_NOSUID, 0), 0); 413 414 ASSERT_EQ(mkdir("/mnt/B/BB", 0777), 0); 415 416 ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts", 417 MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0); 418 419 fd = creat(NOSYMFOLLOW_TARGET, O_RDWR | O_CLOEXEC); 420 ASSERT_GT(fd, 0); 421 ASSERT_EQ(symlink(NOSYMFOLLOW_TARGET, NOSYMFOLLOW_SYMLINK), 0); 422 ASSERT_EQ(close(fd), 0); 423 } 424 425 FIXTURE_TEARDOWN(mount_setattr) 426 { 427 if (!mount_setattr_supported()) 428 SKIP(return, "mount_setattr syscall not supported"); 429 430 (void)umount2("/mnt/A", MNT_DETACH); 431 (void)umount2("/tmp", MNT_DETACH); 432 } 433 434 TEST_F(mount_setattr, invalid_attributes) 435 { 436 struct mount_attr invalid_attr = { 437 .attr_set = (1U << 31), 438 }; 439 440 if (!mount_setattr_supported()) 441 SKIP(return, "mount_setattr syscall not supported"); 442 443 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 444 sizeof(invalid_attr)), 0); 445 446 invalid_attr.attr_set = 0; 447 invalid_attr.attr_clr = (1U << 31); 448 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 449 sizeof(invalid_attr)), 0); 450 451 invalid_attr.attr_clr = 0; 452 invalid_attr.propagation = (1U << 31); 453 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 454 sizeof(invalid_attr)), 0); 455 456 invalid_attr.attr_set = (1U << 31); 457 invalid_attr.attr_clr = (1U << 31); 458 invalid_attr.propagation = (1U << 31); 459 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 460 sizeof(invalid_attr)), 0); 461 462 ASSERT_NE(sys_mount_setattr(-1, "mnt/A", AT_RECURSIVE, &invalid_attr, 463 sizeof(invalid_attr)), 0); 464 } 465 466 TEST_F(mount_setattr, extensibility) 467 { 468 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 469 char *s = "dummy"; 470 struct mount_attr invalid_attr = {}; 471 struct mount_attr_large { 472 struct mount_attr attr1; 473 struct mount_attr attr2; 474 struct mount_attr attr3; 475 } large_attr = {}; 476 477 if (!mount_setattr_supported()) 478 SKIP(return, "mount_setattr syscall not supported"); 479 480 old_flags = read_mnt_flags("/mnt/A"); 481 ASSERT_GT(old_flags, 0); 482 483 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, NULL, 484 sizeof(invalid_attr)), 0); 485 ASSERT_EQ(errno, EFAULT); 486 487 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, (void *)s, 488 sizeof(invalid_attr)), 0); 489 ASSERT_EQ(errno, EINVAL); 490 491 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 0), 0); 492 ASSERT_EQ(errno, EINVAL); 493 494 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 495 sizeof(invalid_attr) / 2), 0); 496 ASSERT_EQ(errno, EINVAL); 497 498 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 499 sizeof(invalid_attr) / 2), 0); 500 ASSERT_EQ(errno, EINVAL); 501 502 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, 503 (void *)&large_attr, sizeof(large_attr)), 0); 504 505 large_attr.attr3.attr_set = MOUNT_ATTR_RDONLY; 506 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, 507 (void *)&large_attr, sizeof(large_attr)), 0); 508 509 large_attr.attr3.attr_set = 0; 510 large_attr.attr1.attr_set = MOUNT_ATTR_RDONLY; 511 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, 512 (void *)&large_attr, sizeof(large_attr)), 0); 513 514 expected_flags = old_flags; 515 expected_flags |= MS_RDONLY; 516 517 new_flags = read_mnt_flags("/mnt/A"); 518 ASSERT_EQ(new_flags, expected_flags); 519 520 new_flags = read_mnt_flags("/mnt/A/AA"); 521 ASSERT_EQ(new_flags, expected_flags); 522 523 new_flags = read_mnt_flags("/mnt/A/AA/B"); 524 ASSERT_EQ(new_flags, expected_flags); 525 526 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 527 ASSERT_EQ(new_flags, expected_flags); 528 } 529 530 TEST_F(mount_setattr, basic) 531 { 532 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 533 struct mount_attr attr = { 534 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME, 535 .attr_clr = MOUNT_ATTR__ATIME, 536 }; 537 538 if (!mount_setattr_supported()) 539 SKIP(return, "mount_setattr syscall not supported"); 540 541 old_flags = read_mnt_flags("/mnt/A"); 542 ASSERT_GT(old_flags, 0); 543 544 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", 0, &attr, sizeof(attr)), 0); 545 546 expected_flags = old_flags; 547 expected_flags |= MS_RDONLY; 548 expected_flags |= MS_NOEXEC; 549 expected_flags &= ~MS_NOATIME; 550 expected_flags |= MS_RELATIME; 551 552 new_flags = read_mnt_flags("/mnt/A"); 553 ASSERT_EQ(new_flags, expected_flags); 554 555 new_flags = read_mnt_flags("/mnt/A/AA"); 556 ASSERT_EQ(new_flags, old_flags); 557 558 new_flags = read_mnt_flags("/mnt/A/AA/B"); 559 ASSERT_EQ(new_flags, old_flags); 560 561 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 562 ASSERT_EQ(new_flags, old_flags); 563 } 564 565 TEST_F(mount_setattr, basic_recursive) 566 { 567 int fd; 568 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 569 struct mount_attr attr = { 570 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME, 571 .attr_clr = MOUNT_ATTR__ATIME, 572 }; 573 574 if (!mount_setattr_supported()) 575 SKIP(return, "mount_setattr syscall not supported"); 576 577 old_flags = read_mnt_flags("/mnt/A"); 578 ASSERT_GT(old_flags, 0); 579 580 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 581 582 expected_flags = old_flags; 583 expected_flags |= MS_RDONLY; 584 expected_flags |= MS_NOEXEC; 585 expected_flags &= ~MS_NOATIME; 586 expected_flags |= MS_RELATIME; 587 588 new_flags = read_mnt_flags("/mnt/A"); 589 ASSERT_EQ(new_flags, expected_flags); 590 591 new_flags = read_mnt_flags("/mnt/A/AA"); 592 ASSERT_EQ(new_flags, expected_flags); 593 594 new_flags = read_mnt_flags("/mnt/A/AA/B"); 595 ASSERT_EQ(new_flags, expected_flags); 596 597 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 598 ASSERT_EQ(new_flags, expected_flags); 599 600 memset(&attr, 0, sizeof(attr)); 601 attr.attr_clr = MOUNT_ATTR_RDONLY; 602 attr.propagation = MS_SHARED; 603 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 604 605 expected_flags &= ~MS_RDONLY; 606 new_flags = read_mnt_flags("/mnt/A"); 607 ASSERT_EQ(new_flags, expected_flags); 608 609 ASSERT_EQ(is_shared_mount("/mnt/A"), true); 610 611 new_flags = read_mnt_flags("/mnt/A/AA"); 612 ASSERT_EQ(new_flags, expected_flags); 613 614 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true); 615 616 new_flags = read_mnt_flags("/mnt/A/AA/B"); 617 ASSERT_EQ(new_flags, expected_flags); 618 619 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true); 620 621 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 622 ASSERT_EQ(new_flags, expected_flags); 623 624 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true); 625 626 fd = open("/mnt/A/AA/B/b", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 0777); 627 ASSERT_GE(fd, 0); 628 629 /* 630 * We're holding a fd open for writing so this needs to fail somewhere 631 * in the middle and the mount options need to be unchanged. 632 */ 633 attr.attr_set = MOUNT_ATTR_RDONLY; 634 ASSERT_LT(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 635 636 new_flags = read_mnt_flags("/mnt/A"); 637 ASSERT_EQ(new_flags, expected_flags); 638 639 ASSERT_EQ(is_shared_mount("/mnt/A"), true); 640 641 new_flags = read_mnt_flags("/mnt/A/AA"); 642 ASSERT_EQ(new_flags, expected_flags); 643 644 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true); 645 646 new_flags = read_mnt_flags("/mnt/A/AA/B"); 647 ASSERT_EQ(new_flags, expected_flags); 648 649 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true); 650 651 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 652 ASSERT_EQ(new_flags, expected_flags); 653 654 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true); 655 656 EXPECT_EQ(close(fd), 0); 657 } 658 659 TEST_F(mount_setattr, mount_has_writers) 660 { 661 int fd, dfd; 662 unsigned int old_flags = 0, new_flags = 0; 663 struct mount_attr attr = { 664 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME, 665 .attr_clr = MOUNT_ATTR__ATIME, 666 .propagation = MS_SHARED, 667 }; 668 669 if (!mount_setattr_supported()) 670 SKIP(return, "mount_setattr syscall not supported"); 671 672 old_flags = read_mnt_flags("/mnt/A"); 673 ASSERT_GT(old_flags, 0); 674 675 fd = open("/mnt/A/AA/B/b", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 0777); 676 ASSERT_GE(fd, 0); 677 678 /* 679 * We're holding a fd open to a mount somwhere in the middle so this 680 * needs to fail somewhere in the middle. After this the mount options 681 * need to be unchanged. 682 */ 683 ASSERT_LT(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 684 685 new_flags = read_mnt_flags("/mnt/A"); 686 ASSERT_EQ(new_flags, old_flags); 687 688 ASSERT_EQ(is_shared_mount("/mnt/A"), false); 689 690 new_flags = read_mnt_flags("/mnt/A/AA"); 691 ASSERT_EQ(new_flags, old_flags); 692 693 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), false); 694 695 new_flags = read_mnt_flags("/mnt/A/AA/B"); 696 ASSERT_EQ(new_flags, old_flags); 697 698 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), false); 699 700 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 701 ASSERT_EQ(new_flags, old_flags); 702 703 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), false); 704 705 dfd = open("/mnt/A/AA/B", O_DIRECTORY | O_CLOEXEC); 706 ASSERT_GE(dfd, 0); 707 EXPECT_EQ(fsync(dfd), 0); 708 EXPECT_EQ(close(dfd), 0); 709 710 EXPECT_EQ(fsync(fd), 0); 711 EXPECT_EQ(close(fd), 0); 712 713 /* All writers are gone so this should succeed. */ 714 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 715 } 716 717 TEST_F(mount_setattr, mixed_mount_options) 718 { 719 unsigned int old_flags1 = 0, old_flags2 = 0, new_flags = 0, expected_flags = 0; 720 struct mount_attr attr = { 721 .attr_clr = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOEXEC | MOUNT_ATTR__ATIME, 722 .attr_set = MOUNT_ATTR_RELATIME, 723 }; 724 725 if (!mount_setattr_supported()) 726 SKIP(return, "mount_setattr syscall not supported"); 727 728 old_flags1 = read_mnt_flags("/mnt/B"); 729 ASSERT_GT(old_flags1, 0); 730 731 old_flags2 = read_mnt_flags("/mnt/B/BB"); 732 ASSERT_GT(old_flags2, 0); 733 734 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/B", AT_RECURSIVE, &attr, sizeof(attr)), 0); 735 736 expected_flags = old_flags2; 737 expected_flags &= ~(MS_RDONLY | MS_NOEXEC | MS_NOATIME | MS_NOSUID); 738 expected_flags |= MS_RELATIME; 739 740 new_flags = read_mnt_flags("/mnt/B"); 741 ASSERT_EQ(new_flags, expected_flags); 742 743 expected_flags = old_flags2; 744 expected_flags &= ~(MS_RDONLY | MS_NOEXEC | MS_NOATIME | MS_NOSUID); 745 expected_flags |= MS_RELATIME; 746 747 new_flags = read_mnt_flags("/mnt/B/BB"); 748 ASSERT_EQ(new_flags, expected_flags); 749 } 750 751 TEST_F(mount_setattr, time_changes) 752 { 753 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 754 struct mount_attr attr = { 755 .attr_set = MOUNT_ATTR_NODIRATIME | MOUNT_ATTR_NOATIME, 756 }; 757 758 if (!mount_setattr_supported()) 759 SKIP(return, "mount_setattr syscall not supported"); 760 761 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 762 763 attr.attr_set = MOUNT_ATTR_STRICTATIME; 764 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 765 766 attr.attr_set = MOUNT_ATTR_STRICTATIME | MOUNT_ATTR_NOATIME; 767 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 768 769 attr.attr_set = MOUNT_ATTR_STRICTATIME | MOUNT_ATTR_NOATIME; 770 attr.attr_clr = MOUNT_ATTR__ATIME; 771 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 772 773 attr.attr_set = 0; 774 attr.attr_clr = MOUNT_ATTR_STRICTATIME; 775 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 776 777 attr.attr_clr = MOUNT_ATTR_NOATIME; 778 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 779 780 old_flags = read_mnt_flags("/mnt/A"); 781 ASSERT_GT(old_flags, 0); 782 783 attr.attr_set = MOUNT_ATTR_NODIRATIME | MOUNT_ATTR_NOATIME; 784 attr.attr_clr = MOUNT_ATTR__ATIME; 785 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 786 787 expected_flags = old_flags; 788 expected_flags |= MS_NOATIME; 789 expected_flags |= MS_NODIRATIME; 790 791 new_flags = read_mnt_flags("/mnt/A"); 792 ASSERT_EQ(new_flags, expected_flags); 793 794 new_flags = read_mnt_flags("/mnt/A/AA"); 795 ASSERT_EQ(new_flags, expected_flags); 796 797 new_flags = read_mnt_flags("/mnt/A/AA/B"); 798 ASSERT_EQ(new_flags, expected_flags); 799 800 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 801 ASSERT_EQ(new_flags, expected_flags); 802 803 memset(&attr, 0, sizeof(attr)); 804 attr.attr_set &= ~MOUNT_ATTR_NOATIME; 805 attr.attr_set |= MOUNT_ATTR_RELATIME; 806 attr.attr_clr |= MOUNT_ATTR__ATIME; 807 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 808 809 expected_flags &= ~MS_NOATIME; 810 expected_flags |= MS_RELATIME; 811 812 new_flags = read_mnt_flags("/mnt/A"); 813 ASSERT_EQ(new_flags, expected_flags); 814 815 new_flags = read_mnt_flags("/mnt/A/AA"); 816 ASSERT_EQ(new_flags, expected_flags); 817 818 new_flags = read_mnt_flags("/mnt/A/AA/B"); 819 ASSERT_EQ(new_flags, expected_flags); 820 821 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 822 ASSERT_EQ(new_flags, expected_flags); 823 824 memset(&attr, 0, sizeof(attr)); 825 attr.attr_set &= ~MOUNT_ATTR_RELATIME; 826 attr.attr_set |= MOUNT_ATTR_STRICTATIME; 827 attr.attr_clr |= MOUNT_ATTR__ATIME; 828 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 829 830 expected_flags &= ~MS_RELATIME; 831 832 new_flags = read_mnt_flags("/mnt/A"); 833 ASSERT_EQ(new_flags, expected_flags); 834 835 new_flags = read_mnt_flags("/mnt/A/AA"); 836 ASSERT_EQ(new_flags, expected_flags); 837 838 new_flags = read_mnt_flags("/mnt/A/AA/B"); 839 ASSERT_EQ(new_flags, expected_flags); 840 841 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 842 ASSERT_EQ(new_flags, expected_flags); 843 844 memset(&attr, 0, sizeof(attr)); 845 attr.attr_set &= ~MOUNT_ATTR_STRICTATIME; 846 attr.attr_set |= MOUNT_ATTR_NOATIME; 847 attr.attr_clr |= MOUNT_ATTR__ATIME; 848 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 849 850 expected_flags |= MS_NOATIME; 851 new_flags = read_mnt_flags("/mnt/A"); 852 ASSERT_EQ(new_flags, expected_flags); 853 854 new_flags = read_mnt_flags("/mnt/A/AA"); 855 ASSERT_EQ(new_flags, expected_flags); 856 857 new_flags = read_mnt_flags("/mnt/A/AA/B"); 858 ASSERT_EQ(new_flags, expected_flags); 859 860 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 861 ASSERT_EQ(new_flags, expected_flags); 862 863 memset(&attr, 0, sizeof(attr)); 864 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 865 866 new_flags = read_mnt_flags("/mnt/A"); 867 ASSERT_EQ(new_flags, expected_flags); 868 869 new_flags = read_mnt_flags("/mnt/A/AA"); 870 ASSERT_EQ(new_flags, expected_flags); 871 872 new_flags = read_mnt_flags("/mnt/A/AA/B"); 873 ASSERT_EQ(new_flags, expected_flags); 874 875 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 876 ASSERT_EQ(new_flags, expected_flags); 877 878 memset(&attr, 0, sizeof(attr)); 879 attr.attr_clr = MOUNT_ATTR_NODIRATIME; 880 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 881 882 expected_flags &= ~MS_NODIRATIME; 883 884 new_flags = read_mnt_flags("/mnt/A"); 885 ASSERT_EQ(new_flags, expected_flags); 886 887 new_flags = read_mnt_flags("/mnt/A/AA"); 888 ASSERT_EQ(new_flags, expected_flags); 889 890 new_flags = read_mnt_flags("/mnt/A/AA/B"); 891 ASSERT_EQ(new_flags, expected_flags); 892 893 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 894 ASSERT_EQ(new_flags, expected_flags); 895 } 896 897 TEST_F(mount_setattr, multi_threaded) 898 { 899 int i, j, nthreads, ret = 0; 900 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 901 pthread_attr_t pattr; 902 pthread_t threads[DEFAULT_THREADS]; 903 904 if (!mount_setattr_supported()) 905 SKIP(return, "mount_setattr syscall not supported"); 906 907 old_flags = read_mnt_flags("/mnt/A"); 908 ASSERT_GT(old_flags, 0); 909 910 /* Try to change mount options from multiple threads. */ 911 nthreads = get_nprocs_conf(); 912 if (nthreads > DEFAULT_THREADS) 913 nthreads = DEFAULT_THREADS; 914 915 pthread_attr_init(&pattr); 916 for (i = 0; i < nthreads; i++) 917 ASSERT_EQ(pthread_create(&threads[i], &pattr, mount_setattr_thread, NULL), 0); 918 919 for (j = 0; j < i; j++) { 920 void *retptr = NULL; 921 922 EXPECT_EQ(pthread_join(threads[j], &retptr), 0); 923 924 ret += ptr_to_int(retptr); 925 EXPECT_EQ(ret, 0); 926 } 927 pthread_attr_destroy(&pattr); 928 929 ASSERT_EQ(ret, 0); 930 931 expected_flags = old_flags; 932 expected_flags |= MS_RDONLY; 933 expected_flags |= MS_NOSUID; 934 new_flags = read_mnt_flags("/mnt/A"); 935 ASSERT_EQ(new_flags, expected_flags); 936 937 ASSERT_EQ(is_shared_mount("/mnt/A"), true); 938 939 new_flags = read_mnt_flags("/mnt/A/AA"); 940 ASSERT_EQ(new_flags, expected_flags); 941 942 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true); 943 944 new_flags = read_mnt_flags("/mnt/A/AA/B"); 945 ASSERT_EQ(new_flags, expected_flags); 946 947 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true); 948 949 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 950 ASSERT_EQ(new_flags, expected_flags); 951 952 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true); 953 } 954 955 TEST_F(mount_setattr, wrong_user_namespace) 956 { 957 int ret; 958 struct mount_attr attr = { 959 .attr_set = MOUNT_ATTR_RDONLY, 960 }; 961 962 if (!mount_setattr_supported()) 963 SKIP(return, "mount_setattr syscall not supported"); 964 965 EXPECT_EQ(create_and_enter_userns(), 0); 966 ret = sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)); 967 ASSERT_LT(ret, 0); 968 ASSERT_EQ(errno, EPERM); 969 } 970 971 TEST_F(mount_setattr, wrong_mount_namespace) 972 { 973 int fd, ret; 974 struct mount_attr attr = { 975 .attr_set = MOUNT_ATTR_RDONLY, 976 }; 977 978 if (!mount_setattr_supported()) 979 SKIP(return, "mount_setattr syscall not supported"); 980 981 fd = open("/mnt/A", O_DIRECTORY | O_CLOEXEC); 982 ASSERT_GE(fd, 0); 983 984 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 985 986 ret = sys_mount_setattr(fd, "", AT_EMPTY_PATH | AT_RECURSIVE, &attr, sizeof(attr)); 987 ASSERT_LT(ret, 0); 988 ASSERT_EQ(errno, EINVAL); 989 } 990 991 FIXTURE(mount_setattr_idmapped) { 992 }; 993 994 FIXTURE_SETUP(mount_setattr_idmapped) 995 { 996 int img_fd = -EBADF; 997 998 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 999 1000 ASSERT_EQ(mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0), 0); 1001 1002 (void)umount2("/mnt", MNT_DETACH); 1003 (void)umount2("/tmp", MNT_DETACH); 1004 1005 ASSERT_EQ(mount("testing", "/tmp", "tmpfs", MS_NOATIME | MS_NODEV, 1006 "size=100000,mode=700"), 0); 1007 1008 ASSERT_EQ(mkdir("/tmp/B", 0777), 0); 1009 ASSERT_EQ(mknodat(-EBADF, "/tmp/B/b", S_IFREG | 0644, 0), 0); 1010 ASSERT_EQ(chown("/tmp/B/b", 0, 0), 0); 1011 1012 ASSERT_EQ(mount("testing", "/tmp/B", "tmpfs", MS_NOATIME | MS_NODEV, 1013 "size=100000,mode=700"), 0); 1014 1015 ASSERT_EQ(mkdir("/tmp/B/BB", 0777), 0); 1016 ASSERT_EQ(mknodat(-EBADF, "/tmp/B/BB/b", S_IFREG | 0644, 0), 0); 1017 ASSERT_EQ(chown("/tmp/B/BB/b", 0, 0), 0); 1018 1019 ASSERT_EQ(mount("testing", "/tmp/B/BB", "tmpfs", MS_NOATIME | MS_NODEV, 1020 "size=100000,mode=700"), 0); 1021 1022 ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV, 1023 "size=2m,mode=700"), 0); 1024 1025 ASSERT_EQ(mkdir("/mnt/A", 0777), 0); 1026 1027 ASSERT_EQ(mount("testing", "/mnt/A", "tmpfs", MS_NOATIME | MS_NODEV, 1028 "size=100000,mode=700"), 0); 1029 1030 ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0); 1031 1032 ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0); 1033 1034 ASSERT_EQ(mkdir("/mnt/B", 0777), 0); 1035 1036 ASSERT_EQ(mount("testing", "/mnt/B", "ramfs", 1037 MS_NOATIME | MS_NODEV | MS_NOSUID, 0), 0); 1038 1039 ASSERT_EQ(mkdir("/mnt/B/BB", 0777), 0); 1040 1041 ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts", 1042 MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0); 1043 1044 ASSERT_EQ(mkdir("/mnt/C", 0777), 0); 1045 ASSERT_EQ(mkdir("/mnt/D", 0777), 0); 1046 img_fd = openat(-EBADF, "/mnt/C/ext4.img", O_CREAT | O_WRONLY, 0600); 1047 ASSERT_GE(img_fd, 0); 1048 ASSERT_EQ(ftruncate(img_fd, 2147483648 /* 2 GB */), 0); 1049 ASSERT_EQ(system("mkfs.ext4 -q /mnt/C/ext4.img"), 0); 1050 ASSERT_EQ(system("mount -o loop -t ext4 /mnt/C/ext4.img /mnt/D/"), 0); 1051 ASSERT_EQ(close(img_fd), 0); 1052 } 1053 1054 FIXTURE_TEARDOWN(mount_setattr_idmapped) 1055 { 1056 (void)umount2("/mnt/A", MNT_DETACH); 1057 (void)umount2("/tmp", MNT_DETACH); 1058 } 1059 1060 /** 1061 * Validate that negative fd values are rejected. 1062 */ 1063 TEST_F(mount_setattr_idmapped, invalid_fd_negative) 1064 { 1065 struct mount_attr attr = { 1066 .attr_set = MOUNT_ATTR_IDMAP, 1067 .userns_fd = -EBADF, 1068 }; 1069 1070 if (!mount_setattr_supported()) 1071 SKIP(return, "mount_setattr syscall not supported"); 1072 1073 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) { 1074 TH_LOG("failure: created idmapped mount with negative fd"); 1075 } 1076 } 1077 1078 /** 1079 * Validate that excessively large fd values are rejected. 1080 */ 1081 TEST_F(mount_setattr_idmapped, invalid_fd_large) 1082 { 1083 struct mount_attr attr = { 1084 .attr_set = MOUNT_ATTR_IDMAP, 1085 .userns_fd = INT64_MAX, 1086 }; 1087 1088 if (!mount_setattr_supported()) 1089 SKIP(return, "mount_setattr syscall not supported"); 1090 1091 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) { 1092 TH_LOG("failure: created idmapped mount with too large fd value"); 1093 } 1094 } 1095 1096 /** 1097 * Validate that closed fd values are rejected. 1098 */ 1099 TEST_F(mount_setattr_idmapped, invalid_fd_closed) 1100 { 1101 int fd; 1102 struct mount_attr attr = { 1103 .attr_set = MOUNT_ATTR_IDMAP, 1104 }; 1105 1106 if (!mount_setattr_supported()) 1107 SKIP(return, "mount_setattr syscall not supported"); 1108 1109 fd = open("/dev/null", O_RDONLY | O_CLOEXEC); 1110 ASSERT_GE(fd, 0); 1111 ASSERT_GE(close(fd), 0); 1112 1113 attr.userns_fd = fd; 1114 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) { 1115 TH_LOG("failure: created idmapped mount with closed fd"); 1116 } 1117 } 1118 1119 /** 1120 * Validate that the initial user namespace is rejected. 1121 */ 1122 TEST_F(mount_setattr_idmapped, invalid_fd_initial_userns) 1123 { 1124 int open_tree_fd = -EBADF; 1125 struct mount_attr attr = { 1126 .attr_set = MOUNT_ATTR_IDMAP, 1127 }; 1128 1129 if (!mount_setattr_supported()) 1130 SKIP(return, "mount_setattr syscall not supported"); 1131 1132 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D", 1133 AT_NO_AUTOMOUNT | 1134 AT_SYMLINK_NOFOLLOW | 1135 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE); 1136 ASSERT_GE(open_tree_fd, 0); 1137 1138 attr.userns_fd = open("/proc/1/ns/user", O_RDONLY | O_CLOEXEC); 1139 ASSERT_GE(attr.userns_fd, 0); 1140 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1141 ASSERT_EQ(errno, EPERM); 1142 ASSERT_EQ(close(attr.userns_fd), 0); 1143 ASSERT_EQ(close(open_tree_fd), 0); 1144 } 1145 1146 static int map_ids(pid_t pid, unsigned long nsid, unsigned long hostid, 1147 unsigned long range) 1148 { 1149 char map[100], procfile[256]; 1150 1151 snprintf(procfile, sizeof(procfile), "/proc/%d/uid_map", pid); 1152 snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range); 1153 if (write_file(procfile, map, strlen(map))) 1154 return -1; 1155 1156 1157 snprintf(procfile, sizeof(procfile), "/proc/%d/gid_map", pid); 1158 snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range); 1159 if (write_file(procfile, map, strlen(map))) 1160 return -1; 1161 1162 return 0; 1163 } 1164 1165 #define __STACK_SIZE (8 * 1024 * 1024) 1166 static pid_t do_clone(int (*fn)(void *), void *arg, int flags) 1167 { 1168 void *stack; 1169 1170 stack = malloc(__STACK_SIZE); 1171 if (!stack) 1172 return -ENOMEM; 1173 1174 #ifdef __ia64__ 1175 return __clone2(fn, stack, __STACK_SIZE, flags | SIGCHLD, arg, NULL); 1176 #else 1177 return clone(fn, stack + __STACK_SIZE, flags | SIGCHLD, arg, NULL); 1178 #endif 1179 } 1180 1181 static int get_userns_fd_cb(void *data) 1182 { 1183 return kill(getpid(), SIGSTOP); 1184 } 1185 1186 static int wait_for_pid(pid_t pid) 1187 { 1188 int status, ret; 1189 1190 again: 1191 ret = waitpid(pid, &status, 0); 1192 if (ret == -1) { 1193 if (errno == EINTR) 1194 goto again; 1195 1196 return -1; 1197 } 1198 1199 if (!WIFEXITED(status)) 1200 return -1; 1201 1202 return WEXITSTATUS(status); 1203 } 1204 1205 static int get_userns_fd(unsigned long nsid, unsigned long hostid, unsigned long range) 1206 { 1207 int ret; 1208 pid_t pid; 1209 char path[256]; 1210 1211 pid = do_clone(get_userns_fd_cb, NULL, CLONE_NEWUSER); 1212 if (pid < 0) 1213 return -errno; 1214 1215 ret = map_ids(pid, nsid, hostid, range); 1216 if (ret < 0) 1217 return ret; 1218 1219 snprintf(path, sizeof(path), "/proc/%d/ns/user", pid); 1220 ret = open(path, O_RDONLY | O_CLOEXEC); 1221 kill(pid, SIGKILL); 1222 wait_for_pid(pid); 1223 return ret; 1224 } 1225 1226 /** 1227 * Validate that an attached mount in our mount namespace cannot be idmapped. 1228 * (The kernel enforces that the mount's mount namespace and the caller's mount 1229 * namespace match.) 1230 */ 1231 TEST_F(mount_setattr_idmapped, attached_mount_inside_current_mount_namespace) 1232 { 1233 int open_tree_fd = -EBADF; 1234 struct mount_attr attr = { 1235 .attr_set = MOUNT_ATTR_IDMAP, 1236 }; 1237 1238 if (!mount_setattr_supported()) 1239 SKIP(return, "mount_setattr syscall not supported"); 1240 1241 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D", 1242 AT_EMPTY_PATH | 1243 AT_NO_AUTOMOUNT | 1244 AT_SYMLINK_NOFOLLOW | 1245 OPEN_TREE_CLOEXEC); 1246 ASSERT_GE(open_tree_fd, 0); 1247 1248 attr.userns_fd = get_userns_fd(0, 10000, 10000); 1249 ASSERT_GE(attr.userns_fd, 0); 1250 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1251 /* 1252 * Make sure that open_tree_attr() without OPEN_TREE_CLONE is not a way 1253 * to bypass this mount_setattr() restriction. 1254 */ 1255 ASSERT_LT(sys_open_tree_attr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1256 1257 ASSERT_EQ(close(attr.userns_fd), 0); 1258 ASSERT_EQ(close(open_tree_fd), 0); 1259 } 1260 1261 /** 1262 * Validate that idmapping a mount is rejected if the mount's mount namespace 1263 * and our mount namespace don't match. 1264 * (The kernel enforces that the mount's mount namespace and the caller's mount 1265 * namespace match.) 1266 */ 1267 TEST_F(mount_setattr_idmapped, attached_mount_outside_current_mount_namespace) 1268 { 1269 int open_tree_fd = -EBADF; 1270 struct mount_attr attr = { 1271 .attr_set = MOUNT_ATTR_IDMAP, 1272 }; 1273 1274 if (!mount_setattr_supported()) 1275 SKIP(return, "mount_setattr syscall not supported"); 1276 1277 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D", 1278 AT_EMPTY_PATH | 1279 AT_NO_AUTOMOUNT | 1280 AT_SYMLINK_NOFOLLOW | 1281 OPEN_TREE_CLOEXEC); 1282 ASSERT_GE(open_tree_fd, 0); 1283 1284 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 1285 1286 attr.userns_fd = get_userns_fd(0, 10000, 10000); 1287 ASSERT_GE(attr.userns_fd, 0); 1288 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, 1289 sizeof(attr)), 0); 1290 /* 1291 * Make sure that open_tree_attr() without OPEN_TREE_CLONE is not a way 1292 * to bypass this mount_setattr() restriction. 1293 */ 1294 ASSERT_LT(sys_open_tree_attr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1295 1296 ASSERT_EQ(close(attr.userns_fd), 0); 1297 ASSERT_EQ(close(open_tree_fd), 0); 1298 } 1299 1300 /** 1301 * Validate that an attached mount in our mount namespace can be idmapped. 1302 */ 1303 TEST_F(mount_setattr_idmapped, detached_mount_inside_current_mount_namespace) 1304 { 1305 int open_tree_fd = -EBADF; 1306 struct mount_attr attr = { 1307 .attr_set = MOUNT_ATTR_IDMAP, 1308 }; 1309 1310 if (!mount_setattr_supported()) 1311 SKIP(return, "mount_setattr syscall not supported"); 1312 1313 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D", 1314 AT_EMPTY_PATH | 1315 AT_NO_AUTOMOUNT | 1316 AT_SYMLINK_NOFOLLOW | 1317 OPEN_TREE_CLOEXEC | 1318 OPEN_TREE_CLONE); 1319 ASSERT_GE(open_tree_fd, 0); 1320 1321 /* Changing mount properties on a detached mount. */ 1322 attr.userns_fd = get_userns_fd(0, 10000, 10000); 1323 ASSERT_GE(attr.userns_fd, 0); 1324 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "", 1325 AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1326 ASSERT_EQ(close(attr.userns_fd), 0); 1327 ASSERT_EQ(close(open_tree_fd), 0); 1328 } 1329 1330 /** 1331 * Validate that a detached mount not in our mount namespace can be idmapped. 1332 */ 1333 TEST_F(mount_setattr_idmapped, detached_mount_outside_current_mount_namespace) 1334 { 1335 int open_tree_fd = -EBADF; 1336 struct mount_attr attr = { 1337 .attr_set = MOUNT_ATTR_IDMAP, 1338 }; 1339 1340 if (!mount_setattr_supported()) 1341 SKIP(return, "mount_setattr syscall not supported"); 1342 1343 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D", 1344 AT_EMPTY_PATH | 1345 AT_NO_AUTOMOUNT | 1346 AT_SYMLINK_NOFOLLOW | 1347 OPEN_TREE_CLOEXEC | 1348 OPEN_TREE_CLONE); 1349 ASSERT_GE(open_tree_fd, 0); 1350 1351 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 1352 1353 /* Changing mount properties on a detached mount. */ 1354 attr.userns_fd = get_userns_fd(0, 10000, 10000); 1355 ASSERT_GE(attr.userns_fd, 0); 1356 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "", 1357 AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1358 ASSERT_EQ(close(attr.userns_fd), 0); 1359 ASSERT_EQ(close(open_tree_fd), 0); 1360 } 1361 1362 static bool expected_uid_gid(int dfd, const char *path, int flags, 1363 uid_t expected_uid, gid_t expected_gid) 1364 { 1365 int ret; 1366 struct stat st; 1367 1368 ret = fstatat(dfd, path, &st, flags); 1369 if (ret < 0) 1370 return false; 1371 1372 return st.st_uid == expected_uid && st.st_gid == expected_gid; 1373 } 1374 1375 /** 1376 * Validate that currently changing the idmapping of an idmapped mount fails. 1377 */ 1378 TEST_F(mount_setattr_idmapped, change_idmapping) 1379 { 1380 int open_tree_fd = -EBADF; 1381 struct mount_attr attr = { 1382 .attr_set = MOUNT_ATTR_IDMAP, 1383 }; 1384 1385 ASSERT_TRUE(expected_uid_gid(-EBADF, "/mnt/D", 0, 0, 0)); 1386 1387 if (!mount_setattr_supported()) 1388 SKIP(return, "mount_setattr syscall not supported"); 1389 1390 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D", 1391 AT_EMPTY_PATH | 1392 AT_NO_AUTOMOUNT | 1393 AT_SYMLINK_NOFOLLOW | 1394 OPEN_TREE_CLOEXEC | 1395 OPEN_TREE_CLONE); 1396 ASSERT_GE(open_tree_fd, 0); 1397 1398 attr.userns_fd = get_userns_fd(0, 10000, 10000); 1399 ASSERT_GE(attr.userns_fd, 0); 1400 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "", 1401 AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1402 ASSERT_EQ(close(attr.userns_fd), 0); 1403 1404 EXPECT_FALSE(expected_uid_gid(open_tree_fd, ".", 0, 0, 0)); 1405 EXPECT_TRUE(expected_uid_gid(open_tree_fd, ".", 0, 10000, 10000)); 1406 1407 /* Change idmapping on a detached mount that is already idmapped. */ 1408 attr.userns_fd = get_userns_fd(0, 20000, 10000); 1409 ASSERT_GE(attr.userns_fd, 0); 1410 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1411 /* 1412 * Make sure that open_tree_attr() without OPEN_TREE_CLONE is not a way 1413 * to bypass this mount_setattr() restriction. 1414 */ 1415 EXPECT_LT(sys_open_tree_attr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1416 EXPECT_FALSE(expected_uid_gid(open_tree_fd, ".", 0, 20000, 20000)); 1417 EXPECT_TRUE(expected_uid_gid(open_tree_fd, ".", 0, 10000, 10000)); 1418 1419 ASSERT_EQ(close(attr.userns_fd), 0); 1420 ASSERT_EQ(close(open_tree_fd), 0); 1421 } 1422 1423 TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid) 1424 { 1425 int open_tree_fd = -EBADF; 1426 struct mount_attr attr = { 1427 .attr_set = MOUNT_ATTR_IDMAP, 1428 }; 1429 1430 if (!mount_setattr_supported()) 1431 SKIP(return, "mount_setattr syscall not supported"); 1432 1433 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0); 1434 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0); 1435 1436 ASSERT_EQ(mount("testing", "/mnt/A", "ramfs", MS_NOATIME | MS_NODEV, 1437 "size=100000,mode=700"), 0); 1438 1439 ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0); 1440 1441 ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0); 1442 1443 open_tree_fd = sys_open_tree(-EBADF, "/mnt/A", 1444 AT_RECURSIVE | 1445 AT_EMPTY_PATH | 1446 AT_NO_AUTOMOUNT | 1447 AT_SYMLINK_NOFOLLOW | 1448 OPEN_TREE_CLOEXEC | 1449 OPEN_TREE_CLONE); 1450 ASSERT_GE(open_tree_fd, 0); 1451 1452 attr.userns_fd = get_userns_fd(0, 10000, 10000); 1453 ASSERT_GE(attr.userns_fd, 0); 1454 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1455 ASSERT_EQ(close(attr.userns_fd), 0); 1456 ASSERT_EQ(close(open_tree_fd), 0); 1457 1458 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0); 1459 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0); 1460 ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/b", 0, 0, 0), 0); 1461 ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/BB/b", 0, 0, 0), 0); 1462 1463 (void)umount2("/mnt/A", MNT_DETACH); 1464 } 1465 1466 TEST_F(mount_setattr, mount_attr_nosymfollow) 1467 { 1468 int fd; 1469 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 1470 struct mount_attr attr = { 1471 .attr_set = MOUNT_ATTR_NOSYMFOLLOW, 1472 }; 1473 1474 if (!mount_setattr_supported()) 1475 SKIP(return, "mount_setattr syscall not supported"); 1476 1477 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC); 1478 ASSERT_GT(fd, 0); 1479 ASSERT_EQ(close(fd), 0); 1480 1481 old_flags = read_mnt_flags("/mnt/A"); 1482 ASSERT_GT(old_flags, 0); 1483 1484 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 1485 1486 expected_flags = old_flags; 1487 expected_flags |= ST_NOSYMFOLLOW; 1488 1489 new_flags = read_mnt_flags("/mnt/A"); 1490 ASSERT_EQ(new_flags, expected_flags); 1491 1492 new_flags = read_mnt_flags("/mnt/A/AA"); 1493 ASSERT_EQ(new_flags, expected_flags); 1494 1495 new_flags = read_mnt_flags("/mnt/A/AA/B"); 1496 ASSERT_EQ(new_flags, expected_flags); 1497 1498 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 1499 ASSERT_EQ(new_flags, expected_flags); 1500 1501 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC); 1502 ASSERT_LT(fd, 0); 1503 ASSERT_EQ(errno, ELOOP); 1504 1505 attr.attr_set &= ~MOUNT_ATTR_NOSYMFOLLOW; 1506 attr.attr_clr |= MOUNT_ATTR_NOSYMFOLLOW; 1507 1508 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 1509 1510 expected_flags &= ~ST_NOSYMFOLLOW; 1511 new_flags = read_mnt_flags("/mnt/A"); 1512 ASSERT_EQ(new_flags, expected_flags); 1513 1514 new_flags = read_mnt_flags("/mnt/A/AA"); 1515 ASSERT_EQ(new_flags, expected_flags); 1516 1517 new_flags = read_mnt_flags("/mnt/A/AA/B"); 1518 ASSERT_EQ(new_flags, expected_flags); 1519 1520 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 1521 ASSERT_EQ(new_flags, expected_flags); 1522 1523 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC); 1524 ASSERT_GT(fd, 0); 1525 ASSERT_EQ(close(fd), 0); 1526 } 1527 1528 TEST_F(mount_setattr, open_tree_detached) 1529 { 1530 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF; 1531 struct statx stx; 1532 1533 fd_tree_base = sys_open_tree(-EBADF, "/mnt", 1534 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1535 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1536 OPEN_TREE_CLONE); 1537 ASSERT_GE(fd_tree_base, 0); 1538 /* 1539 * /mnt testing tmpfs 1540 * |-/mnt/A testing tmpfs 1541 * | `-/mnt/A/AA testing tmpfs 1542 * | `-/mnt/A/AA/B testing tmpfs 1543 * | `-/mnt/A/AA/B/BB testing tmpfs 1544 * `-/mnt/B testing ramfs 1545 */ 1546 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0); 1547 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1548 ASSERT_EQ(statx(fd_tree_base, "A/AA", 0, 0, &stx), 0); 1549 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1550 ASSERT_EQ(statx(fd_tree_base, "A/AA/B", 0, 0, &stx), 0); 1551 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1552 ASSERT_EQ(statx(fd_tree_base, "A/AA/B/BB", 0, 0, &stx), 0); 1553 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1554 1555 fd_tree_subdir = sys_open_tree(fd_tree_base, "A/AA", 1556 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1557 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1558 OPEN_TREE_CLONE); 1559 ASSERT_GE(fd_tree_subdir, 0); 1560 /* 1561 * /AA testing tmpfs 1562 * `-/AA/B testing tmpfs 1563 * `-/AA/B/BB testing tmpfs 1564 */ 1565 ASSERT_EQ(statx(fd_tree_subdir, "B", 0, 0, &stx), 0); 1566 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1567 ASSERT_EQ(statx(fd_tree_subdir, "B/BB", 0, 0, &stx), 0); 1568 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1569 1570 ASSERT_EQ(move_mount(fd_tree_subdir, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0); 1571 /* 1572 * /tmp/target1 testing tmpfs 1573 * `-/tmp/target1/B testing tmpfs 1574 * `-/tmp/target1/B/BB testing tmpfs 1575 */ 1576 ASSERT_EQ(statx(-EBADF, "/tmp/target1", 0, 0, &stx), 0); 1577 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1578 ASSERT_EQ(statx(-EBADF, "/tmp/target1/B", 0, 0, &stx), 0); 1579 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1580 ASSERT_EQ(statx(-EBADF, "/tmp/target1/B/BB", 0, 0, &stx), 0); 1581 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1582 1583 ASSERT_EQ(move_mount(fd_tree_base, "", -EBADF, "/tmp/target2", MOVE_MOUNT_F_EMPTY_PATH), 0); 1584 /* 1585 * /tmp/target2 testing tmpfs 1586 * |-/tmp/target2/A testing tmpfs 1587 * | `-/tmp/target2/A/AA testing tmpfs 1588 * | `-/tmp/target2/A/AA/B testing tmpfs 1589 * | `-/tmp/target2/A/AA/B/BB testing tmpfs 1590 * `-/tmp/target2/B testing ramfs 1591 */ 1592 ASSERT_EQ(statx(-EBADF, "/tmp/target2", 0, 0, &stx), 0); 1593 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1594 ASSERT_EQ(statx(-EBADF, "/tmp/target2/A", 0, 0, &stx), 0); 1595 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1596 ASSERT_EQ(statx(-EBADF, "/tmp/target2/A/AA", 0, 0, &stx), 0); 1597 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1598 ASSERT_EQ(statx(-EBADF, "/tmp/target2/A/AA/B", 0, 0, &stx), 0); 1599 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1600 ASSERT_EQ(statx(-EBADF, "/tmp/target2/A/AA/B/BB", 0, 0, &stx), 0); 1601 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1602 ASSERT_EQ(statx(-EBADF, "/tmp/target2/B", 0, 0, &stx), 0); 1603 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1604 1605 EXPECT_EQ(close(fd_tree_base), 0); 1606 EXPECT_EQ(close(fd_tree_subdir), 0); 1607 } 1608 1609 TEST_F(mount_setattr, open_tree_detached_fail) 1610 { 1611 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF; 1612 struct statx stx; 1613 1614 fd_tree_base = sys_open_tree(-EBADF, "/mnt", 1615 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1616 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1617 OPEN_TREE_CLONE); 1618 ASSERT_GE(fd_tree_base, 0); 1619 /* 1620 * /mnt testing tmpfs 1621 * |-/mnt/A testing tmpfs 1622 * | `-/mnt/A/AA testing tmpfs 1623 * | `-/mnt/A/AA/B testing tmpfs 1624 * | `-/mnt/A/AA/B/BB testing tmpfs 1625 * `-/mnt/B testing ramfs 1626 */ 1627 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0); 1628 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1629 ASSERT_EQ(statx(fd_tree_base, "A/AA", 0, 0, &stx), 0); 1630 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1631 ASSERT_EQ(statx(fd_tree_base, "A/AA/B", 0, 0, &stx), 0); 1632 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1633 ASSERT_EQ(statx(fd_tree_base, "A/AA/B/BB", 0, 0, &stx), 0); 1634 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1635 1636 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 1637 1638 /* 1639 * The origin mount namespace of the anonymous mount namespace 1640 * of @fd_tree_base doesn't match the caller's mount namespace 1641 * anymore so creation of another detached mounts must fail. 1642 */ 1643 fd_tree_subdir = sys_open_tree(fd_tree_base, "A/AA", 1644 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1645 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1646 OPEN_TREE_CLONE); 1647 ASSERT_LT(fd_tree_subdir, 0); 1648 ASSERT_EQ(errno, EINVAL); 1649 } 1650 1651 TEST_F(mount_setattr, open_tree_detached_fail2) 1652 { 1653 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF; 1654 struct statx stx; 1655 1656 fd_tree_base = sys_open_tree(-EBADF, "/mnt", 1657 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1658 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1659 OPEN_TREE_CLONE); 1660 ASSERT_GE(fd_tree_base, 0); 1661 /* 1662 * /mnt testing tmpfs 1663 * |-/mnt/A testing tmpfs 1664 * | `-/mnt/A/AA testing tmpfs 1665 * | `-/mnt/A/AA/B testing tmpfs 1666 * | `-/mnt/A/AA/B/BB testing tmpfs 1667 * `-/mnt/B testing ramfs 1668 */ 1669 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0); 1670 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1671 ASSERT_EQ(statx(fd_tree_base, "A/AA", 0, 0, &stx), 0); 1672 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1673 ASSERT_EQ(statx(fd_tree_base, "A/AA/B", 0, 0, &stx), 0); 1674 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1675 ASSERT_EQ(statx(fd_tree_base, "A/AA/B/BB", 0, 0, &stx), 0); 1676 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1677 1678 EXPECT_EQ(create_and_enter_userns(), 0); 1679 1680 /* 1681 * The caller entered a new user namespace. They will have 1682 * CAP_SYS_ADMIN in this user namespace. However, they're still 1683 * located in a mount namespace that is owned by an ancestor 1684 * user namespace in which they hold no privilege. Creating a 1685 * detached mount must thus fail. 1686 */ 1687 fd_tree_subdir = sys_open_tree(fd_tree_base, "A/AA", 1688 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1689 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1690 OPEN_TREE_CLONE); 1691 ASSERT_LT(fd_tree_subdir, 0); 1692 ASSERT_EQ(errno, EPERM); 1693 } 1694 1695 TEST_F(mount_setattr, open_tree_detached_fail3) 1696 { 1697 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF; 1698 struct statx stx; 1699 1700 fd_tree_base = sys_open_tree(-EBADF, "/mnt", 1701 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1702 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1703 OPEN_TREE_CLONE); 1704 ASSERT_GE(fd_tree_base, 0); 1705 /* 1706 * /mnt testing tmpfs 1707 * |-/mnt/A testing tmpfs 1708 * | `-/mnt/A/AA testing tmpfs 1709 * | `-/mnt/A/AA/B testing tmpfs 1710 * | `-/mnt/A/AA/B/BB testing tmpfs 1711 * `-/mnt/B testing ramfs 1712 */ 1713 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0); 1714 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1715 ASSERT_EQ(statx(fd_tree_base, "A/AA", 0, 0, &stx), 0); 1716 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1717 ASSERT_EQ(statx(fd_tree_base, "A/AA/B", 0, 0, &stx), 0); 1718 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1719 ASSERT_EQ(statx(fd_tree_base, "A/AA/B/BB", 0, 0, &stx), 0); 1720 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1721 1722 EXPECT_EQ(prepare_unpriv_mountns(), 0); 1723 1724 /* 1725 * The caller entered a new mount namespace. They will have 1726 * CAP_SYS_ADMIN in the owning user namespace of their mount 1727 * namespace. 1728 * 1729 * However, the origin mount namespace of the anonymous mount 1730 * namespace of @fd_tree_base doesn't match the caller's mount 1731 * namespace anymore so creation of another detached mounts must 1732 * fail. 1733 */ 1734 fd_tree_subdir = sys_open_tree(fd_tree_base, "A/AA", 1735 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1736 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1737 OPEN_TREE_CLONE); 1738 ASSERT_LT(fd_tree_subdir, 0); 1739 ASSERT_EQ(errno, EINVAL); 1740 } 1741 1742 TEST_F(mount_setattr, open_tree_subfolder) 1743 { 1744 int fd_context, fd_tmpfs, fd_tree; 1745 1746 fd_context = sys_fsopen("tmpfs", 0); 1747 ASSERT_GE(fd_context, 0); 1748 1749 ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0); 1750 1751 fd_tmpfs = sys_fsmount(fd_context, 0, 0); 1752 ASSERT_GE(fd_tmpfs, 0); 1753 1754 EXPECT_EQ(close(fd_context), 0); 1755 1756 ASSERT_EQ(mkdirat(fd_tmpfs, "subdir", 0755), 0); 1757 1758 fd_tree = sys_open_tree(fd_tmpfs, "subdir", 1759 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1760 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1761 OPEN_TREE_CLONE); 1762 ASSERT_GE(fd_tree, 0); 1763 1764 EXPECT_EQ(close(fd_tmpfs), 0); 1765 1766 ASSERT_EQ(mkdirat(-EBADF, "/mnt/open_tree_subfolder", 0755), 0); 1767 1768 ASSERT_EQ(sys_move_mount(fd_tree, "", -EBADF, "/mnt/open_tree_subfolder", MOVE_MOUNT_F_EMPTY_PATH), 0); 1769 1770 EXPECT_EQ(close(fd_tree), 0); 1771 1772 ASSERT_EQ(umount2("/mnt/open_tree_subfolder", 0), 0); 1773 1774 EXPECT_EQ(rmdir("/mnt/open_tree_subfolder"), 0); 1775 } 1776 1777 TEST_F(mount_setattr, mount_detached_mount_on_detached_mount_then_close) 1778 { 1779 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF; 1780 struct statx stx; 1781 1782 fd_tree_base = sys_open_tree(-EBADF, "/mnt", 1783 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1784 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE); 1785 ASSERT_GE(fd_tree_base, 0); 1786 /* 1787 * /mnt testing tmpfs 1788 */ 1789 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0); 1790 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1791 1792 fd_tree_subdir = sys_open_tree(fd_tree_base, "", 1793 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1794 AT_EMPTY_PATH | OPEN_TREE_CLOEXEC | 1795 OPEN_TREE_CLONE); 1796 ASSERT_GE(fd_tree_subdir, 0); 1797 /* 1798 * /mnt testing tmpfs 1799 */ 1800 ASSERT_EQ(statx(fd_tree_subdir, "A", 0, 0, &stx), 0); 1801 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1802 1803 /* 1804 * /mnt testing tmpfs 1805 * `-/mnt testing tmpfs 1806 */ 1807 ASSERT_EQ(move_mount(fd_tree_subdir, "", fd_tree_base, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0); 1808 ASSERT_EQ(statx(fd_tree_subdir, "", AT_EMPTY_PATH, 0, &stx), 0); 1809 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1810 1811 ASSERT_NE(move_mount(fd_tree_subdir, "", fd_tree_base, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0); 1812 1813 EXPECT_EQ(close(fd_tree_base), 0); 1814 EXPECT_EQ(close(fd_tree_subdir), 0); 1815 } 1816 1817 TEST_F(mount_setattr, mount_detached_mount_on_detached_mount_and_attach) 1818 { 1819 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF; 1820 struct statx stx; 1821 __u64 mnt_id = 0; 1822 1823 fd_tree_base = sys_open_tree(-EBADF, "/mnt", 1824 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1825 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE); 1826 ASSERT_GE(fd_tree_base, 0); 1827 /* 1828 * /mnt testing tmpfs 1829 */ 1830 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0); 1831 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1832 1833 fd_tree_subdir = sys_open_tree(fd_tree_base, "", 1834 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1835 AT_EMPTY_PATH | OPEN_TREE_CLOEXEC | 1836 OPEN_TREE_CLONE); 1837 ASSERT_GE(fd_tree_subdir, 0); 1838 /* 1839 * /mnt testing tmpfs 1840 */ 1841 ASSERT_EQ(statx(fd_tree_subdir, "A", 0, 0, &stx), 0); 1842 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1843 1844 /* 1845 * /mnt testing tmpfs 1846 * `-/mnt testing tmpfs 1847 */ 1848 ASSERT_EQ(move_mount(fd_tree_subdir, "", fd_tree_base, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0); 1849 ASSERT_EQ(statx(fd_tree_subdir, "", AT_EMPTY_PATH, STATX_MNT_ID_UNIQUE, &stx), 0); 1850 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1851 ASSERT_TRUE(stx.stx_mask & STATX_MNT_ID_UNIQUE); 1852 mnt_id = stx.stx_mnt_id; 1853 1854 ASSERT_NE(move_mount(fd_tree_subdir, "", fd_tree_base, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0); 1855 1856 ASSERT_EQ(move_mount(fd_tree_base, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0); 1857 ASSERT_EQ(statx(-EBADF, "/tmp/target1", 0, STATX_MNT_ID_UNIQUE, &stx), 0); 1858 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1859 ASSERT_TRUE(stx.stx_mask & STATX_MNT_ID_UNIQUE); 1860 ASSERT_EQ(stx.stx_mnt_id, mnt_id); 1861 1862 EXPECT_EQ(close(fd_tree_base), 0); 1863 EXPECT_EQ(close(fd_tree_subdir), 0); 1864 } 1865 1866 TEST_F(mount_setattr, move_mount_detached_fail) 1867 { 1868 int fd_tree_base = -EBADF, fd_tree_subdir = -EBADF; 1869 struct statx stx; 1870 1871 fd_tree_base = sys_open_tree(-EBADF, "/mnt", 1872 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1873 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE); 1874 ASSERT_GE(fd_tree_base, 0); 1875 1876 /* Attach the mount to the caller's mount namespace. */ 1877 ASSERT_EQ(move_mount(fd_tree_base, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0); 1878 1879 ASSERT_EQ(statx(fd_tree_base, "A", 0, 0, &stx), 0); 1880 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1881 1882 fd_tree_subdir = sys_open_tree(-EBADF, "/tmp/B", 1883 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1884 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE); 1885 ASSERT_GE(fd_tree_subdir, 0); 1886 ASSERT_EQ(statx(fd_tree_subdir, "BB", 0, 0, &stx), 0); 1887 ASSERT_FALSE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1888 1889 /* Not allowed to move an attached mount to a detached mount. */ 1890 ASSERT_NE(move_mount(fd_tree_base, "", fd_tree_subdir, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0); 1891 ASSERT_EQ(errno, EINVAL); 1892 1893 EXPECT_EQ(close(fd_tree_base), 0); 1894 EXPECT_EQ(close(fd_tree_subdir), 0); 1895 } 1896 1897 TEST_F(mount_setattr, attach_detached_mount_then_umount_then_close) 1898 { 1899 int fd_tree = -EBADF; 1900 struct statx stx; 1901 1902 fd_tree = sys_open_tree(-EBADF, "/mnt", 1903 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1904 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1905 OPEN_TREE_CLONE); 1906 ASSERT_GE(fd_tree, 0); 1907 1908 ASSERT_EQ(statx(fd_tree, "A", 0, 0, &stx), 0); 1909 /* We copied with AT_RECURSIVE so /mnt/A must be a mountpoint. */ 1910 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1911 1912 /* Attach the mount to the caller's mount namespace. */ 1913 ASSERT_EQ(move_mount(fd_tree, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0); 1914 1915 ASSERT_EQ(statx(-EBADF, "/tmp/target1", 0, 0, &stx), 0); 1916 ASSERT_TRUE(stx.stx_attributes & STATX_ATTR_MOUNT_ROOT); 1917 1918 ASSERT_EQ(umount2("/tmp/target1", MNT_DETACH), 0); 1919 1920 /* 1921 * This tests whether dissolve_on_fput() handles a NULL mount 1922 * namespace correctly, i.e., that it doesn't splat. 1923 */ 1924 EXPECT_EQ(close(fd_tree), 0); 1925 } 1926 1927 TEST_F(mount_setattr, mount_detached1_onto_detached2_then_close_detached1_then_mount_detached2_onto_attached) 1928 { 1929 int fd_tree1 = -EBADF, fd_tree2 = -EBADF; 1930 1931 /* 1932 * |-/mnt/A testing tmpfs 1933 * `-/mnt/A/AA testing tmpfs 1934 * `-/mnt/A/AA/B testing tmpfs 1935 * `-/mnt/A/AA/B/BB testing tmpfs 1936 */ 1937 fd_tree1 = sys_open_tree(-EBADF, "/mnt/A", 1938 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1939 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 1940 OPEN_TREE_CLONE); 1941 ASSERT_GE(fd_tree1, 0); 1942 1943 /* 1944 * `-/mnt/B testing ramfs 1945 */ 1946 fd_tree2 = sys_open_tree(-EBADF, "/mnt/B", 1947 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 1948 AT_EMPTY_PATH | OPEN_TREE_CLOEXEC | 1949 OPEN_TREE_CLONE); 1950 ASSERT_GE(fd_tree2, 0); 1951 1952 /* 1953 * Move the source detached mount tree to the target detached 1954 * mount tree. This will move all the mounts in the source mount 1955 * tree from the source anonymous mount namespace to the target 1956 * anonymous mount namespace. 1957 * 1958 * The source detached mount tree and the target detached mount 1959 * tree now both refer to the same anonymous mount namespace. 1960 * 1961 * |-"" testing ramfs 1962 * `-"" testing tmpfs 1963 * `-""/AA testing tmpfs 1964 * `-""/AA/B testing tmpfs 1965 * `-""/AA/B/BB testing tmpfs 1966 */ 1967 ASSERT_EQ(move_mount(fd_tree1, "", fd_tree2, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0); 1968 1969 /* 1970 * The source detached mount tree @fd_tree1 is now an attached 1971 * mount, i.e., it has a parent. Specifically, it now has the 1972 * root mount of the mount tree of @fd_tree2 as its parent. 1973 * 1974 * That means we are no longer allowed to attach it as we only 1975 * allow attaching the root of an anonymous mount tree, not 1976 * random bits and pieces. Verify that the kernel enforces this. 1977 */ 1978 ASSERT_NE(move_mount(fd_tree1, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0); 1979 1980 /* 1981 * Closing the source detached mount tree must not unmount and 1982 * free the shared anonymous mount namespace. The kernel will 1983 * quickly yell at us because the anonymous mount namespace 1984 * won't be empty when it's freed. 1985 */ 1986 EXPECT_EQ(close(fd_tree1), 0); 1987 1988 /* 1989 * Attach the mount tree to a non-anonymous mount namespace. 1990 * This can only succeed if closing fd_tree1 had proper 1991 * semantics and didn't cause the anonymous mount namespace to 1992 * be freed. If it did this will trigger a UAF which will be 1993 * visible on any KASAN enabled kernel. 1994 * 1995 * |-/tmp/target1 testing ramfs 1996 * `-/tmp/target1 testing tmpfs 1997 * `-/tmp/target1/AA testing tmpfs 1998 * `-/tmp/target1/AA/B testing tmpfs 1999 * `-/tmp/target1/AA/B/BB testing tmpfs 2000 */ 2001 ASSERT_EQ(move_mount(fd_tree2, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0); 2002 EXPECT_EQ(close(fd_tree2), 0); 2003 } 2004 2005 TEST_F(mount_setattr, two_detached_mounts_referring_to_same_anonymous_mount_namespace) 2006 { 2007 int fd_tree1 = -EBADF, fd_tree2 = -EBADF; 2008 2009 /* 2010 * Copy the following mount tree: 2011 * 2012 * |-/mnt/A testing tmpfs 2013 * `-/mnt/A/AA testing tmpfs 2014 * `-/mnt/A/AA/B testing tmpfs 2015 * `-/mnt/A/AA/B/BB testing tmpfs 2016 */ 2017 fd_tree1 = sys_open_tree(-EBADF, "/mnt/A", 2018 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 2019 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 2020 OPEN_TREE_CLONE); 2021 ASSERT_GE(fd_tree1, 0); 2022 2023 /* 2024 * Create an O_PATH file descriptors with a separate struct file 2025 * that refers to the same detached mount tree as @fd_tree1 2026 */ 2027 fd_tree2 = sys_open_tree(fd_tree1, "", 2028 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 2029 AT_EMPTY_PATH | OPEN_TREE_CLOEXEC); 2030 ASSERT_GE(fd_tree2, 0); 2031 2032 /* 2033 * Copy the following mount tree: 2034 * 2035 * |-/tmp/target1 testing tmpfs 2036 * `-/tmp/target1/AA testing tmpfs 2037 * `-/tmp/target1/AA/B testing tmpfs 2038 * `-/tmp/target1/AA/B/BB testing tmpfs 2039 */ 2040 ASSERT_EQ(move_mount(fd_tree2, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0); 2041 2042 /* 2043 * This must fail as this would mean adding the same mount tree 2044 * into the same mount tree. 2045 */ 2046 ASSERT_NE(move_mount(fd_tree1, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0); 2047 } 2048 2049 TEST_F(mount_setattr, two_detached_subtrees_of_same_anonymous_mount_namespace) 2050 { 2051 int fd_tree1 = -EBADF, fd_tree2 = -EBADF; 2052 2053 /* 2054 * Copy the following mount tree: 2055 * 2056 * |-/mnt/A testing tmpfs 2057 * `-/mnt/A/AA testing tmpfs 2058 * `-/mnt/A/AA/B testing tmpfs 2059 * `-/mnt/A/AA/B/BB testing tmpfs 2060 */ 2061 fd_tree1 = sys_open_tree(-EBADF, "/mnt/A", 2062 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 2063 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 2064 OPEN_TREE_CLONE); 2065 ASSERT_GE(fd_tree1, 0); 2066 2067 /* 2068 * Create an O_PATH file descriptors with a separate struct file that 2069 * refers to a subtree of the same detached mount tree as @fd_tree1 2070 */ 2071 fd_tree2 = sys_open_tree(fd_tree1, "AA", 2072 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 2073 AT_EMPTY_PATH | OPEN_TREE_CLOEXEC); 2074 ASSERT_GE(fd_tree2, 0); 2075 2076 /* 2077 * This must fail as it is only possible to attach the root of a 2078 * detached mount tree. 2079 */ 2080 ASSERT_NE(move_mount(fd_tree2, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0); 2081 2082 ASSERT_EQ(move_mount(fd_tree1, "", -EBADF, "/tmp/target1", MOVE_MOUNT_F_EMPTY_PATH), 0); 2083 } 2084 2085 TEST_F(mount_setattr, detached_tree_propagation) 2086 { 2087 int fd_tree = -EBADF; 2088 struct statx stx1, stx2, stx3, stx4; 2089 2090 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 2091 ASSERT_EQ(mount(NULL, "/mnt", NULL, MS_REC | MS_SHARED, NULL), 0); 2092 2093 /* 2094 * Copy the following mount tree: 2095 * 2096 * /mnt testing tmpfs 2097 * |-/mnt/A testing tmpfs 2098 * | `-/mnt/A/AA testing tmpfs 2099 * | `-/mnt/A/AA/B testing tmpfs 2100 * | `-/mnt/A/AA/B/BB testing tmpfs 2101 * `-/mnt/B testing ramfs 2102 */ 2103 fd_tree = sys_open_tree(-EBADF, "/mnt", 2104 AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | 2105 AT_RECURSIVE | OPEN_TREE_CLOEXEC | 2106 OPEN_TREE_CLONE); 2107 ASSERT_GE(fd_tree, 0); 2108 2109 ASSERT_EQ(statx(-EBADF, "/mnt/A", 0, 0, &stx1), 0); 2110 ASSERT_EQ(statx(fd_tree, "A", 0, 0, &stx2), 0); 2111 2112 /* 2113 * Copying the mount namespace like done above doesn't alter the 2114 * mounts in any way so the filesystem mounted on /mnt must be 2115 * identical even though the mounts will differ. Use the device 2116 * information to verify that. Note that tmpfs will have a 0 2117 * major number so comparing the major number is misleading. 2118 */ 2119 ASSERT_EQ(stx1.stx_dev_minor, stx2.stx_dev_minor); 2120 2121 /* Mount a tmpfs filesystem over /mnt/A. */ 2122 ASSERT_EQ(mount(NULL, "/mnt/A", "tmpfs", 0, NULL), 0); 2123 2124 2125 ASSERT_EQ(statx(-EBADF, "/mnt/A", 0, 0, &stx3), 0); 2126 ASSERT_EQ(statx(fd_tree, "A", 0, 0, &stx4), 0); 2127 2128 /* 2129 * A new filesystem has been mounted on top of /mnt/A which 2130 * means that the device information will be different for any 2131 * statx() that was taken from /mnt/A before the mount compared 2132 * to one after the mount. 2133 */ 2134 ASSERT_NE(stx1.stx_dev_minor, stx3.stx_dev_minor); 2135 ASSERT_EQ(stx1.stx_dev_minor, stx4.stx_dev_minor); 2136 2137 EXPECT_EQ(close(fd_tree), 0); 2138 } 2139 2140 TEST_HARNESS_MAIN 2141