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()));
}