gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/mount.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <errno.h> 16 #include <fcntl.h> 17 #include <linux/capability.h> 18 #include <linux/magic.h> 19 #include <sched.h> 20 #include <stdio.h> 21 #include <sys/eventfd.h> 22 #include <sys/mman.h> 23 #include <sys/mount.h> 24 #include <sys/resource.h> 25 #include <sys/signalfd.h> 26 #include <sys/socket.h> 27 #include <sys/stat.h> 28 #include <sys/statfs.h> 29 #include <sys/un.h> 30 #include <sys/vfs.h> 31 #include <unistd.h> 32 33 #include <cerrno> 34 #include <cmath> 35 #include <cstdint> 36 #include <cstdlib> 37 #include <functional> 38 #include <iostream> 39 #include <memory> 40 #include <ostream> 41 #include <string> 42 #include <tuple> 43 #include <utility> 44 #include <vector> 45 46 #include "gmock/gmock.h" 47 #include "gtest/gtest.h" 48 #include "absl/container/flat_hash_map.h" 49 #include "absl/strings/match.h" 50 #include "absl/strings/numbers.h" 51 #include "absl/strings/str_cat.h" 52 #include "absl/strings/str_format.h" 53 #include "absl/strings/str_split.h" 54 #include "absl/strings/string_view.h" 55 #include "absl/strings/substitute.h" 56 #include "absl/time/clock.h" 57 #include "absl/time/time.h" 58 #include "test/util/capability_util.h" 59 #include "test/util/cleanup.h" 60 #include "test/util/eventfd_util.h" 61 #include "test/util/file_descriptor.h" 62 #include "test/util/fs_util.h" 63 #include "test/util/linux_capability_util.h" 64 #include "test/util/logging.h" 65 #include "test/util/mount_util.h" 66 #include "test/util/multiprocess_util.h" 67 #include "test/util/posix_error.h" 68 #include "test/util/save_util.h" 69 #include "test/util/temp_path.h" 70 #include "test/util/test_util.h" 71 #include "test/util/thread_util.h" 72 73 namespace gvisor { 74 namespace testing { 75 76 namespace { 77 78 using ::testing::AnyOf; 79 using ::testing::Contains; 80 using ::testing::Pair; 81 82 constexpr char kTmpfs[] = "tmpfs"; 83 84 TEST(MountTest, MountBadFilesystem) { 85 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 86 87 // Linux expects a valid target before it checks the file system name. 88 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 89 EXPECT_THAT(mount("", dir.path().c_str(), "foobar", 0, ""), 90 SyscallFailsWithErrno(ENODEV)); 91 } 92 93 TEST(MountTest, MountInvalidTarget) { 94 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 95 96 auto const dir = NewTempAbsPath(); 97 EXPECT_THAT(mount("", dir.c_str(), kTmpfs, 0, ""), 98 SyscallFailsWithErrno(ENOENT)); 99 } 100 101 TEST(MountTest, MountPermDenied) { 102 // Clear CAP_SYS_ADMIN. 103 AutoCapability cap(CAP_SYS_ADMIN, false); 104 105 // Linux expects a valid target before checking capability. 106 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 107 EXPECT_THAT(mount("", dir.path().c_str(), "", 0, ""), 108 SyscallFailsWithErrno(EPERM)); 109 } 110 111 TEST(MountTest, UmountPermDenied) { 112 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 113 114 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 115 auto const mount = 116 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir.path(), kTmpfs, 0, "", 0)); 117 118 // Drop privileges in another thread, so we can still unmount the mounted 119 // directory. 120 ScopedThread([&]() { 121 EXPECT_NO_ERRNO(SetCapability(CAP_SYS_ADMIN, false)); 122 EXPECT_THAT(umount(dir.path().c_str()), SyscallFailsWithErrno(EPERM)); 123 }); 124 } 125 126 TEST(MountTest, MountOverBusy) { 127 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 128 129 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 130 auto const fd = ASSERT_NO_ERRNO_AND_VALUE( 131 Open(JoinPath(dir.path(), "foo"), O_CREAT | O_RDWR, 0777)); 132 133 // Should be able to mount over a busy directory. 134 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir.path(), kTmpfs, 0, "", 0)); 135 } 136 137 TEST(MountTest, OpenFileBusy) { 138 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 139 140 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 141 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 142 Mount("", dir.path(), kTmpfs, 0, "mode=0700", 0)); 143 auto const fd = ASSERT_NO_ERRNO_AND_VALUE( 144 Open(JoinPath(dir.path(), "foo"), O_CREAT | O_RDWR, 0777)); 145 146 // An open file should prevent unmounting. 147 EXPECT_THAT(umount(dir.path().c_str()), SyscallFailsWithErrno(EBUSY)); 148 } 149 150 TEST(MountTest, UmountNoFollow) { 151 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 152 153 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 154 155 auto const mountPoint = NewTempAbsPathInDir(dir.path()); 156 ASSERT_THAT(mkdir(mountPoint.c_str(), 0777), SyscallSucceeds()); 157 158 // Create a symlink in dir which will point to the actual mountpoint. 159 const std::string symlinkInDir = NewTempAbsPathInDir(dir.path()); 160 EXPECT_THAT(symlink(mountPoint.c_str(), symlinkInDir.c_str()), 161 SyscallSucceeds()); 162 163 // Create a symlink to the dir. 164 const std::string symlinkToDir = NewTempAbsPath(); 165 EXPECT_THAT(symlink(dir.path().c_str(), symlinkToDir.c_str()), 166 SyscallSucceeds()); 167 168 // Should fail with ELOOP when UMOUNT_NOFOLLOW is specified and the last 169 // component is a symlink. 170 auto mount = ASSERT_NO_ERRNO_AND_VALUE( 171 Mount("", mountPoint, kTmpfs, 0, "mode=0700", 0)); 172 EXPECT_THAT(umount2(symlinkInDir.c_str(), UMOUNT_NOFOLLOW), 173 SyscallFailsWithErrno(EINVAL)); 174 EXPECT_THAT(unlink(symlinkInDir.c_str()), SyscallSucceeds()); 175 176 // UMOUNT_NOFOLLOW should only apply to the last path component. A symlink in 177 // non-last path component should be just fine. 178 EXPECT_THAT(umount2(JoinPath(symlinkToDir, Basename(mountPoint)).c_str(), 179 UMOUNT_NOFOLLOW), 180 SyscallSucceeds()); 181 mount.Release(); 182 } 183 184 TEST(MountTest, UmountDetach) { 185 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 186 187 // structure: 188 // 189 // dir (mount point) 190 // subdir 191 // file 192 // 193 // We show that we can walk around in the mount after detach-unmount dir. 194 // 195 // We show that even though dir is unreachable from outside the mount, we can 196 // still reach dir's (former) parent! 197 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 198 199 const struct stat before = ASSERT_NO_ERRNO_AND_VALUE(Stat(dir.path())); 200 auto mount = 201 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir.path(), kTmpfs, 0, "mode=0700", 202 /* umountflags= */ MNT_DETACH)); 203 const struct stat after = ASSERT_NO_ERRNO_AND_VALUE(Stat(dir.path())); 204 EXPECT_FALSE(before.st_dev == after.st_dev && before.st_ino == after.st_ino) 205 << "mount point has device number " << before.st_dev 206 << " and inode number " << before.st_ino << " before and after mount"; 207 208 // Create files in the new mount. 209 constexpr char kContents[] = "no no no"; 210 auto const subdir = 211 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path())); 212 auto const file = ASSERT_NO_ERRNO_AND_VALUE( 213 TempPath::CreateFileWith(dir.path(), kContents, 0777)); 214 215 auto const dir_fd = 216 ASSERT_NO_ERRNO_AND_VALUE(Open(subdir.path(), O_RDONLY | O_DIRECTORY)); 217 auto const fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDONLY)); 218 219 // Unmount the tmpfs. 220 mount.Release()(); 221 222 // Inode numbers for gofer-accessed files may change across save/restore. 223 // 224 // For overlayfs, if xino option is not enabled and if all overlayfs layers do 225 // not belong to the same filesystem then "the value of st_ino for directory 226 // objects may not be persistent and could change even while the overlay 227 // filesystem is mounted." -- Documentation/filesystems/overlayfs.txt 228 if (!IsRunningWithSaveRestore() && 229 !ASSERT_NO_ERRNO_AND_VALUE(IsOverlayfs(dir.path()))) { 230 const struct stat after2 = ASSERT_NO_ERRNO_AND_VALUE(Stat(dir.path())); 231 EXPECT_EQ(before.st_ino, after2.st_ino); 232 } 233 234 // Can still read file after unmounting. 235 std::vector<char> buf(sizeof(kContents)); 236 EXPECT_THAT(ReadFd(fd.get(), buf.data(), buf.size()), SyscallSucceeds()); 237 238 // Walk to dir. 239 auto const mounted_dir = ASSERT_NO_ERRNO_AND_VALUE( 240 OpenAt(dir_fd.get(), "..", O_DIRECTORY | O_RDONLY)); 241 // Walk to dir/file. 242 auto const fd_again = ASSERT_NO_ERRNO_AND_VALUE( 243 OpenAt(mounted_dir.get(), std::string(Basename(file.path())), O_RDONLY)); 244 245 std::vector<char> buf2(sizeof(kContents)); 246 EXPECT_THAT(ReadFd(fd_again.get(), buf2.data(), buf2.size()), 247 SyscallSucceeds()); 248 EXPECT_EQ(buf, buf2); 249 250 // Walking outside the unmounted realm should still work, too! 251 auto const dir_parent = ASSERT_NO_ERRNO_AND_VALUE( 252 OpenAt(mounted_dir.get(), "..", O_DIRECTORY | O_RDONLY)); 253 } 254 255 TEST(MountTest, UmountMountsStackedOnDot) { 256 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 257 // Verify that unmounting at "." properly unmounts the mount at the top of 258 // mount stack. 259 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 260 TEST_CHECK_SUCCESS(chdir(dir.path().c_str())); 261 const struct stat before = ASSERT_NO_ERRNO_AND_VALUE(Stat(".")); 262 263 TEST_CHECK_SUCCESS(mount("", dir.path().c_str(), kTmpfs, 0, "mode=0700")); 264 TEST_CHECK_SUCCESS(mount("", dir.path().c_str(), kTmpfs, 0, "mode=0700")); 265 266 // Unmount the second mount at "." 267 TEST_CHECK_SUCCESS(umount2(".", MNT_DETACH)); 268 269 // Unmount the first mount at "."; this will fail if umount does not resolve 270 // "." to the topmost mount. 271 TEST_CHECK_SUCCESS(umount2(".", MNT_DETACH)); 272 const struct stat after2 = ASSERT_NO_ERRNO_AND_VALUE(Stat(".")); 273 EXPECT_TRUE(before.st_dev == after2.st_dev && before.st_ino == after2.st_ino); 274 } 275 276 TEST(MountTest, ActiveSubmountBusy) { 277 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 278 279 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 280 auto const mount1 = ASSERT_NO_ERRNO_AND_VALUE( 281 Mount("", dir.path(), kTmpfs, 0, "mode=0700", 0)); 282 283 auto const dir2 = 284 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path())); 285 auto const mount2 = 286 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir2.path(), kTmpfs, 0, "", 0)); 287 288 // Since dir now has an active submount, should not be able to unmount. 289 EXPECT_THAT(umount(dir.path().c_str()), SyscallFailsWithErrno(EBUSY)); 290 } 291 292 TEST(MountTest, MountTmpfs) { 293 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 294 295 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 296 297 // NOTE(b/129868551): Inode IDs are only stable across S/R if we have an open 298 // FD for that inode. Since we are going to compare inode IDs below, get a 299 // FileDescriptor for this directory here, which will be closed automatically 300 // at the end of the test. 301 auto const fd = 302 ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_DIRECTORY, O_RDONLY)); 303 304 const struct stat before = ASSERT_NO_ERRNO_AND_VALUE(Stat(dir.path())); 305 306 { 307 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 308 Mount("", dir.path(), kTmpfs, 0, "mode=0700", 0)); 309 310 const struct stat s = ASSERT_NO_ERRNO_AND_VALUE(Stat(dir.path())); 311 EXPECT_EQ(s.st_mode, S_IFDIR | 0700); 312 EXPECT_FALSE(before.st_dev == s.st_dev && before.st_ino == s.st_ino) 313 << "mount point has device number " << before.st_dev 314 << " and inode number " << before.st_ino << " before and after mount"; 315 316 EXPECT_NO_ERRNO(Open(JoinPath(dir.path(), "foo"), O_CREAT | O_RDWR, 0777)); 317 } 318 319 // Now that dir is unmounted again, we should have the old inode back. 320 // 321 // Inode numbers for gofer-accessed files may change across save/restore. 322 // 323 // For overlayfs, if xino option is not enabled and if all overlayfs layers do 324 // not belong to the same filesystem then "the value of st_ino for directory 325 // objects may not be persistent and could change even while the overlay 326 // filesystem is mounted." -- Documentation/filesystems/overlayfs.txt 327 if (!IsRunningWithSaveRestore() && 328 !ASSERT_NO_ERRNO_AND_VALUE(IsOverlayfs(dir.path()))) { 329 const struct stat after = ASSERT_NO_ERRNO_AND_VALUE(Stat(dir.path())); 330 EXPECT_EQ(before.st_ino, after.st_ino); 331 } 332 } 333 334 TEST(MountTest, MountTmpfsMagicValIgnored) { 335 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 336 337 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 338 339 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 340 Mount("", dir.path(), kTmpfs, MS_MGC_VAL, "mode=0700", 0)); 341 } 342 343 // Passing nullptr to data is equivalent to "". 344 TEST(MountTest, NullData) { 345 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 346 347 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 348 349 EXPECT_THAT(mount("", dir.path().c_str(), kTmpfs, 0, nullptr), 350 SyscallSucceeds()); 351 EXPECT_THAT(umount2(dir.path().c_str(), 0), SyscallSucceeds()); 352 } 353 354 TEST(MountTest, MountReadonly) { 355 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 356 357 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 358 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 359 Mount("", dir.path(), kTmpfs, MS_RDONLY, "mode=0777", 0)); 360 361 const struct stat s = ASSERT_NO_ERRNO_AND_VALUE(Stat(dir.path())); 362 EXPECT_EQ(s.st_mode, S_IFDIR | 0777); 363 364 EXPECT_THAT(access(dir.path().c_str(), W_OK), SyscallFailsWithErrno(EROFS)); 365 366 std::string const filename = JoinPath(dir.path(), "foo"); 367 EXPECT_THAT(open(filename.c_str(), O_RDWR | O_CREAT, 0777), 368 SyscallFailsWithErrno(EROFS)); 369 } 370 371 PosixErrorOr<absl::Time> ATime(absl::string_view file) { 372 struct stat s = {}; 373 if (stat(std::string(file).c_str(), &s) == -1) { 374 return PosixError(errno, "stat failed"); 375 } 376 return absl::TimeFromTimespec(s.st_atim); 377 } 378 379 TEST(MountTest, MountNoAtime) { 380 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 381 382 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 383 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 384 Mount("", dir.path(), kTmpfs, MS_NOATIME, "mode=0777", 0)); 385 386 std::string const contents = "No no no, don't follow the instructions!"; 387 auto const file = ASSERT_NO_ERRNO_AND_VALUE( 388 TempPath::CreateFileWith(dir.path(), contents, 0777)); 389 390 absl::Time const before = ASSERT_NO_ERRNO_AND_VALUE(ATime(file.path())); 391 392 // Reading from the file should change the atime, but the MS_NOATIME flag 393 // should prevent that. 394 auto const fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR)); 395 char buf[100]; 396 int read_n; 397 ASSERT_THAT(read_n = read(fd.get(), buf, sizeof(buf)), SyscallSucceeds()); 398 EXPECT_EQ(std::string(buf, read_n), contents); 399 400 absl::Time const after = ASSERT_NO_ERRNO_AND_VALUE(ATime(file.path())); 401 402 // Expect that atime hasn't changed. 403 EXPECT_EQ(before, after); 404 } 405 406 TEST(MountTest, MountWithStrictAtime) { 407 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 408 409 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 410 auto const mount = ASSERT_NO_ERRNO_AND_VALUE(Mount( 411 "", dir.path(), kTmpfs, MS_NOATIME | MS_STRICTATIME, "mode=0777", 0)); 412 413 std::string const contents = "No no no, don't follow the instructions!"; 414 auto const file = ASSERT_NO_ERRNO_AND_VALUE( 415 TempPath::CreateFileWith(dir.path(), contents, 0777)); 416 417 absl::Time const before = ASSERT_NO_ERRNO_AND_VALUE(ATime(file.path())); 418 419 absl::SleepFor(absl::Milliseconds(100)); 420 421 // MS_STRICTATIME should override MS_NOATIME and update the file's atime. 422 auto const fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR)); 423 char buf[100]; 424 int read_n; 425 ASSERT_THAT(read_n = read(fd.get(), buf, sizeof(buf)), SyscallSucceeds()); 426 EXPECT_EQ(std::string(buf, read_n), contents); 427 428 absl::Time const after = ASSERT_NO_ERRNO_AND_VALUE(ATime(file.path())); 429 430 // The after atime is expected to be larger than the before atime. 431 EXPECT_LT(before, after); 432 } 433 434 TEST(MountTest, MountNoExec) { 435 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 436 437 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 438 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 439 Mount("", dir.path(), kTmpfs, MS_NOEXEC, "mode=0777", 0)); 440 441 std::string const contents = "No no no, don't follow the instructions!"; 442 auto const file = ASSERT_NO_ERRNO_AND_VALUE( 443 TempPath::CreateFileWith(dir.path(), contents, 0777)); 444 445 int execve_errno; 446 ASSERT_NO_ERRNO_AND_VALUE( 447 ForkAndExec(file.path(), {}, {}, nullptr, &execve_errno)); 448 EXPECT_EQ(execve_errno, EACCES); 449 } 450 451 TEST(MountTest, RenameRemoveMountPoint) { 452 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 453 454 auto const dir_parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 455 auto const dir = 456 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir_parent.path())); 457 auto const new_dir = NewTempAbsPath(); 458 459 auto const mount = 460 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir.path(), kTmpfs, 0, "", 0)); 461 462 ASSERT_THAT(rename(dir.path().c_str(), new_dir.c_str()), 463 SyscallFailsWithErrno(EBUSY)); 464 465 ASSERT_THAT(rmdir(dir.path().c_str()), SyscallFailsWithErrno(EBUSY)); 466 } 467 468 TEST(MountTest, MountInfo) { 469 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 470 471 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 472 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 473 Mount("", dir.path(), kTmpfs, MS_NOEXEC, "mode=0123", 0)); 474 const std::vector<ProcMountsEntry> mounts = 475 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountsEntries()); 476 for (const auto& e : mounts) { 477 if (e.mount_point == dir.path()) { 478 EXPECT_EQ(e.fstype, kTmpfs); 479 auto mopts = ParseMountOptions(e.mount_opts); 480 EXPECT_THAT(mopts, AnyOf(Contains(Pair("mode", "0123")), 481 Contains(Pair("mode", "123")))); 482 } 483 } 484 485 const std::vector<ProcMountInfoEntry> mountinfo = 486 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); 487 488 for (auto const& e : mountinfo) { 489 if (e.mount_point == dir.path()) { 490 EXPECT_EQ(e.fstype, kTmpfs); 491 auto mopts = ParseMountOptions(e.super_opts); 492 EXPECT_THAT(mopts, AnyOf(Contains(Pair("mode", "0123")), 493 Contains(Pair("mode", "123")))); 494 } 495 } 496 } 497 498 TEST(MountTest, TmpfsSizeRoundUpSinglePageSize) { 499 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 500 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 501 auto tmpfs_size_opt = absl::StrCat("size=", kPageSize / 2); 502 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 503 Mount("", dir.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 504 auto fd = ASSERT_NO_ERRNO_AND_VALUE( 505 Open(JoinPath(dir.path(), "foo"), O_CREAT | O_RDWR, 0777)); 506 507 // Check that it starts at size zero. 508 struct stat buf; 509 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 510 EXPECT_EQ(buf.st_size, 0); 511 512 // Grow to 1 Page Size. 513 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize), SyscallSucceeds()); 514 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 515 EXPECT_EQ(buf.st_size, kPageSize); 516 517 // Grow to size beyond tmpfs allocated bytes. 518 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize + 1), 519 SyscallFailsWithErrno(ENOSPC)); 520 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 521 EXPECT_EQ(buf.st_size, kPageSize); 522 } 523 524 TEST(MountTest, TmpfsSizeAllocationMultiplePages) { 525 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 526 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 527 auto page_multiple = 2; 528 auto size = kPageSize * page_multiple; 529 auto tmpfs_size_opt = absl::StrCat("size=", size); 530 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 531 Mount("", dir.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 532 auto fd = ASSERT_NO_ERRNO_AND_VALUE( 533 Open(JoinPath(dir.path(), "foo"), O_CREAT | O_RDWR, 0777)); 534 535 // Check that it starts at size zero. 536 struct stat buf; 537 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 538 EXPECT_EQ(buf.st_size, 0); 539 540 // Ensure fallocate does not allow partial allocations. 541 ASSERT_THAT(fallocate(fd.get(), 0, 0, size + 1), 542 SyscallFailsWithErrno(ENOSPC)); 543 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 544 EXPECT_EQ(buf.st_size, 0); 545 546 // Grow to multiple of page size. 547 ASSERT_THAT(fallocate(fd.get(), 0, 0, size), SyscallSucceeds()); 548 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 549 EXPECT_EQ(buf.st_size, size); 550 551 // Grow to beyond tmpfs size bytes. 552 ASSERT_THAT(fallocate(fd.get(), 0, 0, size + 1), 553 SyscallFailsWithErrno(ENOSPC)); 554 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 555 EXPECT_EQ(buf.st_size, size); 556 } 557 558 TEST(MountTest, TmpfsSizeMoreThanSinglePgSZMultipleFiles) { 559 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 560 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 561 auto const page_multiple = 10; 562 auto const size = kPageSize * page_multiple; 563 auto tmpfs_size_opt = absl::StrCat("size=", size); 564 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 565 Mount("", dir.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 566 for (int i = 0; i < page_multiple; i++) { 567 auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open( 568 JoinPath(dir.path(), absl::StrCat("foo_", i)), O_CREAT | O_RDWR, 0777)); 569 // Create buffer & Grow to 100 bytes. 570 struct stat buf; 571 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 572 ASSERT_THAT(fallocate(fd.get(), 0, 0, 100), SyscallSucceeds()); 573 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 574 EXPECT_EQ(buf.st_size, 100); 575 } 576 auto fd = ASSERT_NO_ERRNO_AND_VALUE( 577 Open(JoinPath(dir.path(), absl::StrCat("foo_", page_multiple + 1)), 578 O_CREAT | O_RDWR, 0777)); 579 // Grow to beyond tmpfs size bytes after exhausting the size. 580 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize), 581 SyscallFailsWithErrno(ENOSPC)); 582 } 583 584 TEST(MountTest, TmpfsSizeFtruncate) { 585 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 586 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 587 auto tmpfs_size_opt = absl::StrCat("size=", kPageSize); 588 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 589 Mount("", dir.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 590 auto fd = ASSERT_NO_ERRNO_AND_VALUE( 591 Open(JoinPath(dir.path(), "foo"), O_CREAT | O_RDWR, 0777)); 592 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize), SyscallSucceeds()); 593 struct stat status; 594 ASSERT_THAT(fstat(fd.get(), &status), SyscallSucceeds()); 595 EXPECT_EQ(status.st_size, kPageSize); 596 597 ASSERT_THAT(ftruncate(fd.get(), kPageSize + 1), SyscallSucceeds()); 598 ASSERT_THAT(fstat(fd.get(), &status), SyscallSucceeds()); 599 EXPECT_EQ(status.st_size, kPageSize + 1); 600 601 ASSERT_THAT(ftruncate(fd.get(), 0), SyscallSucceeds()); 602 ASSERT_THAT(fstat(fd.get(), &status), SyscallSucceeds()); 603 EXPECT_EQ(status.st_size, 0); 604 605 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize), SyscallSucceeds()); 606 ASSERT_THAT(fstat(fd.get(), &status), SyscallSucceeds()); 607 EXPECT_EQ(status.st_size, kPageSize); 608 } 609 610 // Test shows directory does not take up any pages. 611 TEST(MountTest, TmpfsDirectoryAllocCheck) { 612 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 613 auto const dir_parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 614 615 auto tmpfs_size_opt = absl::StrCat("size=", kPageSize); 616 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 617 Mount("", dir_parent.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 618 619 auto const dir_tmp = 620 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir_parent.path())); 621 622 // Creating only 1 regular file allocates 1 page size. 623 auto fd = ASSERT_NO_ERRNO_AND_VALUE( 624 Open(JoinPath(dir_parent.path(), "foo"), O_CREAT | O_RDWR, 0777)); 625 626 // Check that it starts at size zero. 627 struct stat buf; 628 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 629 EXPECT_EQ(buf.st_size, 0); 630 631 // Grow to 1 Page Size. 632 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize), SyscallSucceeds()); 633 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 634 EXPECT_EQ(buf.st_size, kPageSize); 635 636 // Grow to beyond 1 Page Size. 637 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize + 1), 638 SyscallFailsWithErrno(ENOSPC)); 639 } 640 641 // Tests memory allocation for symlinks. 642 TEST(MountTest, TmpfsSymlinkAllocCheck) { 643 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 644 auto const dir_parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 645 646 auto tmpfs_size_opt = absl::StrCat("size=", kPageSize); 647 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 648 Mount("", dir_parent.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 649 650 const int target_size = 128; 651 auto target = std::string(target_size - 1, 'a'); 652 auto pathname = JoinPath(dir_parent.path(), "foo1"); 653 EXPECT_THAT(symlink(target.c_str(), pathname.c_str()), SyscallSucceeds()); 654 655 target = std::string(target_size, 'a'); 656 pathname = absl::StrCat(dir_parent.path(), "/foo2"); 657 EXPECT_THAT(symlink(target.c_str(), pathname.c_str()), SyscallSucceeds()); 658 659 target = std::string(target_size, 'a'); 660 pathname = absl::StrCat(dir_parent.path(), "/foo3"); 661 EXPECT_THAT(symlink(target.c_str(), pathname.c_str()), 662 SyscallFailsWithErrno(ENOSPC)); 663 664 target = std::string(target_size - 1, 'a'); 665 pathname = absl::StrCat(dir_parent.path(), "/foo4"); 666 EXPECT_THAT(symlink(target.c_str(), pathname.c_str()), SyscallSucceeds()); 667 EXPECT_THAT(unlink(pathname.c_str()), SyscallSucceeds()); 668 } 669 670 // Tests memory unallocation for symlinks. 671 TEST(MountTest, TmpfsSymlinkUnallocCheck) { 672 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 673 auto const dir_parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 674 675 auto tmpfs_size_opt = absl::StrCat("size=", kPageSize); 676 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 677 Mount("", dir_parent.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 678 679 const int target_size = 128; 680 auto pathname = JoinPath(dir_parent.path(), "foo1"); 681 auto target = std::string(target_size, 'a'); 682 EXPECT_THAT(symlink(target.c_str(), pathname.c_str()), SyscallSucceeds()); 683 auto const fd = 684 ASSERT_NO_ERRNO_AND_VALUE(Open(pathname, O_CREAT | O_RDWR, 0777)); 685 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize), 686 SyscallFailsWithErrno(ENOSPC)); 687 EXPECT_THAT(unlink(pathname.c_str()), SyscallSucceeds()); 688 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize), SyscallSucceeds()); 689 } 690 691 // Tests memory allocation for Hard Links is not double allocated. 692 TEST(MountTest, TmpfsHardLinkAllocCheck) { 693 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 694 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 695 auto tmpfs_size_opt = absl::StrCat("size=", kPageSize); 696 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 697 Mount("", dir.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 698 const std::string fileOne = JoinPath(dir.path(), "foo1"); 699 const std::string fileTwo = JoinPath(dir.path(), "foo2"); 700 auto const fd = 701 ASSERT_NO_ERRNO_AND_VALUE(Open(fileOne, O_CREAT | O_RDWR, 0777)); 702 EXPECT_THAT(link(fileOne.c_str(), fileTwo.c_str()), SyscallSucceeds()); 703 704 // Check that it starts at size zero. 705 struct stat buf; 706 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 707 EXPECT_EQ(buf.st_size, 0); 708 709 // Grow to 1 Page Size. 710 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize), SyscallSucceeds()); 711 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 712 EXPECT_EQ(buf.st_size, kPageSize); 713 714 // Grow to size beyond tmpfs allocated bytes. 715 ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize + 1), 716 SyscallFailsWithErrno(ENOSPC)); 717 ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); 718 EXPECT_EQ(buf.st_size, kPageSize); 719 EXPECT_THAT(unlink(fileTwo.c_str()), SyscallSucceeds()); 720 EXPECT_THAT(unlink(fileOne.c_str()), SyscallSucceeds()); 721 } 722 723 // Tests memory allocation for empty size. 724 TEST(MountTest, TmpfsEmptySizeAllocCheck) { 725 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 726 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 727 ASSERT_THAT(mount("", dir.path().c_str(), kTmpfs, 0, "size"), 728 SyscallFailsWithErrno(EINVAL)); 729 } 730 731 TEST(MountTest, TmpfsUnlinkRegularFileAllocCheck) { 732 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 733 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 734 auto tmpfs_size_opt = absl::StrCat("size=", kPageSize); 735 const int kTruncateSize = 2 * kPageSize; 736 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 737 Mount("", dir.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 738 const std::string fileOne = JoinPath(dir.path(), "foo1"); 739 auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(fileOne, O_CREAT | O_RDWR, 0777)); 740 EXPECT_THAT(unlink(fileOne.c_str()), SyscallSucceeds()); 741 EXPECT_THAT(ftruncate(fd.get(), kTruncateSize), SyscallSucceeds()); 742 } 743 744 TEST(MountTest, TmpfsSizePartialWriteSinglePage) { 745 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 746 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 747 auto tmpfs_size_opt = absl::StrCat("size=", kPageSize); 748 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 749 Mount("", dir.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 750 751 const std::string fileOne = JoinPath(dir.path(), "foo1"); 752 auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(fileOne, O_CREAT | O_RDWR, 0777)); 753 lseek(fd.get(), kPageSize - 2, SEEK_SET); 754 char buf[4]; 755 EXPECT_THAT(write(fd.get(), buf, 4), SyscallSucceedsWithValue(2)); 756 EXPECT_THAT(write(fd.get(), buf, 4), SyscallFailsWithErrno(ENOSPC)); 757 } 758 759 TEST(MountTest, TmpfsSizePartialWriteMultiplePages) { 760 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 761 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 762 auto tmpfs_size_opt = absl::StrCat("size=", 3 * kPageSize); 763 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 764 Mount("", dir.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 765 766 const std::string fileOne = JoinPath(dir.path(), "foo1"); 767 auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(fileOne, O_CREAT | O_RDWR, 0777)); 768 lseek(fd.get(), kPageSize, SEEK_SET); 769 std::vector<char> buf(kPageSize + 2); 770 EXPECT_THAT(write(fd.get(), buf.data(), 4), SyscallSucceedsWithValue(4)); 771 struct stat status; 772 ASSERT_THAT(fstat(fd.get(), &status), SyscallSucceeds()); 773 EXPECT_EQ(status.st_size, kPageSize + 4); 774 EXPECT_THAT(write(fd.get(), buf.data(), 1), SyscallSucceedsWithValue(1)); 775 776 // Writing with size exactly until the end of page boundary. 777 EXPECT_THAT(write(fd.get(), buf.data(), kPageSize - 5), 778 SyscallSucceedsWithValue(kPageSize - 5)); 779 780 EXPECT_THAT(write(fd.get(), buf.data(), 1), SyscallSucceedsWithValue(1)); 781 // Writing with size more than page end & having extra page available as well. 782 EXPECT_THAT(write(fd.get(), buf.data(), kPageSize + 1), 783 SyscallSucceedsWithValue(kPageSize + 1)); 784 785 // Writing with size more than page end & having no page available. 786 EXPECT_THAT(write(fd.get(), buf.data(), kPageSize + 1), 787 SyscallSucceedsWithValue(kPageSize - 2)); 788 EXPECT_THAT(write(fd.get(), buf.data(), 1), SyscallFailsWithErrno(ENOSPC)); 789 } 790 791 TEST(MountTest, TmpfsSizeMmap) { 792 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 793 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 794 auto tmpfs_size_opt = absl::StrCat("size=", kPageSize); 795 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 796 Mount("", dir.path(), kTmpfs, 0, tmpfs_size_opt, 0)); 797 const std::string fileOne = JoinPath(dir.path(), "foo"); 798 auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(fileOne, O_CREAT | O_RDWR, 0777)); 799 EXPECT_THAT(ftruncate(fd.get(), 2 * kPageSize), SyscallSucceeds()); 800 void* addr = mmap(NULL, 2 * kPageSize, PROT_READ, MAP_PRIVATE, fd.get(), 0); 801 EXPECT_NE(addr, MAP_FAILED); 802 // Access memory so that the first page to page fault occurs and is allocated. 803 char data = ((char*)addr)[kPageSize - 2]; 804 EXPECT_EQ(data, 0); 805 std::vector<char> in(kPageSize + 2); 806 // Access memory such that it causes the second page to page fault. The page 807 // fault should fail due to hitting tmpfs size limit which should cause 808 // SIGBUS signal. 809 EXPECT_EXIT(memcpy(in.data(), reinterpret_cast<char*>(addr), kPageSize + 2), 810 ::testing::KilledBySignal(SIGBUS), ""); 811 EXPECT_THAT(munmap(addr, 2 * kPageSize), SyscallSucceeds()); 812 } 813 814 TEST(MountTest, SimpleBind) { 815 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 816 817 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 818 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 819 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 820 Mount("", dir1.path(), kTmpfs, 0, "mode=0123", 0)); 821 auto const child1 = 822 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 823 auto const child2 = 824 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 825 auto const bind_mount = Mount(dir1.path(), dir2.path(), "", MS_BIND, "", 0); 826 827 // Write to child1 in dir1. 828 const std::string filename = "foo.txt"; 829 const std::string contents = "barbaz"; 830 ASSERT_NO_ERRNO( 831 CreateWithContents(JoinPath(child1.path(), filename), contents, 0666)); 832 // Verify both directories have the same nodes. 833 std::vector<std::string> child_names = {std::string(Basename(child1.path())), 834 std::string(Basename(child2.path()))}; 835 ASSERT_NO_ERRNO(DirContains(dir1.path(), child_names, {})); 836 ASSERT_NO_ERRNO(DirContains(dir2.path(), child_names, {})); 837 838 const std::string dir1_filepath = 839 JoinPath(dir1.path(), Basename(child1.path()), filename); 840 const std::string dir2_filepath = 841 JoinPath(dir2.path(), Basename(child1.path()), filename); 842 843 std::string output; 844 ASSERT_NO_ERRNO(GetContents(dir1_filepath, &output)); 845 EXPECT_EQ(output, contents); 846 ASSERT_NO_ERRNO(GetContents(dir2_filepath, &output)); 847 EXPECT_EQ(output, contents); 848 } 849 850 TEST(MountTest, BindToSelf) { 851 // Test that we can turn a normal directory into a mount with MS_BIND. 852 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 853 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 854 855 const std::vector<ProcMountsEntry> mounts_before = 856 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountsEntries()); 857 for (const auto& e : mounts_before) { 858 ASSERT_NE(e.mount_point, dir.path()); 859 } 860 861 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 862 Mount(dir.path(), dir.path(), "", MS_BIND, "", 0)); 863 864 const std::vector<ProcMountsEntry> mounts_after = 865 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountsEntries()); 866 bool found = false; 867 for (const auto& e : mounts_after) { 868 if (e.mount_point == dir.path()) { 869 found = true; 870 } 871 } 872 ASSERT_TRUE(found); 873 } 874 875 TEST(MountTest, MaxMounts) { 876 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 877 878 auto const parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 879 ASSERT_THAT(mount("", parent.path().c_str(), kTmpfs, 0, ""), 880 SyscallSucceeds()); 881 auto const dir = 882 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path())); 883 ASSERT_THAT( 884 mount(dir.path().c_str(), dir.path().c_str(), nullptr, MS_BIND, nullptr), 885 SyscallSucceeds()); 886 ASSERT_THAT(mount("", dir.path().c_str(), "", MS_SHARED, ""), 887 SyscallSucceeds()); 888 889 // Each bind mount doubles the number of mounts in the peer group. The number 890 // of binds we can do before failing is log2(max_mounts-num_current_mounts). 891 int mount_max = 10000; 892 bool mount_max_exists = 893 ASSERT_NO_ERRNO_AND_VALUE(Exists("/proc/sys/fs/mount-max")); 894 if (mount_max_exists) { 895 std::string mount_max_string; 896 ASSERT_NO_ERRNO(GetContents("/proc/sys/fs/mount-max", &mount_max_string)); 897 ASSERT_TRUE(absl::SimpleAtoi(mount_max_string, &mount_max)); 898 } 899 900 const std::vector<ProcMountInfoEntry> mounts = 901 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); 902 int num_binds = static_cast<int>(std::log2(mount_max - mounts.size())); 903 904 for (int i = 0; i < num_binds; i++) { 905 ASSERT_THAT(mount(dir.path().c_str(), dir.path().c_str(), nullptr, MS_BIND, 906 nullptr), 907 SyscallSucceeds()); 908 } 909 ASSERT_THAT( 910 mount(dir.path().c_str(), dir.path().c_str(), nullptr, MS_BIND, nullptr), 911 SyscallFailsWithErrno(ENOSPC)); 912 umount2(parent.path().c_str(), MNT_DETACH); 913 } 914 915 TEST(MountTest, PropagateToSameMountpointStacksMounts) { 916 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 917 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 918 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 919 auto const mnt = ASSERT_NO_ERRNO_AND_VALUE(Mount( 920 dir.path().c_str(), dir.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 921 auto const child = 922 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path())); 923 ASSERT_THAT(mount(child.path().c_str(), child.path().c_str(), "", MS_BIND, 0), 924 SyscallSucceeds()); 925 ASSERT_THAT(mount("", dir.path().c_str(), "", MS_SHARED, 0), 926 SyscallSucceeds()); 927 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 928 dir.path().c_str(), dir2.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 929 930 std::string dir2_child_path = JoinPath(dir2.path(), Basename(child.path())); 931 ASSERT_THAT( 932 mount(dir2_child_path.c_str(), dir2_child_path.c_str(), "", MS_BIND, 0), 933 SyscallSucceeds()); 934 935 // Check that mounts at the child mount point have distinct parents. 936 std::vector<ProcMountInfoEntry> mounts = 937 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); 938 uint64_t parent_id = 0; 939 for (auto& minfo : mounts) { 940 if (minfo.mount_point == child.path()) { 941 if (parent_id == 0) { 942 parent_id = minfo.parent_id; 943 } else { 944 EXPECT_NE(parent_id, minfo.parent_id); 945 } 946 } 947 } 948 } 949 950 TEST(MountTest, UmountReparentsCoveredMounts) { 951 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 952 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 953 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 954 auto const mnt = ASSERT_NO_ERRNO_AND_VALUE( 955 Mount("", dir.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 956 ASSERT_THAT(mount("", dir.path().c_str(), "", MS_SHARED, 0), 957 SyscallSucceeds()); 958 auto const child = 959 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path())); 960 ASSERT_THAT(mount("", child.path().c_str(), kTmpfs, 0, 0), SyscallSucceeds()); 961 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 962 dir.path().c_str(), dir2.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 963 964 std::string dir2_child_path = JoinPath(dir2.path(), Basename(child.path())); 965 ASSERT_THAT(mount("", dir2_child_path.c_str(), kTmpfs, 0, 0), 966 SyscallSucceeds()); 967 968 umount2(dir2_child_path.c_str(), MNT_DETACH); 969 970 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 971 ASSERT_FALSE(optionals[child.path()].empty()); 972 EXPECT_NE(optionals[child.path()][0].shared, 0); 973 EXPECT_TRUE(optionals[dir2_child_path].empty()); 974 } 975 976 // Tests that it is possible to make a shared mount. 977 TEST(MountTest, MakeShared) { 978 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 979 980 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 981 auto const mnt = ASSERT_NO_ERRNO_AND_VALUE( 982 Mount("", dir.path().c_str(), kTmpfs, 0, "", 0)); 983 ASSERT_THAT(mount("", dir.path().c_str(), "", MS_SHARED, 0), 984 SyscallSucceeds()); 985 986 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 987 ASSERT_FALSE(optionals[dir.path()].empty()); 988 EXPECT_NE(optionals[dir.path()][0].shared, 0); 989 } 990 991 // Tests that shared mounts have different group IDs. 992 TEST(MountTest, MakeMultipleShared) { 993 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 994 995 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 996 auto const mount1 = 997 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir1.path(), kTmpfs, 0, "", 0)); 998 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 999 SyscallSucceeds()); 1000 1001 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1002 auto const mount2 = 1003 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir2.path(), kTmpfs, 0, "", 0)); 1004 ASSERT_THAT(mount("", dir2.path().c_str(), "", MS_SHARED, 0), 1005 SyscallSucceeds()); 1006 1007 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1008 ASSERT_FALSE(optionals[dir1.path()].empty()); 1009 ASSERT_FALSE(optionals[dir2.path()].empty()); 1010 EXPECT_NE(optionals[dir1.path()][0].shared, optionals[dir2.path()][0].shared); 1011 } 1012 1013 // Tests that shared mounts reused group IDs from deleted groups. 1014 TEST(MountTest, ReuseGroupIDs) { 1015 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1016 1017 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1018 auto const mount1 = 1019 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir1.path(), kTmpfs, 0, "", 0)); 1020 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1021 SyscallSucceeds()); 1022 1023 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1024 int reused_group_id; 1025 { 1026 auto const mount2 = 1027 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir2.path(), kTmpfs, 0, "", 0)); 1028 ASSERT_THAT(mount("", dir2.path().c_str(), "", MS_SHARED, 0), 1029 SyscallSucceeds()); 1030 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1031 ASSERT_FALSE(optionals[dir2.path()].empty()); 1032 reused_group_id = optionals[dir2.path()][0].shared; 1033 } 1034 1035 // Check that created a new shared mount reuses the ID 2. 1036 auto const mount2 = 1037 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir2.path(), kTmpfs, 0, "", 0)); 1038 ASSERT_THAT(mount("", dir2.path().c_str(), "", MS_SHARED, 0), 1039 SyscallSucceeds()); 1040 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1041 ASSERT_FALSE(optionals[dir2.path()].empty()); 1042 EXPECT_EQ(reused_group_id, optionals[dir2.path()][0].shared); 1043 } 1044 1045 // Tests that a child mount inherits the propagation type of its parent. 1046 TEST(MountTest, InerheritPropagation) { 1047 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1048 1049 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1050 auto const mount1 = 1051 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir1.path(), kTmpfs, 0, "", 0)); 1052 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1053 SyscallSucceeds()); 1054 1055 auto const dir2 = 1056 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 1057 auto const mount2 = 1058 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir2.path(), kTmpfs, 0, "", 0)); 1059 1060 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1061 ASSERT_FALSE(optionals[dir2.path()].empty()); 1062 EXPECT_NE(optionals[dir2.path()][0].shared, 0); 1063 } 1064 1065 // Tests that it is possible to make a mount private again after it is shared. 1066 TEST(MountTest, MakePrivate) { 1067 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1068 1069 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1070 auto const mnt = 1071 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir.path(), kTmpfs, 0, "", 0)); 1072 ASSERT_THAT(mount("", dir.path().c_str(), "", MS_SHARED, 0), 1073 SyscallSucceeds()); 1074 ASSERT_THAT(mount("", dir.path().c_str(), "", MS_PRIVATE, 0), 1075 SyscallSucceeds()); 1076 1077 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1078 ASSERT_FALSE(optionals[dir.path()].empty()); 1079 EXPECT_EQ(optionals[dir.path()][0].shared, 0); 1080 } 1081 1082 TEST(MountTest, ArgumentsAreIgnored) { 1083 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1084 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1085 // These mounts should not fail even though string arguments are passed as 1086 // NULL. 1087 auto const mnt = ASSERT_NO_ERRNO_AND_VALUE( 1088 Mount(dir.path(), dir.path(), "", MS_BIND, "", MNT_DETACH)); 1089 ASSERT_THAT(mount(NULL, dir.path().c_str(), NULL, MS_SHARED, NULL), 1090 SyscallSucceeds()); 1091 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1092 ASSERT_FALSE(optionals[dir.path()].empty()); 1093 EXPECT_NE(optionals[dir.path()][0].shared, 0); 1094 } 1095 1096 TEST(MountTest, MultiplePropagationFlagsFails) { 1097 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1098 1099 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1100 auto const mnt = 1101 ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir.path(), kTmpfs, 0, "", 0)); 1102 EXPECT_THAT(mount("", dir.path().c_str(), "", MS_SHARED | MS_PRIVATE, 0), 1103 SyscallFailsWithErrno(EINVAL)); 1104 } 1105 1106 TEST(MountTest, SetMountPropagationOfStackedMounts) { 1107 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1108 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1109 auto const mnt1 = ASSERT_NO_ERRNO_AND_VALUE( 1110 Mount("", dir.path().c_str(), kTmpfs, 0, "", 0)); 1111 // Only the topmost mount on the stack should be shared. 1112 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE( 1113 Mount("", dir.path().c_str(), kTmpfs, 0, "", 0)); 1114 ASSERT_THAT(mount("", dir.path().c_str(), "", MS_SHARED, 0), 1115 SyscallSucceeds()); 1116 1117 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1118 ASSERT_FALSE(optionals[dir.path()].empty()); 1119 EXPECT_EQ(optionals[dir.path()][0].shared, 0); 1120 EXPECT_NE(optionals[dir.path()][1].shared, 0); 1121 } 1122 1123 TEST(MountTest, MakePeer) { 1124 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1125 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1126 auto const mnt = ASSERT_NO_ERRNO_AND_VALUE( 1127 Mount("", dir1.path().c_str(), kTmpfs, 0, "", 0)); 1128 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1129 SyscallSucceeds()); 1130 1131 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1132 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE( 1133 Mount(dir1.path(), dir2.path(), "", MS_BIND, "", MNT_DETACH)); 1134 1135 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1136 ASSERT_FALSE(optionals[dir1.path()].empty()); 1137 ASSERT_FALSE(optionals[dir2.path()].empty()); 1138 EXPECT_EQ(optionals[dir1.path()][0].shared, optionals[dir2.path()][0].shared); 1139 EXPECT_NE(optionals[dir1.path()][0].shared, 0); 1140 } 1141 1142 TEST(MountTest, PropagateMountEvent) { 1143 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1144 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1145 auto const mnt = ASSERT_NO_ERRNO_AND_VALUE( 1146 Mount("", dir1.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1147 auto const child_dir = 1148 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 1149 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1150 SyscallSucceeds()); 1151 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1152 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE( 1153 Mount(dir1.path(), dir2.path(), "", MS_BIND, "", MNT_DETACH)); 1154 // This mount should propagate to dir2. 1155 auto const child_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1156 Mount("", child_dir.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1157 1158 const std::string child_path1 = 1159 JoinPath(dir1.path(), Basename(child_dir.path())); 1160 const std::string child_path2 = 1161 JoinPath(dir2.path(), Basename(child_dir.path())); 1162 1163 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1164 ASSERT_FALSE(optionals[dir1.path()].empty()); 1165 ASSERT_FALSE(optionals[dir2.path()].empty()); 1166 ASSERT_FALSE(optionals[child_path1].empty()); 1167 ASSERT_FALSE(optionals[child_path2].empty()); 1168 EXPECT_EQ(optionals[dir1.path()][0].shared, optionals[dir2.path()][0].shared); 1169 EXPECT_NE(optionals[dir1.path()][0].shared, 0); 1170 EXPECT_EQ(optionals[child_path1][0].shared, optionals[child_path2][0].shared); 1171 EXPECT_NE(optionals[child_path1][0].shared, 0); 1172 } 1173 1174 TEST(MountTest, PropagateUmountEvent) { 1175 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1176 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1177 auto const mnt = ASSERT_NO_ERRNO_AND_VALUE( 1178 Mount("", dir1.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1179 auto const child_dir = 1180 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 1181 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1182 SyscallSucceeds()); 1183 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1184 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE( 1185 Mount(dir1.path(), dir2.path(), "", MS_BIND, "", MNT_DETACH)); 1186 // This mount will propagate to dir2. Once the block ends it will be 1187 // unmounted, which should also propagate to dir2. 1188 { 1189 auto const child_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1190 Mount("", child_dir.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1191 } 1192 1193 const std::string child_path1 = 1194 JoinPath(dir1.path(), Basename(child_dir.path())); 1195 const std::string child_path2 = 1196 JoinPath(dir2.path(), Basename(child_dir.path())); 1197 1198 std::vector<ProcMountInfoEntry> mounts = 1199 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); 1200 for (const auto& e : mounts) { 1201 EXPECT_NE(e.mount_point, child_path1); 1202 EXPECT_NE(e.mount_point, child_path2); 1203 } 1204 } 1205 1206 TEST(MountTest, PropagateChildUmountEvent) { 1207 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1208 1209 TempPath const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1210 ASSERT_THAT(mount("", dir1.path().c_str(), kTmpfs, 0, ""), SyscallSucceeds()); 1211 1212 TempPath const child = 1213 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 1214 ASSERT_THAT(mount("", child.path().c_str(), kTmpfs, 0, ""), 1215 SyscallSucceeds()); 1216 ASSERT_THAT(mount("", child.path().c_str(), "", MS_SHARED, 0), 1217 SyscallSucceeds()); 1218 1219 TempPath const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1220 ASSERT_THAT(mount(child.path().c_str(), dir2.path().c_str(), "", MS_BIND, 0), 1221 SyscallSucceeds()); 1222 ASSERT_THAT(mount("", child.path().c_str(), kTmpfs, 0, ""), 1223 SyscallSucceeds()); 1224 ASSERT_THAT(umount2(dir1.path().c_str(), MNT_DETACH), SyscallSucceeds()); 1225 1226 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1227 EXPECT_EQ(optionals[dir2.path()].size(), 1); 1228 1229 ASSERT_EQ(umount2(dir2.path().c_str(), MNT_DETACH), 0); 1230 } 1231 1232 TEST(MountTest, UmountIgnoresPeersWithChildren) { 1233 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1234 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1235 ASSERT_THAT(mount("", dir1.path().c_str(), kTmpfs, 0, ""), SyscallSucceeds()); 1236 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1237 SyscallSucceeds()); 1238 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1239 ASSERT_THAT(mount(dir1.path().c_str(), dir2.path().c_str(), "", MS_BIND, 0), 1240 SyscallSucceeds()); 1241 1242 auto const child_dir = 1243 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 1244 ASSERT_THAT(mount("", child_dir.path().c_str(), kTmpfs, 0, ""), 1245 SyscallSucceeds()); 1246 auto const grandchild_dir = 1247 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(child_dir.path())); 1248 ASSERT_THAT(mount("", grandchild_dir.path().c_str(), kTmpfs, 0, ""), 1249 SyscallSucceeds()); 1250 1251 const std::string child_path1 = 1252 JoinPath(dir1.path(), Basename(child_dir.path())); 1253 const std::string child_path2 = 1254 JoinPath(dir2.path(), Basename(child_dir.path())); 1255 ASSERT_THAT(mount("", child_path2.c_str(), "", MS_PRIVATE, 0), 1256 SyscallSucceeds()); 1257 const std::string grandchild_path2 = 1258 JoinPath(child_path2, Basename(grandchild_dir.path())); 1259 ASSERT_THAT(umount2(grandchild_path2.c_str(), MNT_DETACH), SyscallSucceeds()); 1260 1261 // This umount event should not propagate to the peer at dir1 because its 1262 // child mount still has its own child mount. 1263 ASSERT_THAT(umount2(child_path2.c_str(), MNT_DETACH), SyscallSucceeds()); 1264 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1265 EXPECT_EQ(optionals[child_path2].size(), 0); 1266 EXPECT_EQ(optionals[child_path1].size(), 1); 1267 1268 ASSERT_THAT(umount2(dir1.path().c_str(), MNT_DETACH), SyscallSucceeds()); 1269 ASSERT_THAT(umount2(dir2.path().c_str(), MNT_DETACH), SyscallSucceeds()); 1270 } 1271 1272 TEST(MountTest, BindSharedOnShared) { 1273 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1274 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1275 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1276 auto const dir3 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1277 auto const dir4 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1278 // Dir 1 and 2 are part of peer group 'A', dir 3 and 4 are part of peer group 1279 // 'B'. 1280 auto const mnt1 = ASSERT_NO_ERRNO_AND_VALUE( 1281 Mount("", dir1.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1282 auto const dir5 = 1283 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 1284 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1285 SyscallSucceeds()); 1286 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1287 dir1.path().c_str(), dir2.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1288 auto const mnt3 = ASSERT_NO_ERRNO_AND_VALUE( 1289 Mount("", dir3.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1290 ASSERT_THAT(mount("", dir3.path().c_str(), "", MS_SHARED, 0), 1291 SyscallSucceeds()); 1292 auto const mnt4 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1293 dir3.path().c_str(), dir4.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1294 1295 const std::string dir5_path2 = JoinPath(dir2.path(), Basename(dir5.path())); 1296 1297 // Bind peer group 'A' to peer group 'B'. 1298 auto const mnt5 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1299 dir4.path().c_str(), dir5.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1300 1301 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1302 ASSERT_FALSE(optionals[dir1.path()].empty()); 1303 ASSERT_FALSE(optionals[dir2.path()].empty()); 1304 ASSERT_FALSE(optionals[dir3.path()].empty()); 1305 ASSERT_FALSE(optionals[dir4.path()].empty()); 1306 ASSERT_FALSE(optionals[dir5.path()].empty()); 1307 ASSERT_FALSE(optionals[dir5_path2].empty()); 1308 EXPECT_EQ(optionals[dir3.path()][0].shared, optionals[dir4.path()][0].shared); 1309 EXPECT_EQ(optionals[dir4.path()][0].shared, optionals[dir5.path()][0].shared); 1310 EXPECT_EQ(optionals[dir5.path()][0].shared, optionals[dir5_path2][0].shared); 1311 EXPECT_NE(optionals[dir3.path()][0].shared, 0); 1312 } 1313 1314 TEST(MountTest, BindSharedOnPrivate) { 1315 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1316 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1317 auto const mnt1 = ASSERT_NO_ERRNO_AND_VALUE( 1318 Mount("", dir1.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1319 auto const dir2 = 1320 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 1321 auto const dir3 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1322 auto const dir4 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1323 auto const mnt3 = ASSERT_NO_ERRNO_AND_VALUE( 1324 Mount("", dir3.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1325 ASSERT_THAT(mount("", dir3.path().c_str(), "", MS_SHARED, 0), 1326 SyscallSucceeds()); 1327 auto const mnt4 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1328 dir3.path().c_str(), dir4.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1329 1330 // bind to private mount. 1331 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1332 dir3.path().c_str(), dir2.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1333 1334 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1335 ASSERT_FALSE(optionals[dir1.path()].empty()); 1336 ASSERT_FALSE(optionals[dir2.path()].empty()); 1337 ASSERT_FALSE(optionals[dir3.path()].empty()); 1338 ASSERT_FALSE(optionals[dir4.path()].empty()); 1339 EXPECT_EQ(optionals[dir1.path()][0].shared, 0); 1340 EXPECT_EQ(optionals[dir2.path()][0].shared, optionals[dir3.path()][0].shared); 1341 EXPECT_EQ(optionals[dir3.path()][0].shared, optionals[dir4.path()][0].shared); 1342 } 1343 1344 TEST(MountTest, BindPeerGroupsWithChildren) { 1345 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1346 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1347 auto const mnt1 = ASSERT_NO_ERRNO_AND_VALUE( 1348 Mount("", dir1.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1349 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1350 SyscallSucceeds()); 1351 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1352 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE( 1353 Mount("", dir2.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1354 ASSERT_THAT(mount("", dir2.path().c_str(), "", MS_SHARED, 0), 1355 SyscallSucceeds()); 1356 // dir3 and dir4 are child mounts of dir1. 1357 auto const dir3 = 1358 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 1359 auto const mnt3 = ASSERT_NO_ERRNO_AND_VALUE( 1360 Mount("", dir3.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1361 auto const dir4 = 1362 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 1363 auto const mnt4 = ASSERT_NO_ERRNO_AND_VALUE( 1364 Mount("", dir4.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1365 auto const mnt5 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1366 dir1.path().c_str(), dir2.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1367 1368 const std::string dir3_path2 = JoinPath(dir2.path(), Basename(dir3.path())); 1369 const std::string dir4_path2 = JoinPath(dir2.path(), Basename(dir4.path())); 1370 1371 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1372 ASSERT_FALSE(optionals[dir1.path()].empty()); 1373 ASSERT_FALSE(optionals[dir2.path()].empty()); 1374 ASSERT_FALSE(optionals[dir3.path()].empty()); 1375 1376 EXPECT_NE(optionals[dir1.path()][0].shared, optionals[dir3.path()][0].shared); 1377 EXPECT_NE(optionals[dir3.path()][0].shared, optionals[dir4.path()][0].shared); 1378 EXPECT_NE(optionals[dir4.path()][0].shared, optionals[dir1.path()][0].shared); 1379 EXPECT_EQ(optionals[dir3_path2].size(), 0); 1380 EXPECT_EQ(optionals[dir4_path2].size(), 0); 1381 } 1382 1383 TEST(MountTest, BindParentToChild) { 1384 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1385 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1386 auto const mnt1 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1387 dir1.path().c_str(), dir1.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1388 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1389 SyscallSucceeds()); 1390 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1391 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1392 dir1.path().c_str(), dir2.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1393 auto const child_dir = 1394 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 1395 auto const mnt3 = ASSERT_NO_ERRNO_AND_VALUE( 1396 Mount(dir1.path().c_str(), child_dir.path().c_str(), "", MS_BIND, "", 1397 MNT_DETACH)); 1398 1399 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1400 ASSERT_FALSE(optionals[dir1.path()].empty()); 1401 ASSERT_FALSE(optionals[dir2.path()].empty()); 1402 ASSERT_FALSE(optionals[child_dir.path()].empty()); 1403 1404 EXPECT_EQ(optionals[dir1.path()][0].shared, optionals[dir2.path()][0].shared); 1405 EXPECT_EQ(optionals[dir2.path()][0].shared, 1406 optionals[child_dir.path()][0].shared); 1407 EXPECT_NE(optionals[dir1.path()][0].shared, 0); 1408 } 1409 1410 TEST(MountTest, MountInfoHasRoot) { 1411 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1412 auto const parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1413 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 1414 Mount("", parent.path(), kTmpfs, 0, "mode=0123", 0)); 1415 auto const child = 1416 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path())); 1417 auto const bind_mount = Mount(child.path(), child.path(), "", MS_BIND, "", 0); 1418 std::vector<ProcMountInfoEntry> mounts = 1419 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); 1420 for (const auto& e : mounts) { 1421 if (e.mount_point == child.path()) { 1422 EXPECT_EQ(e.root, JoinPath("/", Basename(child.path()))) 1423 << "Offending mount ID is: " << e.id; 1424 } 1425 if (e.mount_point == parent.path()) { 1426 EXPECT_EQ(e.root, "/") << "Offending mount ID is: " << e.id; 1427 } 1428 } 1429 } 1430 1431 TEST(MountTest, DeadMountsAreDecRefd) { 1432 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1433 DisableSave ds; 1434 std::string home = NewTempAbsPath(); 1435 ASSERT_NO_ERRNO(Mkdir(home)); 1436 ASSERT_THAT(chdir(home.c_str()), SyscallSucceeds()); 1437 constexpr char dirpath[] = "./file"; 1438 1439 for (int i = 0; i < 10; ++i) { 1440 const auto rest = [&] { 1441 mkdir(dirpath, 0); 1442 mount(dirpath, ".", 0, MS_BIND, 0); 1443 rmdir(dirpath); 1444 mkdir(dirpath, 0); 1445 mount(dirpath, ".", 0, MS_BIND, 0); 1446 }; 1447 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 1448 } 1449 } 1450 1451 TEST(MountTest, UmountSharedBind) { 1452 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1453 std::string home = NewTempAbsPath(); 1454 ASSERT_NO_ERRNO(Mkdir(home)); 1455 ASSERT_THAT(chdir(home.c_str()), SyscallSucceeds()); 1456 constexpr char dirpath[] = "./file"; 1457 1458 ASSERT_THAT(mkdir(dirpath, 0), SyscallSucceeds()); 1459 ASSERT_THAT(mount(dirpath, dirpath, 0, MS_BIND, 0), SyscallSucceeds()); 1460 ASSERT_THAT(mount(0, dirpath, 0, MS_SHARED, 0), SyscallSucceeds()); 1461 ASSERT_THAT(mount(dirpath, dirpath, 0, MS_BIND, 0), SyscallSucceeds()); 1462 ASSERT_THAT(mount(0, dirpath, 0, MS_SHARED, 0), SyscallSucceeds()); 1463 ASSERT_THAT(umount2(dirpath, MNT_DETACH), SyscallSucceeds()); 1464 ASSERT_THAT(umount2(dirpath, MNT_DETACH), SyscallSucceeds()); 1465 } 1466 1467 TEST(MountTest, MakeSlave) { 1468 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1469 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1470 auto const mnt1 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1471 dir1.path().c_str(), dir1.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1472 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1473 SyscallSucceeds()); 1474 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1475 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1476 dir1.path().c_str(), dir2.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1477 1478 ASSERT_THAT(mount(0, dir2.path().c_str(), 0, MS_SLAVE, 0), SyscallSucceeds()); 1479 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1480 ASSERT_NE(optionals[dir1.path()][0].shared, 0); 1481 ASSERT_NE(optionals[dir2.path()][0].master, 0); 1482 } 1483 1484 TEST(MountTest, MakeSharedSlave) { 1485 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1486 1487 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1488 auto const mnt1 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1489 dir1.path().c_str(), dir1.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1490 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1491 SyscallSucceeds()); 1492 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1493 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1494 dir1.path().c_str(), dir2.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1495 1496 ASSERT_THAT(mount(0, dir2.path().c_str(), 0, MS_SLAVE, 0), SyscallSucceeds()); 1497 ASSERT_THAT(mount(0, dir2.path().c_str(), 0, MS_SHARED, 0), 1498 SyscallSucceeds()); 1499 1500 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1501 ASSERT_NE(optionals[dir1.path()][0].shared, 0); 1502 ASSERT_NE(optionals[dir2.path()][0].shared, 0); 1503 ASSERT_NE(optionals[dir2.path()][0].master, 0); 1504 } 1505 1506 TEST(MountTest, PrivateMasterUnslaves) { 1507 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1508 auto const base = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1509 auto const base_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1510 Mount("", base.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 1511 ASSERT_THAT(mount("", base.path().c_str(), "", MS_PRIVATE, 0), 1512 SyscallSucceeds()); 1513 1514 auto const dir1 = 1515 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(base.path())); 1516 auto const mnt1 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1517 dir1.path().c_str(), dir1.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1518 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1519 SyscallSucceeds()); 1520 auto const dir2 = 1521 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(base.path())); 1522 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1523 dir1.path().c_str(), dir2.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1524 ASSERT_THAT(mount(0, dir2.path().c_str(), 0, MS_SLAVE, 0), SyscallSucceeds()); 1525 ASSERT_THAT(mount(0, dir2.path().c_str(), 0, MS_SHARED, 0), 1526 SyscallSucceeds()); 1527 1528 ASSERT_THAT(mount(0, dir1.path().c_str(), 0, MS_PRIVATE, 0), 1529 SyscallSucceeds()); 1530 1531 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1532 ASSERT_EQ(optionals[dir1.path()][0].shared, 0); 1533 ASSERT_EQ(optionals[dir2.path()][0].master, 0); 1534 ASSERT_NE(optionals[dir2.path()][0].shared, 0); 1535 } 1536 1537 TEST(MountTest, SlaveMaster) { 1538 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1539 1540 auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1541 auto const mnt1 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1542 dir1.path().c_str(), dir1.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1543 ASSERT_THAT(mount("", dir1.path().c_str(), "", MS_SHARED, 0), 1544 SyscallSucceeds()); 1545 auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1546 auto const mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1547 dir1.path().c_str(), dir2.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1548 ASSERT_THAT(mount(0, dir2.path().c_str(), 0, MS_SLAVE, 0), SyscallSucceeds()); 1549 ASSERT_THAT(mount(0, dir2.path().c_str(), 0, MS_SHARED, 0), 1550 SyscallSucceeds()); 1551 auto const dir3 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1552 auto const mnt3 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1553 dir2.path().c_str(), dir3.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1554 ASSERT_THAT(mount(0, dir3.path().c_str(), 0, MS_SLAVE, 0), SyscallSucceeds()); 1555 1556 ASSERT_THAT(mount(0, dir2.path().c_str(), 0, MS_PRIVATE, 0), 1557 SyscallSucceeds()); 1558 1559 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1560 ASSERT_NE(optionals[dir1.path()][0].shared, 0); 1561 ASSERT_EQ(optionals[dir2.path()][0].shared, 0); 1562 ASSERT_EQ(optionals[dir2.path()][0].master, 0); 1563 ASSERT_EQ(optionals[dir3.path()][0].master, optionals[dir1.path()][0].shared); 1564 } 1565 1566 TEST(MountTest, BindSharedToSlave) { 1567 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1568 1569 auto const src = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1570 auto const src_mnt = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1571 src.path().c_str(), src.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1572 ASSERT_THAT(mount("", src.path().c_str(), "", MS_SHARED, 0), 1573 SyscallSucceeds()); 1574 auto const dst_master = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1575 auto const dst_master_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1576 Mount(dst_master.path().c_str(), dst_master.path().c_str(), "", MS_BIND, 1577 "", MNT_DETACH)); 1578 ASSERT_THAT(mount("", dst_master.path().c_str(), "", MS_SHARED, 0), 1579 SyscallSucceeds()); 1580 auto const dst = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1581 auto const dst_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1582 Mount(dst_master.path().c_str(), dst.path().c_str(), "", MS_BIND, "", 1583 MNT_DETACH)); 1584 ASSERT_THAT(mount("", dst.path().c_str(), "", MS_SLAVE, 0), 1585 SyscallSucceeds()); 1586 1587 auto const dst_mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1588 src.path().c_str(), dst.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1589 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1590 1591 ASSERT_EQ(optionals[src.path()][0].shared, optionals[dst.path()][1].shared); 1592 ASSERT_EQ(optionals[dst.path()][0].master, 1593 optionals[dst_master.path()][0].shared); 1594 } 1595 1596 TEST(MountTest, BindSlaveToShared) { 1597 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1598 1599 auto const src = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1600 auto const src_mnt = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1601 src.path().c_str(), src.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1602 ASSERT_THAT(mount("", src.path().c_str(), "", MS_SHARED, 0), 1603 SyscallSucceeds()); 1604 auto const src_master = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1605 auto const src_master_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1606 Mount(src.path().c_str(), src_master.path().c_str(), "", MS_BIND, "", 1607 MNT_DETACH)); 1608 ASSERT_THAT(mount("", src.path().c_str(), "", MS_SLAVE, 0), 1609 SyscallSucceeds()); 1610 1611 auto const dst = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1612 auto const dst_mnt = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1613 dst.path().c_str(), dst.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1614 ASSERT_THAT(mount("", dst.path().c_str(), "", MS_SHARED, 0), 1615 SyscallSucceeds()); 1616 auto const dst_peer = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1617 auto const dst_peer_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1618 Mount(dst.path().c_str(), dst_peer.path().c_str(), "", MS_BIND, "", 1619 MNT_DETACH)); 1620 1621 auto const dst_mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1622 src.path().c_str(), dst.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1623 1624 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1625 ASSERT_EQ(optionals[dst.path()][1].shared, 1626 optionals[dst_peer.path()][1].shared); 1627 ASSERT_EQ(optionals[dst.path()][1].master, 1628 optionals[dst_peer.path()][1].master); 1629 ASSERT_EQ(optionals[dst.path()][1].master, 1630 optionals[src_master.path()][0].shared); 1631 } 1632 1633 TEST(MountTest, BindSlaveToSlave) { 1634 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1635 1636 auto const src = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1637 auto const src_mnt = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1638 src.path().c_str(), src.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1639 ASSERT_THAT(mount("", src.path().c_str(), "", MS_SHARED, 0), 1640 SyscallSucceeds()); 1641 auto const src_master = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1642 auto const src_master_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1643 Mount(src.path().c_str(), src_master.path().c_str(), "", MS_BIND, "", 1644 MNT_DETACH)); 1645 ASSERT_THAT(mount("", src.path().c_str(), "", MS_SLAVE, 0), 1646 SyscallSucceeds()); 1647 1648 auto const dst = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1649 auto const dst_mnt = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1650 dst.path().c_str(), dst.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1651 ASSERT_THAT(mount("", dst.path().c_str(), "", MS_SHARED, 0), 1652 SyscallSucceeds()); 1653 auto const dst_master = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1654 auto const dst_master_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1655 Mount(dst.path().c_str(), dst_master.path().c_str(), "", MS_BIND, "", 1656 MNT_DETACH)); 1657 ASSERT_THAT(mount("", dst.path().c_str(), "", MS_SLAVE, 0), 1658 SyscallSucceeds()); 1659 1660 auto const dst_mnt2 = ASSERT_NO_ERRNO_AND_VALUE(Mount( 1661 src.path().c_str(), dst.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1662 1663 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1664 ASSERT_EQ(optionals[dst.path()][1].master, optionals[src.path()][0].master); 1665 } 1666 1667 // Test that mounting on a slave mount does not propagate to the master. 1668 TEST(MountTest, SlavePropagationEvent) { 1669 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1670 1671 auto const dst_master = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1672 auto const dst_master_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1673 Mount(dst_master.path().c_str(), dst_master.path().c_str(), "", MS_BIND, 1674 "", MNT_DETACH)); 1675 ASSERT_THAT(mount("", dst_master.path().c_str(), "", MS_SHARED, 0), 1676 SyscallSucceeds()); 1677 auto const dst = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1678 auto const dst_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1679 Mount(dst_master.path().c_str(), dst.path().c_str(), "", MS_BIND, "", 1680 MNT_DETACH)); 1681 ASSERT_THAT(mount("", dst.path().c_str(), "", MS_SLAVE, 0), 1682 SyscallSucceeds()); 1683 auto const child = 1684 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dst_master.path())); 1685 1686 const std::string master_child_path = 1687 JoinPath(dst_master.path(), Basename(child.path())); 1688 const std::string slave_child_path = 1689 JoinPath(dst.path(), Basename(child.path())); 1690 auto const slave_child_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1691 Mount("", slave_child_path.c_str(), kTmpfs, 0, "", MNT_DETACH)); 1692 1693 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1694 ASSERT_EQ(optionals[child.path()].size(), 0); 1695 } 1696 1697 // We are building a propagation tree that looks like this: 1698 /* 1699 A <--> B <--> C <---> D 1700 /|\ /| |\ 1701 / F G J K H I 1702 / 1703 E<-->O 1704 /|\ 1705 M L N 1706 */ 1707 // Propagating mount events across this tree should cover most propagation 1708 // cases. 1709 TEST(MountTest, LargeTreePropagationEvent) { 1710 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1711 1712 // 15 total mounts that should all get propagated to if we mount on A. 1713 auto const a = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1714 auto const b = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1715 auto const c = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1716 auto const d = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1717 auto const e = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1718 auto const f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1719 auto const g = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1720 auto const h = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1721 auto const i = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1722 auto const j = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1723 auto const k = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1724 auto const l = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1725 auto const m = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1726 auto const n = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1727 auto const o = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1728 1729 auto const a_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1730 Mount(a.path().c_str(), a.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1731 ASSERT_THAT(mount("", a.path().c_str(), "", MS_SHARED, 0), SyscallSucceeds()); 1732 1733 // Place E, F, and G in A's peer group, then make them slaves. 1734 auto const e_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1735 Mount(a.path().c_str(), e.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1736 auto const f_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1737 Mount(a.path().c_str(), f.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1738 auto const g_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1739 Mount(a.path().c_str(), g.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1740 ASSERT_THAT(mount("", e.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1741 ASSERT_THAT(mount("", f.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1742 ASSERT_THAT(mount("", g.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1743 1744 // Add B to A's shared group. 1745 auto const b_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1746 Mount(a.path().c_str(), b.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1747 1748 // Add C to A's shared group and place J and K in C's peer group, then make 1749 // them slaves. 1750 auto const c_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1751 Mount(a.path().c_str(), c.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1752 auto const j_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1753 Mount(c.path().c_str(), j.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1754 auto const k_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1755 Mount(c.path().c_str(), k.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1756 ASSERT_THAT(mount("", j.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1757 ASSERT_THAT(mount("", k.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1758 1759 // Add D to A's shared group and place H and I in Ds peer group, then make 1760 // them slaves. 1761 auto const d_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1762 Mount(a.path().c_str(), d.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1763 auto const h_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1764 Mount(d.path().c_str(), h.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1765 auto const i_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1766 Mount(d.path().c_str(), i.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1767 ASSERT_THAT(mount("", h.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1768 ASSERT_THAT(mount("", i.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1769 1770 // Make E shared and create a group with O. 1771 ASSERT_THAT(mount("", e.path().c_str(), "", MS_SHARED, 0), SyscallSucceeds()); 1772 auto const o_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1773 Mount(e.path().c_str(), o.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1774 1775 // Add M, L and N to K's shared group and make them slaves of O. 1776 auto const m_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1777 Mount(o.path().c_str(), m.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1778 auto const l_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1779 Mount(o.path().c_str(), l.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1780 auto const n_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1781 Mount(o.path().c_str(), n.path().c_str(), "", MS_BIND, "", MNT_DETACH)); 1782 ASSERT_THAT(mount("", m.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1783 ASSERT_THAT(mount("", l.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1784 ASSERT_THAT(mount("", n.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1785 1786 std::vector<ProcMountInfoEntry> mounts = 1787 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); 1788 1789 ASSERT_THAT(mount("", a.path().c_str(), kTmpfs, 0, ""), SyscallSucceeds()); 1790 1791 std::vector<ProcMountInfoEntry> mounts_after_mount = 1792 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); 1793 ASSERT_EQ(mounts_after_mount.size(), mounts.size() + 15); 1794 1795 auto optionals = ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1796 1797 // A, B, C, and D are all mounted over and in a peer group. 1798 ASSERT_NE(optionals[a.path()][1].shared, 0); 1799 ASSERT_EQ(optionals[a.path()][1].shared, optionals[b.path()][1].shared); 1800 ASSERT_EQ(optionals[a.path()][1].shared, optionals[c.path()][1].shared); 1801 ASSERT_EQ(optionals[a.path()][1].shared, optionals[d.path()][1].shared); 1802 1803 // E, F, G, H, I, J, K are all mounted over and slave to A's peer group. 1804 ASSERT_EQ(optionals[a.path()][1].shared, optionals[e.path()][1].master); 1805 ASSERT_EQ(optionals[a.path()][1].shared, optionals[f.path()][1].master); 1806 ASSERT_EQ(optionals[a.path()][1].shared, optionals[g.path()][1].master); 1807 ASSERT_EQ(optionals[a.path()][1].shared, optionals[h.path()][1].master); 1808 ASSERT_EQ(optionals[a.path()][1].shared, optionals[i.path()][1].master); 1809 ASSERT_EQ(optionals[a.path()][1].shared, optionals[j.path()][1].master); 1810 ASSERT_EQ(optionals[a.path()][1].shared, optionals[k.path()][1].master); 1811 1812 // E and O are all mounted over and in a peer group. 1813 ASSERT_EQ(optionals[e.path()][1].shared, optionals[o.path()][1].shared); 1814 1815 // L, M, and N are all mounted over and slaves to E's peer group. 1816 ASSERT_EQ(optionals[e.path()][1].shared, optionals[l.path()][1].master); 1817 ASSERT_EQ(optionals[e.path()][1].shared, optionals[m.path()][1].master); 1818 ASSERT_EQ(optionals[e.path()][1].shared, optionals[n.path()][1].master); 1819 1820 ASSERT_THAT(umount2(a.path().c_str(), MNT_DETACH), SyscallSucceeds()); 1821 std::vector<ProcMountInfoEntry> mounts_after_umount = 1822 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); 1823 ASSERT_EQ(mounts_after_umount.size(), mounts.size()); 1824 } 1825 1826 TEST(MountTest, MaxMountsWithSlave) { 1827 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1828 1829 auto const parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1830 auto const parent_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1831 Mount("test", parent.path(), kTmpfs, 0, "mode=0123", MNT_DETACH)); 1832 auto const a = 1833 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path())); 1834 auto const b = 1835 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path())); 1836 auto const c = 1837 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path())); 1838 1839 auto const a_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1840 Mount("test", a.path(), kTmpfs, 0, "mode=0123", MNT_DETACH)); 1841 ASSERT_THAT(mount("", a.path().c_str(), "", MS_SHARED, 0), SyscallSucceeds()); 1842 1843 auto const b_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1844 Mount(a.path(), b.path(), "", MS_BIND, "", MNT_DETACH)); 1845 ASSERT_THAT(mount("", b.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1846 ASSERT_THAT(mount("", b.path().c_str(), "", MS_SHARED, 0), SyscallSucceeds()); 1847 1848 auto const c_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1849 Mount(b.path(), c.path(), "", MS_BIND, "", MNT_DETACH)); 1850 ASSERT_THAT(mount("", c.path().c_str(), "", MS_SLAVE, 0), SyscallSucceeds()); 1851 1852 auto const d = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(a.path())); 1853 auto const e = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(a.path())); 1854 1855 int mount_max = 10000; 1856 bool mount_max_exists = 1857 ASSERT_NO_ERRNO_AND_VALUE(Exists("/proc/sys/fs/mount-max")); 1858 if (mount_max_exists) { 1859 std::string mount_max_string; 1860 ASSERT_NO_ERRNO(GetContents("/proc/sys/fs/mount-max", &mount_max_string)); 1861 ASSERT_TRUE(absl::SimpleAtoi(mount_max_string, &mount_max)); 1862 } 1863 1864 // Each bind mount doubles the number of mounts in the propagation tree 1865 // starting with 3. The number of binds we can do before failing is 1866 // log2((max_mounts-num_current_mounts)/3). 1867 std::vector<ProcMountInfoEntry> mounts = 1868 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); 1869 int num_binds = static_cast<int>(std::log2((mount_max - mounts.size()) / 3)); 1870 1871 for (int i = 0; i < num_binds; i++) { 1872 ASSERT_THAT( 1873 mount(d.path().c_str(), d.path().c_str(), nullptr, MS_BIND, nullptr), 1874 SyscallSucceeds()); 1875 ASSERT_THAT(mount("", d.path().c_str(), "", MS_SHARED, 0), 1876 SyscallSucceeds()); 1877 } 1878 for (int i = 0; i < 2; i++) { 1879 EXPECT_THAT( 1880 mount(d.path().c_str(), d.path().c_str(), nullptr, MS_BIND, nullptr), 1881 SyscallFailsWithErrno(ENOSPC)); 1882 } 1883 } 1884 1885 TEST(MountTest, SetPropagationRecursive) { 1886 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1887 1888 const TempPath a = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1889 auto const a_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1890 Mount("test", a.path(), kTmpfs, 0, "mode=0123", MNT_DETACH)); 1891 const auto b = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(a.path())); 1892 auto const b_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1893 Mount("test", b.path(), kTmpfs, 0, "mode=0123", MNT_DETACH)); 1894 const auto c = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(b.path())); 1895 auto const c_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1896 Mount("test", c.path(), kTmpfs, 0, "mode=0123", MNT_DETACH)); 1897 const auto d = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(c.path())); 1898 auto const d_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1899 Mount("test", d.path(), kTmpfs, 0, "mode=0123", MNT_DETACH)); 1900 1901 ASSERT_THAT(mount("", a.path().c_str(), "", MS_SHARED | MS_REC, 0), 1902 SyscallSucceeds()); 1903 absl::flat_hash_map<std::string, std::vector<MountOptional>> optionals = 1904 ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1905 EXPECT_NE(optionals[a.path()][0].shared, 0); 1906 EXPECT_NE(optionals[b.path()][0].shared, 0); 1907 EXPECT_NE(optionals[c.path()][0].shared, 0); 1908 EXPECT_NE(optionals[d.path()][0].shared, 0); 1909 } 1910 1911 TEST(MountTest, SetSlaveRecursive) { 1912 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1913 1914 const auto a = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1915 auto const a_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1916 Mount(a.path(), a.path(), "", MS_BIND, "", MNT_DETACH)); 1917 ASSERT_THAT(mount("", a.path().c_str(), "", MS_SHARED, 0), SyscallSucceeds()); 1918 const auto a_master = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1919 auto const a_master_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1920 Mount(a.path(), a_master.path(), "", MS_BIND, "", MNT_DETACH)); 1921 1922 const auto b = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(a.path())); 1923 auto const b_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1924 Mount(a.path(), b.path(), "", MS_BIND, "", MNT_DETACH)); 1925 const auto b_master = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1926 auto const b_master_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1927 Mount(b.path(), b_master.path(), "", MS_BIND, "", MNT_DETACH)); 1928 1929 ASSERT_THAT(mount("", a.path().c_str(), "", MS_SLAVE | MS_REC, 0), 1930 SyscallSucceeds()); 1931 1932 absl::flat_hash_map<std::string, std::vector<MountOptional>> optionals = 1933 ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 1934 EXPECT_EQ(optionals[a.path()][0].master, 1935 optionals[a_master.path()][0].shared); 1936 EXPECT_EQ(optionals[b.path()][0].master, 1937 optionals[b_master.path()][0].shared); 1938 } 1939 1940 TEST(MountTest, RecursiveBind) { 1941 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1942 1943 const auto a = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1944 auto const a_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1945 Mount(a.path(), a.path(), "", MS_BIND, "", MNT_DETACH)); 1946 const auto b = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(a.path())); 1947 auto const b_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1948 Mount(b.path(), b.path(), "", MS_BIND, "", MNT_DETACH)); 1949 const auto c = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(b.path())); 1950 const auto d = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1951 auto const d_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1952 Mount(a.path(), d.path(), "", MS_BIND | MS_REC, "", MNT_DETACH)); 1953 1954 // Write to child1 in dir1. 1955 const std::string filename = "foo.txt"; 1956 const std::string contents = "barbaz"; 1957 ASSERT_NO_ERRNO( 1958 CreateWithContents(JoinPath(c.path(), filename), contents, 0666)); 1959 // Verify both directories have the same nodes. 1960 const std::string path = 1961 JoinPath(d.path(), Basename(b.path()), Basename(c.path()), filename); 1962 1963 std::string output; 1964 ASSERT_NO_ERRNO(GetContents(path, &output)); 1965 EXPECT_EQ(output, contents); 1966 } 1967 1968 TEST(MountTest, MaxRecursiveBind) { 1969 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 1970 1971 const auto a = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 1972 auto const a_mnt = ASSERT_NO_ERRNO_AND_VALUE( 1973 Mount(a.path(), a.path(), "", MS_BIND, "", MNT_DETACH)); 1974 const auto b = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(a.path())); 1975 1976 int mount_max = 10000; 1977 bool mount_max_exists = 1978 ASSERT_NO_ERRNO_AND_VALUE(Exists("/proc/sys/fs/mount-max")); 1979 if (mount_max_exists) { 1980 std::string mount_max_string; 1981 ASSERT_NO_ERRNO(GetContents("/proc/sys/fs/mount-max", &mount_max_string)); 1982 ASSERT_TRUE(absl::SimpleAtoi(mount_max_string, &mount_max)); 1983 } 1984 1985 const std::vector<ProcMountInfoEntry> mounts = 1986 ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); 1987 int num_binds = static_cast<int>(std::log2(mount_max - mounts.size())); 1988 1989 for (int i = 0; i < num_binds; i++) { 1990 ASSERT_THAT(mount(a.path().c_str(), b.path().c_str(), nullptr, 1991 MS_BIND | MS_REC, nullptr), 1992 SyscallSucceeds()); 1993 } 1994 ASSERT_THAT(mount(a.path().c_str(), b.path().c_str(), nullptr, 1995 MS_BIND | MS_REC, nullptr), 1996 SyscallFailsWithErrno(ENOSPC)); 1997 } 1998 1999 TEST(MountTest, RecursiveBindPropagation) { 2000 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2001 2002 const auto parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2003 auto const parent_mnt = ASSERT_NO_ERRNO_AND_VALUE( 2004 Mount(parent.path(), parent.path(), "", MS_BIND, "", MNT_DETACH)); 2005 const auto a = 2006 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path())); 2007 const auto b = 2008 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path())); 2009 const auto c = 2010 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path())); 2011 2012 auto const a_mnt = ASSERT_NO_ERRNO_AND_VALUE( 2013 Mount("test", a.path(), kTmpfs, 0, "", MNT_DETACH)); 2014 ASSERT_THAT(mount("", a.path().c_str(), "", MS_SHARED, 0), SyscallSucceeds()); 2015 2016 auto const b_mnt = ASSERT_NO_ERRNO_AND_VALUE( 2017 Mount(a.path(), b.path(), "", MS_BIND, "", MNT_DETACH)); 2018 auto const c_mnt = ASSERT_NO_ERRNO_AND_VALUE( 2019 Mount(a.path(), c.path(), "", MS_BIND, "", MNT_DETACH)); 2020 2021 const auto d = 2022 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path())); 2023 const auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(a.path())); 2024 auto const d_mnt = ASSERT_NO_ERRNO_AND_VALUE( 2025 Mount(d.path(), d.path(), "", MS_BIND, "", MNT_DETACH)); 2026 2027 const auto e = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(d.path())); 2028 auto const e_mnt = ASSERT_NO_ERRNO_AND_VALUE( 2029 Mount(e.path(), e.path(), "", MS_BIND, "", MNT_DETACH)); 2030 2031 auto const f_mnt = ASSERT_NO_ERRNO_AND_VALUE( 2032 Mount(d.path(), f.path(), "", MS_BIND | MS_REC, "", MNT_DETACH)); 2033 2034 absl::flat_hash_map<std::string, std::vector<MountOptional>> optionals = 2035 ASSERT_NO_ERRNO_AND_VALUE(MountOptionals()); 2036 auto b_e_path = JoinPath(b.path(), Basename(f.path()), Basename(e.path())); 2037 ASSERT_FALSE(optionals[b_e_path].empty()); 2038 auto c_e_path = JoinPath(c.path(), Basename(f.path()), Basename(e.path())); 2039 ASSERT_FALSE(optionals[c_e_path].empty()); 2040 } 2041 2042 TEST(MountTest, MountNamespace) { 2043 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2044 2045 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2046 auto const mount = ASSERT_NO_ERRNO_AND_VALUE( 2047 Mount("", dir.path(), kTmpfs, 0, "mode=0700", 0)); 2048 auto const file_path = JoinPath(dir.path(), "foo"); 2049 EXPECT_NO_ERRNO(Open(file_path, O_CREAT | O_RDWR, 0777)); 2050 2051 pid_t child = fork(); 2052 if (child == 0) { 2053 // Create a new mount namespace and umount the test mount from it. 2054 TEST_PCHECK(unshare(CLONE_NEWNS) == 0); 2055 TEST_PCHECK(access(file_path.c_str(), F_OK) == 0); 2056 TEST_PCHECK(umount2(dir.path().c_str(), MNT_DETACH) == 0); 2057 _exit(0); 2058 } 2059 ASSERT_THAT(child, SyscallSucceeds()); 2060 int status; 2061 ASSERT_THAT(waitpid(child, &status, 0), SyscallSucceedsWithValue(child)); 2062 ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); 2063 2064 // Check that the test mount is still here. 2065 EXPECT_NO_ERRNO(Open(file_path, O_RDWR)); 2066 } 2067 2068 TEST(MountTest, MountNamespaceSetns) { 2069 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2070 2071 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2072 auto const mnt = ASSERT_NO_ERRNO_AND_VALUE( 2073 Mount("", dir.path(), kTmpfs, 0, "mode=0700", MNT_DETACH)); 2074 auto const file_path = JoinPath(dir.path(), "foo"); 2075 EXPECT_NO_ERRNO(Open(file_path, O_CREAT | O_RDWR, 0777)); 2076 const FileDescriptor nsfd = 2077 ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/thread-self/ns/mnt", O_RDONLY)); 2078 2079 pid_t child = fork(); 2080 if (child == 0) { 2081 TEST_PCHECK(unshare(CLONE_NEWNS) == 0); 2082 TEST_PCHECK(umount2(dir.path().c_str(), MNT_DETACH) == 0); 2083 TEST_PCHECK(setns(nsfd.get(), CLONE_NEWNS) == 0); 2084 TEST_PCHECK(access(file_path.c_str(), F_OK) == 0); 2085 _exit(0); 2086 } 2087 ASSERT_THAT(child, SyscallSucceeds()); 2088 int status; 2089 ASSERT_THAT(waitpid(child, &status, 0), SyscallSucceedsWithValue(child)); 2090 ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); 2091 } 2092 2093 TEST(MountTest, MountNamespacePropagation) { 2094 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2095 2096 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2097 auto const mnt = ASSERT_NO_ERRNO_AND_VALUE( 2098 Mount("", dir.path(), kTmpfs, 0, "mode=0700", MNT_DETACH)); 2099 auto child_dir = JoinPath(dir.path(), "test"); 2100 auto const file_path = JoinPath(child_dir, "foo"); 2101 auto const file2_path = JoinPath(child_dir, "boo"); 2102 2103 ASSERT_THAT(mount(NULL, dir.path().c_str(), NULL, MS_SHARED, NULL), 2104 SyscallSucceeds()); 2105 ASSERT_THAT(mkdir(child_dir.c_str(), 0700), SyscallSucceeds()); 2106 ASSERT_THAT(mount("child", child_dir.c_str(), kTmpfs, 0, NULL), 2107 SyscallSucceeds()); 2108 EXPECT_NO_ERRNO(Open(file_path, O_CREAT | O_RDWR, 0777)); 2109 2110 pid_t child = fork(); 2111 if (child == 0) { 2112 TEST_PCHECK(unshare(CLONE_NEWNS) == 0); 2113 TEST_PCHECK(access(file_path.c_str(), F_OK) == 0); 2114 // The test mount has to be umounted from the second mount namespace too. 2115 TEST_PCHECK(umount2(child_dir.c_str(), MNT_DETACH) == 0); 2116 // The new mount has to be propagated to the second mount namespace. 2117 TEST_PCHECK(mount("test2", child_dir.c_str(), kTmpfs, 0, NULL) == 0); 2118 TEST_PCHECK(mknod(file2_path.c_str(), 0777 | S_IFREG, 0) == 0); 2119 _exit(0); 2120 } 2121 ASSERT_THAT(child, SyscallSucceeds()); 2122 int status; 2123 ASSERT_THAT(waitpid(child, &status, 0), SyscallSucceedsWithValue(child)); 2124 ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); 2125 2126 // Check that the test mount is still here. 2127 EXPECT_NO_ERRNO(Open(file2_path, O_RDWR)); 2128 EXPECT_THAT(umount2(child_dir.c_str(), MNT_DETACH), SyscallSucceeds()); 2129 } 2130 2131 TEST(MountTest, MountNamespaceSlavesNewUserNamespace) { 2132 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2133 SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(IsOverlayfs(GetAbsoluteTestTmpdir()))); 2134 const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2135 2136 const Cleanup dir_mount = ASSERT_NO_ERRNO_AND_VALUE( 2137 Mount("", dir.path(), kTmpfs, 0, "", MNT_DETACH)); 2138 ASSERT_THAT(mount(NULL, dir.path().c_str(), NULL, MS_SHARED, NULL), 2139 SyscallSucceeds()); 2140 const TempPath child_dir = 2141 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path())); 2142 const std::string file_path = JoinPath(child_dir.path(), "foo"); 2143 const std::string file2_path = JoinPath(child_dir.path(), "boo"); 2144 2145 const std::function<void()> parent = [&] { 2146 TEST_CHECK_SUCCESS( 2147 mount("child", child_dir.path().c_str(), kTmpfs, 0, NULL)); 2148 TEST_CHECK_SUCCESS(open(file_path.c_str(), O_CREAT | O_RDWR, 0777)); 2149 }; 2150 const std::function<void()> child = [&] { 2151 TEST_CHECK_SUCCESS(access(JoinPath(child_dir.path(), "foo").c_str(), F_OK)); 2152 2153 // These mount operations will not propagate to the other namespace 2154 // because it is a slave mount. 2155 TEST_CHECK_SUCCESS(umount2(child_dir.path().c_str(), MNT_DETACH)); 2156 TEST_CHECK_SUCCESS( 2157 mount("test2", child_dir.path().c_str(), kTmpfs, 0, NULL)); 2158 TEST_CHECK_SUCCESS(mknod(file2_path.c_str(), 0777 | S_IFREG, 0)); 2159 2160 TEST_CHECK_SUCCESS(umount2(child_dir.path().c_str(), MNT_DETACH)); 2161 // This should fail because the mount is locked. 2162 TEST_CHECK_ERRNO(umount2(child_dir.path().c_str(), MNT_DETACH), EINVAL); 2163 2164 // Check that there is a master entry in mountinfo. 2165 int fd = open("/proc/self/mountinfo", O_RDONLY); 2166 TEST_CHECK(fd >= 0); 2167 char child_mountinfo[0x8000]; 2168 int size = 0; 2169 while (true) { 2170 int ret = 2171 read(fd, child_mountinfo + size, sizeof(child_mountinfo) - size); 2172 TEST_CHECK(ret != -1); 2173 size += ret; 2174 if (ret == 0) { 2175 break; 2176 } 2177 } 2178 TEST_CHECK(absl::StrContains(child_mountinfo, "master:")); 2179 }; 2180 EXPECT_THAT(InForkedUserMountNamespace(parent, child), 2181 IsPosixErrorOkAndHolds(0)); 2182 2183 // Check that the test mount is still here. 2184 EXPECT_EQ(Open(file2_path, O_RDWR).error().errno_value(), ENOENT); 2185 EXPECT_THAT(umount2(child_dir.path().c_str(), MNT_DETACH), SyscallSucceeds()); 2186 } 2187 2188 TEST(MountTest, LockedMountStopsNonRecBind) { 2189 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2190 SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(IsOverlayfs(GetAbsoluteTestTmpdir()))); 2191 2192 const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2193 const Cleanup dir_mount = ASSERT_NO_ERRNO_AND_VALUE( 2194 Mount("", dir.path(), kTmpfs, 0, "", MNT_DETACH)); 2195 const TempPath child_dir = 2196 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path())); 2197 const Cleanup child_mount = ASSERT_NO_ERRNO_AND_VALUE( 2198 Mount("", child_dir.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 2199 const std::string foo_dir = JoinPath(dir.path(), "foo"); 2200 2201 const std::function<void()> child_fn = [&] { 2202 TEST_CHECK_SUCCESS(mkdir(foo_dir.c_str(), 0700)); 2203 TEST_CHECK_ERRNO( 2204 mount(dir.path().c_str(), foo_dir.c_str(), "", MS_BIND, ""), EINVAL); 2205 TEST_CHECK_SUCCESS( 2206 mount(dir.path().c_str(), foo_dir.c_str(), "", MS_BIND | MS_REC, "")); 2207 }; 2208 EXPECT_THAT(InForkedUserMountNamespace([] {}, child_fn), 2209 IsPosixErrorOkAndHolds(0)); 2210 } 2211 2212 // This test checks that a mount tree that propagates from a more privileged 2213 // mount namespace cannot be partially unmounted. It must be unmounted as a 2214 // single unit as described in point 4 of the notes in 2215 // https://man7.org/linux/man-pages/man7/mount_namespaces.7.html. This test 2216 // also checks that unmounting a propagated mount tree does not reveal the 2217 // contents of overmounted filesystems from the more privileged mount namespace. 2218 TEST(MountTest, UmountPropagatedSubtreeFromPrivilegedNS) { 2219 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2220 SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(IsOverlayfs(GetAbsoluteTestTmpdir()))); 2221 2222 const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2223 const Cleanup dir_mount = ASSERT_NO_ERRNO_AND_VALUE( 2224 Mount(dir.path(), dir.path(), "", MS_BIND, "", MNT_DETACH)); 2225 ASSERT_THAT(mount(NULL, dir.path().c_str(), NULL, MS_SHARED, NULL), 2226 SyscallSucceeds()); 2227 2228 const TempPath child_dir = 2229 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path())); 2230 const TempPath sibling_dir = 2231 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path())); 2232 const Cleanup child_mount = ASSERT_NO_ERRNO_AND_VALUE( 2233 Mount("", child_dir.path(), kTmpfs, 0, "", MNT_DETACH)); 2234 ASSERT_THAT(mount(NULL, child_dir.path().c_str(), NULL, MS_PRIVATE, NULL), 2235 SyscallSucceeds()); 2236 2237 const TempPath grandchild_dir = 2238 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(child_dir.path())); 2239 ASSERT_THAT(open(JoinPath(grandchild_dir.path(), "foo").c_str(), 2240 O_CREAT | O_RDWR, 0777), 2241 SyscallSucceeds()); 2242 const Cleanup grandchild_mnt = ASSERT_NO_ERRNO_AND_VALUE( 2243 Mount("", grandchild_dir.path(), kTmpfs, 0, "", MNT_DETACH)); 2244 ASSERT_THAT( 2245 mount(NULL, grandchild_dir.path().c_str(), NULL, MS_PRIVATE, NULL), 2246 SyscallSucceeds()); 2247 const std::string grandsibling_dir = 2248 JoinPath(sibling_dir.path(), Basename(grandchild_dir.path())); 2249 2250 const std::function<void()> parent = [&] { 2251 TEST_CHECK_SUCCESS(mount(child_dir.path().c_str(), 2252 sibling_dir.path().c_str(), "", MS_BIND | MS_REC, 2253 "")); 2254 TEST_CHECK_SUCCESS( 2255 mount("", sibling_dir.path().c_str(), "", MS_PRIVATE | MS_REC, "")); 2256 }; 2257 // You can umount an entire subtree that propagated from a more privileged 2258 // mount namespace, but can't umount only part of the subtree. 2259 const std::string file_path = 2260 JoinPath(Basename(grandchild_dir.path()), "foo"); 2261 const std::function<void()> child = [&] { 2262 TEST_CHECK_ERRNO(umount2(grandsibling_dir.c_str(), MNT_DETACH), EINVAL); 2263 int dirfd = open(sibling_dir.path().c_str(), O_RDONLY | O_DIRECTORY); 2264 TEST_PCHECK(dirfd >= 0); 2265 TEST_CHECK_SUCCESS(umount2(sibling_dir.path().c_str(), MNT_DETACH)); 2266 // Check to ensure you cannot access an overmounted file with openat after 2267 // the mount unit has been destroyed. 2268 TEST_CHECK_ERRNO(openat(dirfd, file_path.c_str(), O_RDONLY), ENOENT); 2269 }; 2270 EXPECT_THAT(InForkedUserMountNamespace(parent, child), 2271 IsPosixErrorOkAndHolds(0)); 2272 } 2273 2274 TEST(MountTest, MountFailsOnPseudoFilesystemMountpoint) { 2275 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2276 auto const fd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, 0)); 2277 std::string path = absl::StrCat("/proc/self/fd/", fd.get()); 2278 EXPECT_THAT(mount("test", path.c_str(), kTmpfs, 0, 0), 2279 SyscallFailsWithErrno(EINVAL)); 2280 } 2281 2282 TEST(MountTest, ChangeMountFlags) { 2283 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2284 2285 const auto flag = MS_NODEV; 2286 const auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2287 const auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2288 const auto mount_cleanup = ASSERT_NO_ERRNO_AND_VALUE( 2289 Mount(dir1.path(), dir2.path(), kTmpfs, MS_BIND, "", 0)); 2290 2291 struct statfs st; 2292 EXPECT_THAT(mount(dir1.path().c_str(), dir2.path().c_str(), kTmpfs, 2293 MS_REMOUNT | MS_BIND | flag, ""), 2294 SyscallSucceeds()); 2295 EXPECT_THAT(statfs(dir2.path().c_str(), &st), SyscallSucceeds()); 2296 EXPECT_EQ(st.f_flags & flag, flag); 2297 // Resets mount flags. 2298 EXPECT_THAT(mount(dir1.path().c_str(), dir2.path().c_str(), kTmpfs, 2299 MS_REMOUNT | MS_BIND, ""), 2300 SyscallSucceeds()); 2301 ASSERT_THAT(statfs(dir2.path().c_str(), &st), SyscallSucceeds()); 2302 ASSERT_EQ(st.f_flags & flag, 0); 2303 } 2304 2305 TEST(MountTest, RemountUnmounted) { 2306 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2307 2308 auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2309 2310 EXPECT_THAT(mount("", dir.path().c_str(), kTmpfs, MS_REMOUNT, ""), 2311 SyscallFailsWithErrno(EINVAL)); 2312 } 2313 2314 TEST(MountTest, DetachedMountBindFails) { 2315 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 2316 2317 const TempPath path1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2318 Cleanup mount_cleanup = ASSERT_NO_ERRNO_AND_VALUE( 2319 Mount("", path1.path().c_str(), kTmpfs, 0, "", MNT_DETACH)); 2320 mount_cleanup.Release(); 2321 const FileDescriptor fd = 2322 ASSERT_NO_ERRNO_AND_VALUE(Open(path1.path().c_str(), O_RDONLY)); 2323 std::string fd_path = absl::Substitute("/proc/self/fd/$0", fd.get()); 2324 ASSERT_THAT(umount2(path1.path().c_str(), MNT_DETACH), SyscallSucceeds()); 2325 const TempPath path2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 2326 2327 EXPECT_THAT(mount(fd_path.c_str(), path2.path().c_str(), "", MS_BIND, 0), 2328 SyscallFailsWithErrno(EINVAL)); 2329 } 2330 2331 } // namespace 2332 2333 } // namespace testing 2334 } // namespace gvisor