Skip to content

Commit b80f6c3

Browse files
committed
Merge pull request #13482 from prasanna8585:fix-detached-mount-open-tree
PiperOrigin-RevId: 940007299
2 parents cb25e97 + e712060 commit b80f6c3

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

pkg/sentry/vfs/namespace.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,13 @@ func (vfs *VirtualFilesystem) CloneTreeToAnonNS(
257257
// MS_UNBINDABLE mounts should be rejected here.
258258

259259
fsName := fromMnt.Filesystem().FilesystemType().Name()
260+
// fromMnt must not have been detached from its mount tree (e.g. via
261+
// umount(MNT_DETACH)). Note that fromMnt.ns is not cleared on detach,
262+
// only fromMnt.umounted is set, so this must be checked independently
263+
// of the namespace-membership check below.
264+
if fromMnt.umounted {
265+
return nil, linuxerr.EINVAL
266+
}
260267
// fromMnt must be either:
261268
// - In the same mount ns as the current task
262269
// - In an appropriate anonymous mount namespace

test/syscalls/linux/mount_fd.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,34 @@ TEST(OpenTreeTest, OpenTreeCloneNonRecursiveOnAttached) {
759759
SyscallFailsWithErrno(ENOENT));
760760
}
761761

762+
TEST(OpenTreeTest, OpenTreeCloneFailsOnDetachedMount) {
763+
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
764+
765+
// Create a detached tmpfs mount fd via fsopen/fsmount (no path attachment).
766+
int fsfd = fsopen(kTmpfs, 0);
767+
ASSERT_THAT(fsfd, SyscallSucceeds());
768+
auto cleanup_fs = Cleanup([&]() { close(fsfd); });
769+
ASSERT_THAT(fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0),
770+
SyscallSucceeds());
771+
int mntfd = fsmount(fsfd, 0, 0);
772+
ASSERT_THAT(mntfd, SyscallSucceeds());
773+
auto cleanup_mnt = Cleanup([&]() { close(mntfd); });
774+
775+
// Attach the mount to a path and then detach it via MNT_DETACH while
776+
// keeping the mount fd alive.
777+
const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
778+
ASSERT_THAT(move_mount(mntfd, "", AT_FDCWD, dir.path().c_str(),
779+
MOVE_MOUNT_F_EMPTY_PATH),
780+
SyscallSucceeds());
781+
ASSERT_THAT(umount2(dir.path().c_str(), MNT_DETACH), SyscallSucceeds());
782+
783+
// open_tree(OPEN_TREE_CLONE) on a mount that has already been detached via
784+
// MNT_DETACH must fail with EINVAL, matching Linux. Regression test for
785+
// CloneTreeToAnonNS() not checking Mount.umounted (gvisor.dev/issue/13481).
786+
EXPECT_THAT(open_tree(mntfd, "", AT_EMPTY_PATH | OPEN_TREE_CLONE),
787+
SyscallFailsWithErrno(EINVAL));
788+
}
789+
762790
TEST(OpenTreeTest, OpenTreeCloneNonRecursiveOnDetached) {
763791
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
764792

0 commit comments

Comments
 (0)