Modify pivot_root to return errors in cases of shared mounts.

This is in line with linux as described here
https://man7.org/linux/man-pages/man2/pivot_root.2.html

PiperOrigin-RevId: 486388848
This commit is contained in:
Lucas Manning
2022-11-05 14:09:42 -07:00
committed by gVisor bot
parent 1fc476d7fe
commit 7520b7f833
2 changed files with 111 additions and 15 deletions
+12 -3
View File
@@ -1121,11 +1121,20 @@ retry:
if rootVd.mount.ns != ns || newRootVd.mount.ns != ns {
return linuxerr.EINVAL
}
// TODO(gvisor.dev/issues/221): Update this function to disallow
// pivot_root-ing new_root/put_old mounts with MS_SHARED propagation once it
// is implemented in gVisor.
vfs.mountMu.Lock()
// Either the mount point at new_root, or the parent mount of that mount
// point, has propagation type MS_SHARED.
if newRootParent := newRootVd.mount.parent(); newRootVd.mount.propType == Shared || newRootParent.propType == Shared {
vfs.mountMu.Unlock()
return linuxerr.EINVAL
}
// put_old is a mount point and has the propagation type MS_SHARED.
if putOldVd.mount.root == putOldVd.dentry && putOldVd.mount.propType == Shared {
vfs.mountMu.Unlock()
return linuxerr.EINVAL
}
if !vfs.mounts.seq.BeginWriteOk(epoch) {
// Checks above raced with a mount change.
vfs.mountMu.Unlock()
+99 -12
View File
@@ -325,8 +325,8 @@ TEST(PivotRootTest, NewRootNotAMountpoint) {
SyscallSucceeds());
const std::string mountpoint_path =
absl::StrCat("/", Basename(mountpoint.path()));
auto new_root = ASSERT_NO_ERRNO_AND_VALUE(
TempPath::CreateDirIn(mountpoint.path()));
auto new_root =
ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(mountpoint.path()));
const std::string new_root_path =
absl::StrCat(mountpoint_path, "/", Basename(new_root.path()));
auto put_old =
@@ -336,8 +336,9 @@ TEST(PivotRootTest, NewRootNotAMountpoint) {
const auto rest = [&] {
TEST_CHECK_SUCCESS(chroot(root.path().c_str()));
TEST_CHECK_ERRNO(syscall(
__NR_pivot_root, new_root_path.c_str(), put_old_path.c_str()), EINVAL);
TEST_CHECK_ERRNO(
syscall(__NR_pivot_root, new_root_path.c_str(), put_old_path.c_str()),
EINVAL);
};
EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
}
@@ -349,16 +350,13 @@ TEST(PivotRootTest, PutOldNotUnderNewRoot) {
auto root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
EXPECT_THAT(mount("", root.path().c_str(), "tmpfs", 0, "mode=0700"),
SyscallSucceeds());
auto new_root =
ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
auto new_root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
const std::string new_root_path =
absl::StrCat("/", Basename(new_root.path()));
EXPECT_THAT(mount("", new_root.path().c_str(), "tmpfs", 0, "mode=0700"),
SyscallSucceeds());
auto put_old =
ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
const std::string put_old_path =
absl::StrCat("/", Basename(put_old.path()));
auto put_old = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
const std::string put_old_path = absl::StrCat("/", Basename(put_old.path()));
EXPECT_THAT(mount("", put_old.path().c_str(), "tmpfs", 0, "mode=0700"),
SyscallSucceeds());
@@ -388,8 +386,9 @@ TEST(PivotRootTest, CurrentRootNotAMountPoint) {
const auto rest = [&] {
TEST_CHECK_SUCCESS(chroot(root.path().c_str()));
TEST_CHECK_ERRNO(syscall(
__NR_pivot_root, new_root_path.c_str(), put_old_path.c_str()), EINVAL);
TEST_CHECK_ERRNO(
syscall(__NR_pivot_root, new_root_path.c_str(), put_old_path.c_str()),
EINVAL);
};
EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
}
@@ -414,6 +413,94 @@ TEST(PivotRootTest, OnRootFS) {
EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
}
TEST(PivotRootTest, OnSharedNewRootParent) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_CHROOT)));
auto root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
EXPECT_THAT(mount("", root.path().c_str(), "tmpfs", 0, "mode=0700"),
SyscallSucceeds());
auto new_root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
EXPECT_THAT(mount("", new_root.path().c_str(), "tmpfs", 0, "mode=0700"),
SyscallSucceeds());
const std::string new_root_path = JoinPath("/", Basename(new_root.path()));
auto put_old =
ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(new_root.path()));
const std::string put_old_path =
JoinPath(new_root_path, "/", Basename(put_old.path()));
// Fails because parent has propagation type shared.
EXPECT_THAT(mount(nullptr, root.path().c_str(), nullptr, MS_SHARED, nullptr),
SyscallSucceeds());
const auto rest = [&] {
TEST_CHECK_SUCCESS(chroot(root.path().c_str()));
TEST_CHECK_ERRNO(
syscall(__NR_pivot_root, new_root_path.c_str(), put_old_path.c_str()),
EINVAL);
};
EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
}
TEST(PivotRootTest, OnSharedNewRoot) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_CHROOT)));
auto root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
EXPECT_THAT(mount("", root.path().c_str(), "tmpfs", 0, "mode=0700"),
SyscallSucceeds());
auto new_root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
EXPECT_THAT(mount("", new_root.path().c_str(), "tmpfs", 0, "mode=0700"),
SyscallSucceeds());
const std::string new_root_path = JoinPath("/", Basename(new_root.path()));
auto put_old =
ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(new_root.path()));
const std::string put_old_path =
JoinPath(new_root_path, "/", Basename(put_old.path()));
// Fails because new_root has propagation type shared.
EXPECT_THAT(
mount(nullptr, new_root.path().c_str(), nullptr, MS_SHARED, nullptr),
SyscallSucceeds());
const auto rest = [&] {
TEST_CHECK_SUCCESS(chroot(root.path().c_str()));
TEST_CHECK_ERRNO(
syscall(__NR_pivot_root, new_root_path.c_str(), put_old_path.c_str()),
EINVAL);
};
EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
}
TEST(PivotRootTest, OnSharedPutOldMountpoint) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_CHROOT)));
auto root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
EXPECT_THAT(mount("", root.path().c_str(), "tmpfs", 0, "mode=0700"),
SyscallSucceeds());
auto new_root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
EXPECT_THAT(mount("", new_root.path().c_str(), "tmpfs", 0, "mode=0700"),
SyscallSucceeds());
const std::string new_root_path = JoinPath("/", Basename(new_root.path()));
auto put_old =
ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(new_root.path()));
const std::string put_old_path =
JoinPath(new_root_path, "/", Basename(put_old.path()));
// Fails because put_old is a mountpoint and has propagation type shared.
EXPECT_THAT(mount("", put_old.path().c_str(), "tmpfs", 0, "mode=0700"),
SyscallSucceeds());
EXPECT_THAT(
mount(nullptr, put_old.path().c_str(), nullptr, MS_SHARED, nullptr),
SyscallSucceeds());
const auto rest = [&] {
TEST_CHECK_SUCCESS(chroot(root.path().c_str()));
TEST_CHECK_ERRNO(
syscall(__NR_pivot_root, new_root_path.c_str(), put_old_path.c_str()),
EINVAL);
};
EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0));
}
} // namespace
} // namespace testing