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