mount_setattr_test.c (38617B)
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 22#include "../kselftest_harness.h" 23 24#ifndef CLONE_NEWNS 25#define CLONE_NEWNS 0x00020000 26#endif 27 28#ifndef CLONE_NEWUSER 29#define CLONE_NEWUSER 0x10000000 30#endif 31 32#ifndef MS_REC 33#define MS_REC 16384 34#endif 35 36#ifndef MS_RELATIME 37#define MS_RELATIME (1 << 21) 38#endif 39 40#ifndef MS_STRICTATIME 41#define MS_STRICTATIME (1 << 24) 42#endif 43 44#ifndef MOUNT_ATTR_RDONLY 45#define MOUNT_ATTR_RDONLY 0x00000001 46#endif 47 48#ifndef MOUNT_ATTR_NOSUID 49#define MOUNT_ATTR_NOSUID 0x00000002 50#endif 51 52#ifndef MOUNT_ATTR_NOEXEC 53#define MOUNT_ATTR_NOEXEC 0x00000008 54#endif 55 56#ifndef MOUNT_ATTR_NODIRATIME 57#define MOUNT_ATTR_NODIRATIME 0x00000080 58#endif 59 60#ifndef MOUNT_ATTR__ATIME 61#define MOUNT_ATTR__ATIME 0x00000070 62#endif 63 64#ifndef MOUNT_ATTR_RELATIME 65#define MOUNT_ATTR_RELATIME 0x00000000 66#endif 67 68#ifndef MOUNT_ATTR_NOATIME 69#define MOUNT_ATTR_NOATIME 0x00000010 70#endif 71 72#ifndef MOUNT_ATTR_STRICTATIME 73#define MOUNT_ATTR_STRICTATIME 0x00000020 74#endif 75 76#ifndef AT_RECURSIVE 77#define AT_RECURSIVE 0x8000 78#endif 79 80#ifndef MS_SHARED 81#define MS_SHARED (1 << 20) 82#endif 83 84#define DEFAULT_THREADS 4 85#define ptr_to_int(p) ((int)((intptr_t)(p))) 86#define int_to_ptr(u) ((void *)((intptr_t)(u))) 87 88#ifndef __NR_mount_setattr 89 #if defined __alpha__ 90 #define __NR_mount_setattr 552 91 #elif defined _MIPS_SIM 92 #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ 93 #define __NR_mount_setattr (442 + 4000) 94 #endif 95 #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */ 96 #define __NR_mount_setattr (442 + 6000) 97 #endif 98 #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ 99 #define __NR_mount_setattr (442 + 5000) 100 #endif 101 #elif defined __ia64__ 102 #define __NR_mount_setattr (442 + 1024) 103 #else 104 #define __NR_mount_setattr 442 105 #endif 106 107struct mount_attr { 108 __u64 attr_set; 109 __u64 attr_clr; 110 __u64 propagation; 111 __u64 userns_fd; 112}; 113#endif 114 115#ifndef __NR_open_tree 116 #if defined __alpha__ 117 #define __NR_open_tree 538 118 #elif defined _MIPS_SIM 119 #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ 120 #define __NR_open_tree 4428 121 #endif 122 #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */ 123 #define __NR_open_tree 6428 124 #endif 125 #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ 126 #define __NR_open_tree 5428 127 #endif 128 #elif defined __ia64__ 129 #define __NR_open_tree (428 + 1024) 130 #else 131 #define __NR_open_tree 428 132 #endif 133#endif 134 135#ifndef MOUNT_ATTR_IDMAP 136#define MOUNT_ATTR_IDMAP 0x00100000 137#endif 138 139#ifndef MOUNT_ATTR_NOSYMFOLLOW 140#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 141#endif 142 143static inline int sys_mount_setattr(int dfd, const char *path, unsigned int flags, 144 struct mount_attr *attr, size_t size) 145{ 146 return syscall(__NR_mount_setattr, dfd, path, flags, attr, size); 147} 148 149#ifndef OPEN_TREE_CLONE 150#define OPEN_TREE_CLONE 1 151#endif 152 153#ifndef OPEN_TREE_CLOEXEC 154#define OPEN_TREE_CLOEXEC O_CLOEXEC 155#endif 156 157#ifndef AT_RECURSIVE 158#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */ 159#endif 160 161static inline int sys_open_tree(int dfd, const char *filename, unsigned int flags) 162{ 163 return syscall(__NR_open_tree, dfd, filename, flags); 164} 165 166static ssize_t write_nointr(int fd, const void *buf, size_t count) 167{ 168 ssize_t ret; 169 170 do { 171 ret = write(fd, buf, count); 172 } while (ret < 0 && errno == EINTR); 173 174 return ret; 175} 176 177static int write_file(const char *path, const void *buf, size_t count) 178{ 179 int fd; 180 ssize_t ret; 181 182 fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW); 183 if (fd < 0) 184 return -1; 185 186 ret = write_nointr(fd, buf, count); 187 close(fd); 188 if (ret < 0 || (size_t)ret != count) 189 return -1; 190 191 return 0; 192} 193 194static int create_and_enter_userns(void) 195{ 196 uid_t uid; 197 gid_t gid; 198 char map[100]; 199 200 uid = getuid(); 201 gid = getgid(); 202 203 if (unshare(CLONE_NEWUSER)) 204 return -1; 205 206 if (write_file("/proc/self/setgroups", "deny", sizeof("deny") - 1) && 207 errno != ENOENT) 208 return -1; 209 210 snprintf(map, sizeof(map), "0 %d 1", uid); 211 if (write_file("/proc/self/uid_map", map, strlen(map))) 212 return -1; 213 214 215 snprintf(map, sizeof(map), "0 %d 1", gid); 216 if (write_file("/proc/self/gid_map", map, strlen(map))) 217 return -1; 218 219 if (setgid(0)) 220 return -1; 221 222 if (setuid(0)) 223 return -1; 224 225 return 0; 226} 227 228static int prepare_unpriv_mountns(void) 229{ 230 if (create_and_enter_userns()) 231 return -1; 232 233 if (unshare(CLONE_NEWNS)) 234 return -1; 235 236 if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0)) 237 return -1; 238 239 return 0; 240} 241 242#ifndef ST_NOSYMFOLLOW 243#define ST_NOSYMFOLLOW 0x2000 /* do not follow symlinks */ 244#endif 245 246static int read_mnt_flags(const char *path) 247{ 248 int ret; 249 struct statvfs stat; 250 unsigned int mnt_flags; 251 252 ret = statvfs(path, &stat); 253 if (ret != 0) 254 return -EINVAL; 255 256 if (stat.f_flag & ~(ST_RDONLY | ST_NOSUID | ST_NODEV | ST_NOEXEC | 257 ST_NOATIME | ST_NODIRATIME | ST_RELATIME | 258 ST_SYNCHRONOUS | ST_MANDLOCK | ST_NOSYMFOLLOW)) 259 return -EINVAL; 260 261 mnt_flags = 0; 262 if (stat.f_flag & ST_RDONLY) 263 mnt_flags |= MS_RDONLY; 264 if (stat.f_flag & ST_NOSUID) 265 mnt_flags |= MS_NOSUID; 266 if (stat.f_flag & ST_NODEV) 267 mnt_flags |= MS_NODEV; 268 if (stat.f_flag & ST_NOEXEC) 269 mnt_flags |= MS_NOEXEC; 270 if (stat.f_flag & ST_NOATIME) 271 mnt_flags |= MS_NOATIME; 272 if (stat.f_flag & ST_NODIRATIME) 273 mnt_flags |= MS_NODIRATIME; 274 if (stat.f_flag & ST_RELATIME) 275 mnt_flags |= MS_RELATIME; 276 if (stat.f_flag & ST_SYNCHRONOUS) 277 mnt_flags |= MS_SYNCHRONOUS; 278 if (stat.f_flag & ST_MANDLOCK) 279 mnt_flags |= ST_MANDLOCK; 280 if (stat.f_flag & ST_NOSYMFOLLOW) 281 mnt_flags |= ST_NOSYMFOLLOW; 282 283 return mnt_flags; 284} 285 286static char *get_field(char *src, int nfields) 287{ 288 int i; 289 char *p = src; 290 291 for (i = 0; i < nfields; i++) { 292 while (*p && *p != ' ' && *p != '\t') 293 p++; 294 295 if (!*p) 296 break; 297 298 p++; 299 } 300 301 return p; 302} 303 304static void null_endofword(char *word) 305{ 306 while (*word && *word != ' ' && *word != '\t') 307 word++; 308 *word = '\0'; 309} 310 311static bool is_shared_mount(const char *path) 312{ 313 size_t len = 0; 314 char *line = NULL; 315 FILE *f = NULL; 316 317 f = fopen("/proc/self/mountinfo", "re"); 318 if (!f) 319 return false; 320 321 while (getline(&line, &len, f) != -1) { 322 char *opts, *target; 323 324 target = get_field(line, 4); 325 if (!target) 326 continue; 327 328 opts = get_field(target, 2); 329 if (!opts) 330 continue; 331 332 null_endofword(target); 333 334 if (strcmp(target, path) != 0) 335 continue; 336 337 null_endofword(opts); 338 if (strstr(opts, "shared:")) 339 return true; 340 } 341 342 free(line); 343 fclose(f); 344 345 return false; 346} 347 348static void *mount_setattr_thread(void *data) 349{ 350 struct mount_attr attr = { 351 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID, 352 .attr_clr = 0, 353 .propagation = MS_SHARED, 354 }; 355 356 if (sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr))) 357 pthread_exit(int_to_ptr(-1)); 358 359 pthread_exit(int_to_ptr(0)); 360} 361 362/* Attempt to de-conflict with the selftests tree. */ 363#ifndef SKIP 364#define SKIP(s, ...) XFAIL(s, ##__VA_ARGS__) 365#endif 366 367static bool mount_setattr_supported(void) 368{ 369 int ret; 370 371 ret = sys_mount_setattr(-EBADF, "", AT_EMPTY_PATH, NULL, 0); 372 if (ret < 0 && errno == ENOSYS) 373 return false; 374 375 return true; 376} 377 378FIXTURE(mount_setattr) { 379}; 380 381#define NOSYMFOLLOW_TARGET "/mnt/A/AA/data" 382#define NOSYMFOLLOW_SYMLINK "/mnt/A/AA/symlink" 383 384FIXTURE_SETUP(mount_setattr) 385{ 386 int fd = -EBADF; 387 388 if (!mount_setattr_supported()) 389 SKIP(return, "mount_setattr syscall not supported"); 390 391 ASSERT_EQ(prepare_unpriv_mountns(), 0); 392 393 (void)umount2("/mnt", MNT_DETACH); 394 (void)umount2("/tmp", MNT_DETACH); 395 396 ASSERT_EQ(mount("testing", "/tmp", "tmpfs", MS_NOATIME | MS_NODEV, 397 "size=100000,mode=700"), 0); 398 399 ASSERT_EQ(mkdir("/tmp/B", 0777), 0); 400 401 ASSERT_EQ(mount("testing", "/tmp/B", "tmpfs", MS_NOATIME | MS_NODEV, 402 "size=100000,mode=700"), 0); 403 404 ASSERT_EQ(mkdir("/tmp/B/BB", 0777), 0); 405 406 ASSERT_EQ(mount("testing", "/tmp/B/BB", "tmpfs", MS_NOATIME | MS_NODEV, 407 "size=100000,mode=700"), 0); 408 409 ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV, 410 "size=100000,mode=700"), 0); 411 412 ASSERT_EQ(mkdir("/mnt/A", 0777), 0); 413 414 ASSERT_EQ(mount("testing", "/mnt/A", "tmpfs", MS_NOATIME | MS_NODEV, 415 "size=100000,mode=700"), 0); 416 417 ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0); 418 419 ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0); 420 421 ASSERT_EQ(mkdir("/mnt/B", 0777), 0); 422 423 ASSERT_EQ(mount("testing", "/mnt/B", "ramfs", 424 MS_NOATIME | MS_NODEV | MS_NOSUID, 0), 0); 425 426 ASSERT_EQ(mkdir("/mnt/B/BB", 0777), 0); 427 428 ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts", 429 MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0); 430 431 fd = creat(NOSYMFOLLOW_TARGET, O_RDWR | O_CLOEXEC); 432 ASSERT_GT(fd, 0); 433 ASSERT_EQ(symlink(NOSYMFOLLOW_TARGET, NOSYMFOLLOW_SYMLINK), 0); 434 ASSERT_EQ(close(fd), 0); 435} 436 437FIXTURE_TEARDOWN(mount_setattr) 438{ 439 if (!mount_setattr_supported()) 440 SKIP(return, "mount_setattr syscall not supported"); 441 442 (void)umount2("/mnt/A", MNT_DETACH); 443 (void)umount2("/tmp", MNT_DETACH); 444} 445 446TEST_F(mount_setattr, invalid_attributes) 447{ 448 struct mount_attr invalid_attr = { 449 .attr_set = (1U << 31), 450 }; 451 452 if (!mount_setattr_supported()) 453 SKIP(return, "mount_setattr syscall not supported"); 454 455 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 456 sizeof(invalid_attr)), 0); 457 458 invalid_attr.attr_set = 0; 459 invalid_attr.attr_clr = (1U << 31); 460 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 461 sizeof(invalid_attr)), 0); 462 463 invalid_attr.attr_clr = 0; 464 invalid_attr.propagation = (1U << 31); 465 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 466 sizeof(invalid_attr)), 0); 467 468 invalid_attr.attr_set = (1U << 31); 469 invalid_attr.attr_clr = (1U << 31); 470 invalid_attr.propagation = (1U << 31); 471 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 472 sizeof(invalid_attr)), 0); 473 474 ASSERT_NE(sys_mount_setattr(-1, "mnt/A", AT_RECURSIVE, &invalid_attr, 475 sizeof(invalid_attr)), 0); 476} 477 478TEST_F(mount_setattr, extensibility) 479{ 480 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 481 char *s = "dummy"; 482 struct mount_attr invalid_attr = {}; 483 struct mount_attr_large { 484 struct mount_attr attr1; 485 struct mount_attr attr2; 486 struct mount_attr attr3; 487 } large_attr = {}; 488 489 if (!mount_setattr_supported()) 490 SKIP(return, "mount_setattr syscall not supported"); 491 492 old_flags = read_mnt_flags("/mnt/A"); 493 ASSERT_GT(old_flags, 0); 494 495 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, NULL, 496 sizeof(invalid_attr)), 0); 497 ASSERT_EQ(errno, EFAULT); 498 499 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, (void *)s, 500 sizeof(invalid_attr)), 0); 501 ASSERT_EQ(errno, EINVAL); 502 503 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 0), 0); 504 ASSERT_EQ(errno, EINVAL); 505 506 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 507 sizeof(invalid_attr) / 2), 0); 508 ASSERT_EQ(errno, EINVAL); 509 510 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &invalid_attr, 511 sizeof(invalid_attr) / 2), 0); 512 ASSERT_EQ(errno, EINVAL); 513 514 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, 515 (void *)&large_attr, sizeof(large_attr)), 0); 516 517 large_attr.attr3.attr_set = MOUNT_ATTR_RDONLY; 518 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, 519 (void *)&large_attr, sizeof(large_attr)), 0); 520 521 large_attr.attr3.attr_set = 0; 522 large_attr.attr1.attr_set = MOUNT_ATTR_RDONLY; 523 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, 524 (void *)&large_attr, sizeof(large_attr)), 0); 525 526 expected_flags = old_flags; 527 expected_flags |= MS_RDONLY; 528 529 new_flags = read_mnt_flags("/mnt/A"); 530 ASSERT_EQ(new_flags, expected_flags); 531 532 new_flags = read_mnt_flags("/mnt/A/AA"); 533 ASSERT_EQ(new_flags, expected_flags); 534 535 new_flags = read_mnt_flags("/mnt/A/AA/B"); 536 ASSERT_EQ(new_flags, expected_flags); 537 538 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 539 ASSERT_EQ(new_flags, expected_flags); 540} 541 542TEST_F(mount_setattr, basic) 543{ 544 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 545 struct mount_attr attr = { 546 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME, 547 .attr_clr = MOUNT_ATTR__ATIME, 548 }; 549 550 if (!mount_setattr_supported()) 551 SKIP(return, "mount_setattr syscall not supported"); 552 553 old_flags = read_mnt_flags("/mnt/A"); 554 ASSERT_GT(old_flags, 0); 555 556 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", 0, &attr, sizeof(attr)), 0); 557 558 expected_flags = old_flags; 559 expected_flags |= MS_RDONLY; 560 expected_flags |= MS_NOEXEC; 561 expected_flags &= ~MS_NOATIME; 562 expected_flags |= MS_RELATIME; 563 564 new_flags = read_mnt_flags("/mnt/A"); 565 ASSERT_EQ(new_flags, expected_flags); 566 567 new_flags = read_mnt_flags("/mnt/A/AA"); 568 ASSERT_EQ(new_flags, old_flags); 569 570 new_flags = read_mnt_flags("/mnt/A/AA/B"); 571 ASSERT_EQ(new_flags, old_flags); 572 573 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 574 ASSERT_EQ(new_flags, old_flags); 575} 576 577TEST_F(mount_setattr, basic_recursive) 578{ 579 int fd; 580 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 581 struct mount_attr attr = { 582 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME, 583 .attr_clr = MOUNT_ATTR__ATIME, 584 }; 585 586 if (!mount_setattr_supported()) 587 SKIP(return, "mount_setattr syscall not supported"); 588 589 old_flags = read_mnt_flags("/mnt/A"); 590 ASSERT_GT(old_flags, 0); 591 592 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 593 594 expected_flags = old_flags; 595 expected_flags |= MS_RDONLY; 596 expected_flags |= MS_NOEXEC; 597 expected_flags &= ~MS_NOATIME; 598 expected_flags |= MS_RELATIME; 599 600 new_flags = read_mnt_flags("/mnt/A"); 601 ASSERT_EQ(new_flags, expected_flags); 602 603 new_flags = read_mnt_flags("/mnt/A/AA"); 604 ASSERT_EQ(new_flags, expected_flags); 605 606 new_flags = read_mnt_flags("/mnt/A/AA/B"); 607 ASSERT_EQ(new_flags, expected_flags); 608 609 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 610 ASSERT_EQ(new_flags, expected_flags); 611 612 memset(&attr, 0, sizeof(attr)); 613 attr.attr_clr = MOUNT_ATTR_RDONLY; 614 attr.propagation = MS_SHARED; 615 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 616 617 expected_flags &= ~MS_RDONLY; 618 new_flags = read_mnt_flags("/mnt/A"); 619 ASSERT_EQ(new_flags, expected_flags); 620 621 ASSERT_EQ(is_shared_mount("/mnt/A"), true); 622 623 new_flags = read_mnt_flags("/mnt/A/AA"); 624 ASSERT_EQ(new_flags, expected_flags); 625 626 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true); 627 628 new_flags = read_mnt_flags("/mnt/A/AA/B"); 629 ASSERT_EQ(new_flags, expected_flags); 630 631 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true); 632 633 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 634 ASSERT_EQ(new_flags, expected_flags); 635 636 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true); 637 638 fd = open("/mnt/A/AA/B/b", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 0777); 639 ASSERT_GE(fd, 0); 640 641 /* 642 * We're holding a fd open for writing so this needs to fail somewhere 643 * in the middle and the mount options need to be unchanged. 644 */ 645 attr.attr_set = MOUNT_ATTR_RDONLY; 646 ASSERT_LT(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 647 648 new_flags = read_mnt_flags("/mnt/A"); 649 ASSERT_EQ(new_flags, expected_flags); 650 651 ASSERT_EQ(is_shared_mount("/mnt/A"), true); 652 653 new_flags = read_mnt_flags("/mnt/A/AA"); 654 ASSERT_EQ(new_flags, expected_flags); 655 656 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true); 657 658 new_flags = read_mnt_flags("/mnt/A/AA/B"); 659 ASSERT_EQ(new_flags, expected_flags); 660 661 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true); 662 663 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 664 ASSERT_EQ(new_flags, expected_flags); 665 666 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true); 667 668 EXPECT_EQ(close(fd), 0); 669} 670 671TEST_F(mount_setattr, mount_has_writers) 672{ 673 int fd, dfd; 674 unsigned int old_flags = 0, new_flags = 0; 675 struct mount_attr attr = { 676 .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME, 677 .attr_clr = MOUNT_ATTR__ATIME, 678 .propagation = MS_SHARED, 679 }; 680 681 if (!mount_setattr_supported()) 682 SKIP(return, "mount_setattr syscall not supported"); 683 684 old_flags = read_mnt_flags("/mnt/A"); 685 ASSERT_GT(old_flags, 0); 686 687 fd = open("/mnt/A/AA/B/b", O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 0777); 688 ASSERT_GE(fd, 0); 689 690 /* 691 * We're holding a fd open to a mount somwhere in the middle so this 692 * needs to fail somewhere in the middle. After this the mount options 693 * need to be unchanged. 694 */ 695 ASSERT_LT(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 696 697 new_flags = read_mnt_flags("/mnt/A"); 698 ASSERT_EQ(new_flags, old_flags); 699 700 ASSERT_EQ(is_shared_mount("/mnt/A"), false); 701 702 new_flags = read_mnt_flags("/mnt/A/AA"); 703 ASSERT_EQ(new_flags, old_flags); 704 705 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), false); 706 707 new_flags = read_mnt_flags("/mnt/A/AA/B"); 708 ASSERT_EQ(new_flags, old_flags); 709 710 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), false); 711 712 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 713 ASSERT_EQ(new_flags, old_flags); 714 715 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), false); 716 717 dfd = open("/mnt/A/AA/B", O_DIRECTORY | O_CLOEXEC); 718 ASSERT_GE(dfd, 0); 719 EXPECT_EQ(fsync(dfd), 0); 720 EXPECT_EQ(close(dfd), 0); 721 722 EXPECT_EQ(fsync(fd), 0); 723 EXPECT_EQ(close(fd), 0); 724 725 /* All writers are gone so this should succeed. */ 726 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 727} 728 729TEST_F(mount_setattr, mixed_mount_options) 730{ 731 unsigned int old_flags1 = 0, old_flags2 = 0, new_flags = 0, expected_flags = 0; 732 struct mount_attr attr = { 733 .attr_clr = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOEXEC | MOUNT_ATTR__ATIME, 734 .attr_set = MOUNT_ATTR_RELATIME, 735 }; 736 737 if (!mount_setattr_supported()) 738 SKIP(return, "mount_setattr syscall not supported"); 739 740 old_flags1 = read_mnt_flags("/mnt/B"); 741 ASSERT_GT(old_flags1, 0); 742 743 old_flags2 = read_mnt_flags("/mnt/B/BB"); 744 ASSERT_GT(old_flags2, 0); 745 746 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/B", AT_RECURSIVE, &attr, sizeof(attr)), 0); 747 748 expected_flags = old_flags2; 749 expected_flags &= ~(MS_RDONLY | MS_NOEXEC | MS_NOATIME | MS_NOSUID); 750 expected_flags |= MS_RELATIME; 751 752 new_flags = read_mnt_flags("/mnt/B"); 753 ASSERT_EQ(new_flags, expected_flags); 754 755 expected_flags = old_flags2; 756 expected_flags &= ~(MS_RDONLY | MS_NOEXEC | MS_NOATIME | MS_NOSUID); 757 expected_flags |= MS_RELATIME; 758 759 new_flags = read_mnt_flags("/mnt/B/BB"); 760 ASSERT_EQ(new_flags, expected_flags); 761} 762 763TEST_F(mount_setattr, time_changes) 764{ 765 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 766 struct mount_attr attr = { 767 .attr_set = MOUNT_ATTR_NODIRATIME | MOUNT_ATTR_NOATIME, 768 }; 769 770 if (!mount_setattr_supported()) 771 SKIP(return, "mount_setattr syscall not supported"); 772 773 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 774 775 attr.attr_set = MOUNT_ATTR_STRICTATIME; 776 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 777 778 attr.attr_set = MOUNT_ATTR_STRICTATIME | MOUNT_ATTR_NOATIME; 779 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 780 781 attr.attr_set = MOUNT_ATTR_STRICTATIME | MOUNT_ATTR_NOATIME; 782 attr.attr_clr = MOUNT_ATTR__ATIME; 783 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 784 785 attr.attr_set = 0; 786 attr.attr_clr = MOUNT_ATTR_STRICTATIME; 787 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 788 789 attr.attr_clr = MOUNT_ATTR_NOATIME; 790 ASSERT_NE(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 791 792 old_flags = read_mnt_flags("/mnt/A"); 793 ASSERT_GT(old_flags, 0); 794 795 attr.attr_set = MOUNT_ATTR_NODIRATIME | MOUNT_ATTR_NOATIME; 796 attr.attr_clr = MOUNT_ATTR__ATIME; 797 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 798 799 expected_flags = old_flags; 800 expected_flags |= MS_NOATIME; 801 expected_flags |= MS_NODIRATIME; 802 803 new_flags = read_mnt_flags("/mnt/A"); 804 ASSERT_EQ(new_flags, expected_flags); 805 806 new_flags = read_mnt_flags("/mnt/A/AA"); 807 ASSERT_EQ(new_flags, expected_flags); 808 809 new_flags = read_mnt_flags("/mnt/A/AA/B"); 810 ASSERT_EQ(new_flags, expected_flags); 811 812 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 813 ASSERT_EQ(new_flags, expected_flags); 814 815 memset(&attr, 0, sizeof(attr)); 816 attr.attr_set &= ~MOUNT_ATTR_NOATIME; 817 attr.attr_set |= MOUNT_ATTR_RELATIME; 818 attr.attr_clr |= MOUNT_ATTR__ATIME; 819 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 820 821 expected_flags &= ~MS_NOATIME; 822 expected_flags |= MS_RELATIME; 823 824 new_flags = read_mnt_flags("/mnt/A"); 825 ASSERT_EQ(new_flags, expected_flags); 826 827 new_flags = read_mnt_flags("/mnt/A/AA"); 828 ASSERT_EQ(new_flags, expected_flags); 829 830 new_flags = read_mnt_flags("/mnt/A/AA/B"); 831 ASSERT_EQ(new_flags, expected_flags); 832 833 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 834 ASSERT_EQ(new_flags, expected_flags); 835 836 memset(&attr, 0, sizeof(attr)); 837 attr.attr_set &= ~MOUNT_ATTR_RELATIME; 838 attr.attr_set |= MOUNT_ATTR_STRICTATIME; 839 attr.attr_clr |= MOUNT_ATTR__ATIME; 840 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 841 842 expected_flags &= ~MS_RELATIME; 843 844 new_flags = read_mnt_flags("/mnt/A"); 845 ASSERT_EQ(new_flags, expected_flags); 846 847 new_flags = read_mnt_flags("/mnt/A/AA"); 848 ASSERT_EQ(new_flags, expected_flags); 849 850 new_flags = read_mnt_flags("/mnt/A/AA/B"); 851 ASSERT_EQ(new_flags, expected_flags); 852 853 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 854 ASSERT_EQ(new_flags, expected_flags); 855 856 memset(&attr, 0, sizeof(attr)); 857 attr.attr_set &= ~MOUNT_ATTR_STRICTATIME; 858 attr.attr_set |= MOUNT_ATTR_NOATIME; 859 attr.attr_clr |= MOUNT_ATTR__ATIME; 860 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 861 862 expected_flags |= MS_NOATIME; 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 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 877 878 new_flags = read_mnt_flags("/mnt/A"); 879 ASSERT_EQ(new_flags, expected_flags); 880 881 new_flags = read_mnt_flags("/mnt/A/AA"); 882 ASSERT_EQ(new_flags, expected_flags); 883 884 new_flags = read_mnt_flags("/mnt/A/AA/B"); 885 ASSERT_EQ(new_flags, expected_flags); 886 887 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 888 ASSERT_EQ(new_flags, expected_flags); 889 890 memset(&attr, 0, sizeof(attr)); 891 attr.attr_clr = MOUNT_ATTR_NODIRATIME; 892 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 893 894 expected_flags &= ~MS_NODIRATIME; 895 896 new_flags = read_mnt_flags("/mnt/A"); 897 ASSERT_EQ(new_flags, expected_flags); 898 899 new_flags = read_mnt_flags("/mnt/A/AA"); 900 ASSERT_EQ(new_flags, expected_flags); 901 902 new_flags = read_mnt_flags("/mnt/A/AA/B"); 903 ASSERT_EQ(new_flags, expected_flags); 904 905 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 906 ASSERT_EQ(new_flags, expected_flags); 907} 908 909TEST_F(mount_setattr, multi_threaded) 910{ 911 int i, j, nthreads, ret = 0; 912 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 913 pthread_attr_t pattr; 914 pthread_t threads[DEFAULT_THREADS]; 915 916 if (!mount_setattr_supported()) 917 SKIP(return, "mount_setattr syscall not supported"); 918 919 old_flags = read_mnt_flags("/mnt/A"); 920 ASSERT_GT(old_flags, 0); 921 922 /* Try to change mount options from multiple threads. */ 923 nthreads = get_nprocs_conf(); 924 if (nthreads > DEFAULT_THREADS) 925 nthreads = DEFAULT_THREADS; 926 927 pthread_attr_init(&pattr); 928 for (i = 0; i < nthreads; i++) 929 ASSERT_EQ(pthread_create(&threads[i], &pattr, mount_setattr_thread, NULL), 0); 930 931 for (j = 0; j < i; j++) { 932 void *retptr = NULL; 933 934 EXPECT_EQ(pthread_join(threads[j], &retptr), 0); 935 936 ret += ptr_to_int(retptr); 937 EXPECT_EQ(ret, 0); 938 } 939 pthread_attr_destroy(&pattr); 940 941 ASSERT_EQ(ret, 0); 942 943 expected_flags = old_flags; 944 expected_flags |= MS_RDONLY; 945 expected_flags |= MS_NOSUID; 946 new_flags = read_mnt_flags("/mnt/A"); 947 ASSERT_EQ(new_flags, expected_flags); 948 949 ASSERT_EQ(is_shared_mount("/mnt/A"), true); 950 951 new_flags = read_mnt_flags("/mnt/A/AA"); 952 ASSERT_EQ(new_flags, expected_flags); 953 954 ASSERT_EQ(is_shared_mount("/mnt/A/AA"), true); 955 956 new_flags = read_mnt_flags("/mnt/A/AA/B"); 957 ASSERT_EQ(new_flags, expected_flags); 958 959 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B"), true); 960 961 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 962 ASSERT_EQ(new_flags, expected_flags); 963 964 ASSERT_EQ(is_shared_mount("/mnt/A/AA/B/BB"), true); 965} 966 967TEST_F(mount_setattr, wrong_user_namespace) 968{ 969 int ret; 970 struct mount_attr attr = { 971 .attr_set = MOUNT_ATTR_RDONLY, 972 }; 973 974 if (!mount_setattr_supported()) 975 SKIP(return, "mount_setattr syscall not supported"); 976 977 EXPECT_EQ(create_and_enter_userns(), 0); 978 ret = sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)); 979 ASSERT_LT(ret, 0); 980 ASSERT_EQ(errno, EPERM); 981} 982 983TEST_F(mount_setattr, wrong_mount_namespace) 984{ 985 int fd, ret; 986 struct mount_attr attr = { 987 .attr_set = MOUNT_ATTR_RDONLY, 988 }; 989 990 if (!mount_setattr_supported()) 991 SKIP(return, "mount_setattr syscall not supported"); 992 993 fd = open("/mnt/A", O_DIRECTORY | O_CLOEXEC); 994 ASSERT_GE(fd, 0); 995 996 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 997 998 ret = sys_mount_setattr(fd, "", AT_EMPTY_PATH | AT_RECURSIVE, &attr, sizeof(attr)); 999 ASSERT_LT(ret, 0); 1000 ASSERT_EQ(errno, EINVAL); 1001} 1002 1003FIXTURE(mount_setattr_idmapped) { 1004}; 1005 1006FIXTURE_SETUP(mount_setattr_idmapped) 1007{ 1008 int img_fd = -EBADF; 1009 1010 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 1011 1012 ASSERT_EQ(mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0), 0); 1013 1014 (void)umount2("/mnt", MNT_DETACH); 1015 (void)umount2("/tmp", MNT_DETACH); 1016 1017 ASSERT_EQ(mount("testing", "/tmp", "tmpfs", MS_NOATIME | MS_NODEV, 1018 "size=100000,mode=700"), 0); 1019 1020 ASSERT_EQ(mkdir("/tmp/B", 0777), 0); 1021 ASSERT_EQ(mknodat(-EBADF, "/tmp/B/b", S_IFREG | 0644, 0), 0); 1022 ASSERT_EQ(chown("/tmp/B/b", 0, 0), 0); 1023 1024 ASSERT_EQ(mount("testing", "/tmp/B", "tmpfs", MS_NOATIME | MS_NODEV, 1025 "size=100000,mode=700"), 0); 1026 1027 ASSERT_EQ(mkdir("/tmp/B/BB", 0777), 0); 1028 ASSERT_EQ(mknodat(-EBADF, "/tmp/B/BB/b", S_IFREG | 0644, 0), 0); 1029 ASSERT_EQ(chown("/tmp/B/BB/b", 0, 0), 0); 1030 1031 ASSERT_EQ(mount("testing", "/tmp/B/BB", "tmpfs", MS_NOATIME | MS_NODEV, 1032 "size=100000,mode=700"), 0); 1033 1034 ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV, 1035 "size=100000,mode=700"), 0); 1036 1037 ASSERT_EQ(mkdir("/mnt/A", 0777), 0); 1038 1039 ASSERT_EQ(mount("testing", "/mnt/A", "tmpfs", MS_NOATIME | MS_NODEV, 1040 "size=100000,mode=700"), 0); 1041 1042 ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0); 1043 1044 ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0); 1045 1046 ASSERT_EQ(mkdir("/mnt/B", 0777), 0); 1047 1048 ASSERT_EQ(mount("testing", "/mnt/B", "ramfs", 1049 MS_NOATIME | MS_NODEV | MS_NOSUID, 0), 0); 1050 1051 ASSERT_EQ(mkdir("/mnt/B/BB", 0777), 0); 1052 1053 ASSERT_EQ(mount("testing", "/tmp/B/BB", "devpts", 1054 MS_RELATIME | MS_NOEXEC | MS_RDONLY, 0), 0); 1055 1056 ASSERT_EQ(mkdir("/mnt/C", 0777), 0); 1057 ASSERT_EQ(mkdir("/mnt/D", 0777), 0); 1058 img_fd = openat(-EBADF, "/mnt/C/ext4.img", O_CREAT | O_WRONLY, 0600); 1059 ASSERT_GE(img_fd, 0); 1060 ASSERT_EQ(ftruncate(img_fd, 1024 * 2048), 0); 1061 ASSERT_EQ(system("mkfs.ext4 -q /mnt/C/ext4.img"), 0); 1062 ASSERT_EQ(system("mount -o loop -t ext4 /mnt/C/ext4.img /mnt/D/"), 0); 1063 ASSERT_EQ(close(img_fd), 0); 1064} 1065 1066FIXTURE_TEARDOWN(mount_setattr_idmapped) 1067{ 1068 (void)umount2("/mnt/A", MNT_DETACH); 1069 (void)umount2("/tmp", MNT_DETACH); 1070} 1071 1072/** 1073 * Validate that negative fd values are rejected. 1074 */ 1075TEST_F(mount_setattr_idmapped, invalid_fd_negative) 1076{ 1077 struct mount_attr attr = { 1078 .attr_set = MOUNT_ATTR_IDMAP, 1079 .userns_fd = -EBADF, 1080 }; 1081 1082 if (!mount_setattr_supported()) 1083 SKIP(return, "mount_setattr syscall not supported"); 1084 1085 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) { 1086 TH_LOG("failure: created idmapped mount with negative fd"); 1087 } 1088} 1089 1090/** 1091 * Validate that excessively large fd values are rejected. 1092 */ 1093TEST_F(mount_setattr_idmapped, invalid_fd_large) 1094{ 1095 struct mount_attr attr = { 1096 .attr_set = MOUNT_ATTR_IDMAP, 1097 .userns_fd = INT64_MAX, 1098 }; 1099 1100 if (!mount_setattr_supported()) 1101 SKIP(return, "mount_setattr syscall not supported"); 1102 1103 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) { 1104 TH_LOG("failure: created idmapped mount with too large fd value"); 1105 } 1106} 1107 1108/** 1109 * Validate that closed fd values are rejected. 1110 */ 1111TEST_F(mount_setattr_idmapped, invalid_fd_closed) 1112{ 1113 int fd; 1114 struct mount_attr attr = { 1115 .attr_set = MOUNT_ATTR_IDMAP, 1116 }; 1117 1118 if (!mount_setattr_supported()) 1119 SKIP(return, "mount_setattr syscall not supported"); 1120 1121 fd = open("/dev/null", O_RDONLY | O_CLOEXEC); 1122 ASSERT_GE(fd, 0); 1123 ASSERT_GE(close(fd), 0); 1124 1125 attr.userns_fd = fd; 1126 ASSERT_NE(sys_mount_setattr(-1, "/", 0, &attr, sizeof(attr)), 0) { 1127 TH_LOG("failure: created idmapped mount with closed fd"); 1128 } 1129} 1130 1131/** 1132 * Validate that the initial user namespace is rejected. 1133 */ 1134TEST_F(mount_setattr_idmapped, invalid_fd_initial_userns) 1135{ 1136 int open_tree_fd = -EBADF; 1137 struct mount_attr attr = { 1138 .attr_set = MOUNT_ATTR_IDMAP, 1139 }; 1140 1141 if (!mount_setattr_supported()) 1142 SKIP(return, "mount_setattr syscall not supported"); 1143 1144 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D", 1145 AT_NO_AUTOMOUNT | 1146 AT_SYMLINK_NOFOLLOW | 1147 OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE); 1148 ASSERT_GE(open_tree_fd, 0); 1149 1150 attr.userns_fd = open("/proc/1/ns/user", O_RDONLY | O_CLOEXEC); 1151 ASSERT_GE(attr.userns_fd, 0); 1152 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1153 ASSERT_EQ(errno, EPERM); 1154 ASSERT_EQ(close(attr.userns_fd), 0); 1155 ASSERT_EQ(close(open_tree_fd), 0); 1156} 1157 1158static int map_ids(pid_t pid, unsigned long nsid, unsigned long hostid, 1159 unsigned long range) 1160{ 1161 char map[100], procfile[256]; 1162 1163 snprintf(procfile, sizeof(procfile), "/proc/%d/uid_map", pid); 1164 snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range); 1165 if (write_file(procfile, map, strlen(map))) 1166 return -1; 1167 1168 1169 snprintf(procfile, sizeof(procfile), "/proc/%d/gid_map", pid); 1170 snprintf(map, sizeof(map), "%lu %lu %lu", nsid, hostid, range); 1171 if (write_file(procfile, map, strlen(map))) 1172 return -1; 1173 1174 return 0; 1175} 1176 1177#define __STACK_SIZE (8 * 1024 * 1024) 1178static pid_t do_clone(int (*fn)(void *), void *arg, int flags) 1179{ 1180 void *stack; 1181 1182 stack = malloc(__STACK_SIZE); 1183 if (!stack) 1184 return -ENOMEM; 1185 1186#ifdef __ia64__ 1187 return __clone2(fn, stack, __STACK_SIZE, flags | SIGCHLD, arg, NULL); 1188#else 1189 return clone(fn, stack + __STACK_SIZE, flags | SIGCHLD, arg, NULL); 1190#endif 1191} 1192 1193static int get_userns_fd_cb(void *data) 1194{ 1195 return kill(getpid(), SIGSTOP); 1196} 1197 1198static int wait_for_pid(pid_t pid) 1199{ 1200 int status, ret; 1201 1202again: 1203 ret = waitpid(pid, &status, 0); 1204 if (ret == -1) { 1205 if (errno == EINTR) 1206 goto again; 1207 1208 return -1; 1209 } 1210 1211 if (!WIFEXITED(status)) 1212 return -1; 1213 1214 return WEXITSTATUS(status); 1215} 1216 1217static int get_userns_fd(unsigned long nsid, unsigned long hostid, unsigned long range) 1218{ 1219 int ret; 1220 pid_t pid; 1221 char path[256]; 1222 1223 pid = do_clone(get_userns_fd_cb, NULL, CLONE_NEWUSER); 1224 if (pid < 0) 1225 return -errno; 1226 1227 ret = map_ids(pid, nsid, hostid, range); 1228 if (ret < 0) 1229 return ret; 1230 1231 snprintf(path, sizeof(path), "/proc/%d/ns/user", pid); 1232 ret = open(path, O_RDONLY | O_CLOEXEC); 1233 kill(pid, SIGKILL); 1234 wait_for_pid(pid); 1235 return ret; 1236} 1237 1238/** 1239 * Validate that an attached mount in our mount namespace cannot be idmapped. 1240 * (The kernel enforces that the mount's mount namespace and the caller's mount 1241 * namespace match.) 1242 */ 1243TEST_F(mount_setattr_idmapped, attached_mount_inside_current_mount_namespace) 1244{ 1245 int open_tree_fd = -EBADF; 1246 struct mount_attr attr = { 1247 .attr_set = MOUNT_ATTR_IDMAP, 1248 }; 1249 1250 if (!mount_setattr_supported()) 1251 SKIP(return, "mount_setattr syscall not supported"); 1252 1253 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D", 1254 AT_EMPTY_PATH | 1255 AT_NO_AUTOMOUNT | 1256 AT_SYMLINK_NOFOLLOW | 1257 OPEN_TREE_CLOEXEC); 1258 ASSERT_GE(open_tree_fd, 0); 1259 1260 attr.userns_fd = get_userns_fd(0, 10000, 10000); 1261 ASSERT_GE(attr.userns_fd, 0); 1262 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1263 ASSERT_EQ(close(attr.userns_fd), 0); 1264 ASSERT_EQ(close(open_tree_fd), 0); 1265} 1266 1267/** 1268 * Validate that idmapping a mount is rejected if the mount's mount namespace 1269 * and our mount namespace don't match. 1270 * (The kernel enforces that the mount's mount namespace and the caller's mount 1271 * namespace match.) 1272 */ 1273TEST_F(mount_setattr_idmapped, attached_mount_outside_current_mount_namespace) 1274{ 1275 int open_tree_fd = -EBADF; 1276 struct mount_attr attr = { 1277 .attr_set = MOUNT_ATTR_IDMAP, 1278 }; 1279 1280 if (!mount_setattr_supported()) 1281 SKIP(return, "mount_setattr syscall not supported"); 1282 1283 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D", 1284 AT_EMPTY_PATH | 1285 AT_NO_AUTOMOUNT | 1286 AT_SYMLINK_NOFOLLOW | 1287 OPEN_TREE_CLOEXEC); 1288 ASSERT_GE(open_tree_fd, 0); 1289 1290 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 1291 1292 attr.userns_fd = get_userns_fd(0, 10000, 10000); 1293 ASSERT_GE(attr.userns_fd, 0); 1294 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, 1295 sizeof(attr)), 0); 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 */ 1303TEST_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 */ 1333TEST_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/** 1363 * Validate that currently changing the idmapping of an idmapped mount fails. 1364 */ 1365TEST_F(mount_setattr_idmapped, change_idmapping) 1366{ 1367 int open_tree_fd = -EBADF; 1368 struct mount_attr attr = { 1369 .attr_set = MOUNT_ATTR_IDMAP, 1370 }; 1371 1372 if (!mount_setattr_supported()) 1373 SKIP(return, "mount_setattr syscall not supported"); 1374 1375 open_tree_fd = sys_open_tree(-EBADF, "/mnt/D", 1376 AT_EMPTY_PATH | 1377 AT_NO_AUTOMOUNT | 1378 AT_SYMLINK_NOFOLLOW | 1379 OPEN_TREE_CLOEXEC | 1380 OPEN_TREE_CLONE); 1381 ASSERT_GE(open_tree_fd, 0); 1382 1383 attr.userns_fd = get_userns_fd(0, 10000, 10000); 1384 ASSERT_GE(attr.userns_fd, 0); 1385 ASSERT_EQ(sys_mount_setattr(open_tree_fd, "", 1386 AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1387 ASSERT_EQ(close(attr.userns_fd), 0); 1388 1389 /* Change idmapping on a detached mount that is already idmapped. */ 1390 attr.userns_fd = get_userns_fd(0, 20000, 10000); 1391 ASSERT_GE(attr.userns_fd, 0); 1392 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1393 ASSERT_EQ(close(attr.userns_fd), 0); 1394 ASSERT_EQ(close(open_tree_fd), 0); 1395} 1396 1397static bool expected_uid_gid(int dfd, const char *path, int flags, 1398 uid_t expected_uid, gid_t expected_gid) 1399{ 1400 int ret; 1401 struct stat st; 1402 1403 ret = fstatat(dfd, path, &st, flags); 1404 if (ret < 0) 1405 return false; 1406 1407 return st.st_uid == expected_uid && st.st_gid == expected_gid; 1408} 1409 1410TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid) 1411{ 1412 int open_tree_fd = -EBADF; 1413 struct mount_attr attr = { 1414 .attr_set = MOUNT_ATTR_IDMAP, 1415 }; 1416 1417 if (!mount_setattr_supported()) 1418 SKIP(return, "mount_setattr syscall not supported"); 1419 1420 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0); 1421 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0); 1422 1423 open_tree_fd = sys_open_tree(-EBADF, "/mnt/A", 1424 AT_RECURSIVE | 1425 AT_EMPTY_PATH | 1426 AT_NO_AUTOMOUNT | 1427 AT_SYMLINK_NOFOLLOW | 1428 OPEN_TREE_CLOEXEC | 1429 OPEN_TREE_CLONE); 1430 ASSERT_GE(open_tree_fd, 0); 1431 1432 attr.userns_fd = get_userns_fd(0, 10000, 10000); 1433 ASSERT_GE(attr.userns_fd, 0); 1434 ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0); 1435 ASSERT_EQ(close(attr.userns_fd), 0); 1436 ASSERT_EQ(close(open_tree_fd), 0); 1437 1438 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0); 1439 ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0); 1440 ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/b", 0, 0, 0), 0); 1441 ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/BB/b", 0, 0, 0), 0); 1442} 1443 1444TEST_F(mount_setattr, mount_attr_nosymfollow) 1445{ 1446 int fd; 1447 unsigned int old_flags = 0, new_flags = 0, expected_flags = 0; 1448 struct mount_attr attr = { 1449 .attr_set = MOUNT_ATTR_NOSYMFOLLOW, 1450 }; 1451 1452 if (!mount_setattr_supported()) 1453 SKIP(return, "mount_setattr syscall not supported"); 1454 1455 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC); 1456 ASSERT_GT(fd, 0); 1457 ASSERT_EQ(close(fd), 0); 1458 1459 old_flags = read_mnt_flags("/mnt/A"); 1460 ASSERT_GT(old_flags, 0); 1461 1462 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 1463 1464 expected_flags = old_flags; 1465 expected_flags |= ST_NOSYMFOLLOW; 1466 1467 new_flags = read_mnt_flags("/mnt/A"); 1468 ASSERT_EQ(new_flags, expected_flags); 1469 1470 new_flags = read_mnt_flags("/mnt/A/AA"); 1471 ASSERT_EQ(new_flags, expected_flags); 1472 1473 new_flags = read_mnt_flags("/mnt/A/AA/B"); 1474 ASSERT_EQ(new_flags, expected_flags); 1475 1476 new_flags = read_mnt_flags("/mnt/A/AA/B/BB"); 1477 ASSERT_EQ(new_flags, expected_flags); 1478 1479 fd = open(NOSYMFOLLOW_SYMLINK, O_RDWR | O_CLOEXEC); 1480 ASSERT_LT(fd, 0); 1481 ASSERT_EQ(errno, ELOOP); 1482 1483 attr.attr_set &= ~MOUNT_ATTR_NOSYMFOLLOW; 1484 attr.attr_clr |= MOUNT_ATTR_NOSYMFOLLOW; 1485 1486 ASSERT_EQ(sys_mount_setattr(-1, "/mnt/A", AT_RECURSIVE, &attr, sizeof(attr)), 0); 1487 1488 expected_flags &= ~ST_NOSYMFOLLOW; 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_GT(fd, 0); 1503 ASSERT_EQ(close(fd), 0); 1504} 1505 1506TEST_HARNESS_MAIN