minijail: Copy the mount flags from source when bind-mounting This change makes all bindmounts copy the mount flags from the source path if a remount is issued. It also fixes a bug where ro mounts could never become rw. Bug: 111325710 Test: make tests Test: Repro scenario in https://crbug.com/862171 Change-Id: Ia87ea2933f1ab1b8a9fd2efd6f832c51a5a8f7a2
diff --git a/system_unittest.cc b/system_unittest.cc index e0d4d2b..60d5c03 100644 --- a/system_unittest.cc +++ b/system_unittest.cc
@@ -11,6 +11,7 @@ #include <stdlib.h> #include <string.h> #include <sys/stat.h> +#include <sys/statvfs.h> #include <unistd.h> #include <gtest/gtest.h> @@ -210,15 +211,39 @@ TEST(setup_mount_destination, dest_exists) { // Pick some paths that should always exist. We pass in invalid pointers // for other args so we crash if the dest check doesn't short circuit. - EXPECT_EQ(0, setup_mount_destination(nullptr, kValidDir, 0, 0, false)); - EXPECT_EQ(0, setup_mount_destination(nullptr, "/proc", 0, 0, true)); - EXPECT_EQ(0, setup_mount_destination(nullptr, "/dev", 0, 0, false)); + EXPECT_EQ(0, setup_mount_destination(nullptr, kValidDir, 0, 0, false, + nullptr)); + EXPECT_EQ(0, setup_mount_destination(nullptr, "/proc", 0, 0, true, nullptr)); + EXPECT_EQ(0, setup_mount_destination(nullptr, "/dev", 0, 0, false, nullptr)); +} + +// Mount flags should be obtained for bind-mounts +TEST(setup_mount_destination, mount_flags) { + struct statvfs stvfs_buf; + ASSERT_EQ(0, statvfs("/proc", &stvfs_buf)); + + std::string path = get_temp_path(); + ASSERT_NE(std::string(), path); + + unsigned long mount_flags = -1; + // Passing -1 for user ID/group ID tells chown to make no changes. + EXPECT_EQ(0, setup_mount_destination("/proc", path.c_str(), -1, -1, true, + &mount_flags)); + EXPECT_EQ(stvfs_buf.f_flag, mount_flags); + EXPECT_EQ(0, rmdir(path.c_str())); + + // Same thing holds for children of a mount. + mount_flags = -1; + EXPECT_EQ(0, setup_mount_destination("/proc/self", path.c_str(), -1, -1, true, + &mount_flags)); + EXPECT_EQ(stvfs_buf.f_flag, mount_flags); + EXPECT_EQ(0, rmdir(path.c_str())); } // When given a bind mount where the source is relative, reject it. TEST(setup_mount_destination, reject_relative_bind) { // Pick a destination we know doesn't exist. - EXPECT_NE(0, setup_mount_destination("foo", kNoSuchDir, 0, 0, true)); + EXPECT_NE(0, setup_mount_destination("foo", kNoSuchDir, 0, 0, true, nullptr)); } // A mount of a pseudo filesystem should make the destination dir. @@ -227,7 +252,8 @@ ASSERT_NE(std::string(), path); // Passing -1 for user ID/group ID tells chown to make no changes. - EXPECT_EQ(0, setup_mount_destination("none", path.c_str(), -1, -1, false)); + EXPECT_EQ(0, setup_mount_destination("none", path.c_str(), -1, -1, false, + nullptr)); // We check it's a directory by deleting it as such. EXPECT_EQ(0, rmdir(path.c_str())); @@ -237,15 +263,18 @@ // invalid user ID, just skip this check. if (!is_android()) { EXPECT_NE(0, setup_mount_destination("none", path.c_str(), - UINT_MAX / 2, UINT_MAX / 2, false)); + UINT_MAX / 2, UINT_MAX / 2, false, + nullptr)); } } // If the source path does not exist, we should error out. TEST(setup_mount_destination, missing_source) { // The missing dest path is so we can exercise the source logic. - EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, false)); - EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, true)); + EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, false, + nullptr)); + EXPECT_NE(0, setup_mount_destination(kNoSuchDir, kNoSuchDir, 0, 0, true, + nullptr)); } // A bind mount of a directory should create the destination dir. @@ -254,7 +283,8 @@ ASSERT_NE(std::string(), path); // Passing -1 for user ID/group ID tells chown to make no changes. - EXPECT_EQ(0, setup_mount_destination(kValidDir, path.c_str(), -1, -1, true)); + EXPECT_EQ(0, setup_mount_destination(kValidDir, path.c_str(), -1, -1, true, + nullptr)); // We check it's a directory by deleting it as such. EXPECT_EQ(0, rmdir(path.c_str())); } @@ -265,7 +295,8 @@ ASSERT_NE(std::string(), path); // Passing -1 for user ID/group ID tells chown to make no changes. - EXPECT_EQ(0, setup_mount_destination(kValidFile, path.c_str(), -1, -1, true)); + EXPECT_EQ(0, setup_mount_destination(kValidFile, path.c_str(), -1, -1, true, + nullptr)); // We check it's a file by deleting it as such. EXPECT_EQ(0, unlink(path.c_str())); } @@ -276,7 +307,8 @@ ASSERT_NE(std::string(), path); // Passing -1 for user ID/group ID tells chown to make no changes. - EXPECT_EQ(0, setup_mount_destination(kValidCharDev, path.c_str(), -1, -1, false)); + EXPECT_EQ(0, setup_mount_destination(kValidCharDev, path.c_str(), -1, -1, + false, nullptr)); // We check it's a directory by deleting it as such. EXPECT_EQ(0, rmdir(path.c_str())); }