mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Fix small mount propagation bug.
The MS_PRIVATE flag was not being cleared in addPeer. Reported-by: syzbot+ea0d65b2da47bf96a8d1@syzkaller.appspotmail.com PiperOrigin-RevId: 557949154
This commit is contained in:
committed by
gVisor bot
parent
5ba2eb884a
commit
960b564a68
+16
-24
@@ -87,8 +87,8 @@ type Mount struct {
|
||||
// Mount. children is protected by VirtualFilesystem.mountMu.
|
||||
children map[*Mount]struct{}
|
||||
|
||||
// propFlags are the propagation flags set on this mount.
|
||||
propFlags uint32
|
||||
// isShared indicates this mount has the MS_SHARED propagation type.
|
||||
isShared bool
|
||||
|
||||
// sharedEntry represents an entry in a circular list (ring) of mounts in a
|
||||
// shared peer group.
|
||||
@@ -116,14 +116,14 @@ func (sharedMapper) linkerFor(mnt *Mount) *sharedEntry { return &mnt.sharedEntry
|
||||
|
||||
func newMount(vfs *VirtualFilesystem, fs *Filesystem, root *Dentry, mntns *MountNamespace, opts *MountOptions) *Mount {
|
||||
mnt := &Mount{
|
||||
ID: vfs.lastMountID.Add(1),
|
||||
Flags: opts.Flags,
|
||||
vfs: vfs,
|
||||
fs: fs,
|
||||
root: root,
|
||||
ns: mntns,
|
||||
propFlags: linux.MS_PRIVATE,
|
||||
refs: atomicbitops.FromInt64(1),
|
||||
ID: vfs.lastMountID.Add(1),
|
||||
Flags: opts.Flags,
|
||||
vfs: vfs,
|
||||
fs: fs,
|
||||
root: root,
|
||||
ns: mntns,
|
||||
isShared: false,
|
||||
refs: atomicbitops.FromInt64(1),
|
||||
}
|
||||
if opts.ReadOnly {
|
||||
mnt.setReadOnlyLocked(true)
|
||||
@@ -148,20 +148,12 @@ func (mnt *Mount) generateOptionalTags() string {
|
||||
defer mnt.vfs.mountMu.Unlock()
|
||||
// TODO(b/249777195): Support MS_SLAVE and MS_UNBINDABLE propagation types.
|
||||
var optional string
|
||||
if mnt.shared() {
|
||||
if mnt.isShared {
|
||||
optional = fmt.Sprintf("shared:%d", mnt.groupID)
|
||||
}
|
||||
return optional
|
||||
}
|
||||
|
||||
func (mnt *Mount) shared() bool {
|
||||
return mnt.propFlags&linux.MS_SHARED != 0
|
||||
}
|
||||
|
||||
func (mnt *Mount) private() bool {
|
||||
return mnt.propFlags&linux.MS_PRIVATE != 0
|
||||
}
|
||||
|
||||
// NewFilesystem creates a new filesystem object not yet associated with any
|
||||
// mounts. It can be installed into the filesystem tree with ConnectMountAt.
|
||||
// Note that only the filesystem-specific mount options from opts are used by
|
||||
@@ -319,7 +311,7 @@ func (vfs *VirtualFilesystem) cloneMount(mnt *Mount, root *Dentry, mopts *MountO
|
||||
}
|
||||
}
|
||||
clone := vfs.NewDisconnectedMount(mnt.fs, root, opts)
|
||||
if mnt.shared() {
|
||||
if mnt.isShared {
|
||||
vfs.addPeer(mnt, clone)
|
||||
}
|
||||
return clone
|
||||
@@ -443,7 +435,7 @@ func (vfs *VirtualFilesystem) UmountAt(ctx context.Context, creds *auth.Credenti
|
||||
|
||||
umountTree := []*Mount{vd.mount}
|
||||
parent, mountpoint := vd.mount.parent(), vd.mount.point()
|
||||
if parent != nil && parent.shared() {
|
||||
if parent != nil && parent.isShared {
|
||||
for peer := parent.sharedEntry.Next(); peer != parent; peer = peer.sharedEntry.Next() {
|
||||
umountMnt := vfs.mounts.Lookup(peer, mountpoint)
|
||||
// From https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt:
|
||||
@@ -537,7 +529,7 @@ func (vfs *VirtualFilesystem) umountRecursiveLocked(mnt *Mount, opts *umountRecu
|
||||
if parent := mnt.parent(); parent != nil && (opts.disconnectHierarchy || !parent.umounted) {
|
||||
vdsToDecRef = append(vdsToDecRef, vfs.disconnectLocked(mnt))
|
||||
}
|
||||
if mnt.shared() {
|
||||
if mnt.isShared {
|
||||
vfs.setPropagation(mnt, linux.MS_PRIVATE)
|
||||
}
|
||||
}
|
||||
@@ -885,12 +877,12 @@ retry:
|
||||
|
||||
// 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.shared() || newRootParent.shared() {
|
||||
if newRootParent := newRootVd.mount.parent(); newRootVd.mount.isShared || newRootParent.isShared {
|
||||
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.shared() {
|
||||
if putOldVd.mount.root == putOldVd.dentry && putOldVd.mount.isShared {
|
||||
vfs.mountMu.Unlock()
|
||||
return linuxerr.EINVAL
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ func (vfs *VirtualFilesystem) CloneMountNamespace(
|
||||
ns.root.root.IncRef()
|
||||
ns.root.fs.IncRef()
|
||||
newns.root = newMount(vfs, ns.root.fs, ns.root.root, newns, &MountOptions{Flags: ns.root.Flags, ReadOnly: ns.root.ReadOnly()})
|
||||
if ns.root.shared() {
|
||||
if ns.root.isShared {
|
||||
vfs.addPeer(ns.root, newns.root)
|
||||
}
|
||||
vfs.updateRootAndCWD(ctx, root, cwd, ns.root, newns.root)
|
||||
|
||||
@@ -56,26 +56,27 @@ func propTypeToString(pflag uint32) string {
|
||||
func (vfs *VirtualFilesystem) setPropagation(mnt *Mount, pflag uint32) error {
|
||||
switch pflag {
|
||||
case linux.MS_SHARED:
|
||||
if mnt.private() {
|
||||
if !mnt.isShared {
|
||||
id, err := vfs.allocateGroupID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mnt.groupID = id
|
||||
sharedRingInit(mnt)
|
||||
mnt.isShared = true
|
||||
}
|
||||
case linux.MS_PRIVATE:
|
||||
if mnt.shared() {
|
||||
if mnt.isShared {
|
||||
if sharedRingEmpty(mnt) {
|
||||
vfs.freeGroupID(mnt.groupID)
|
||||
}
|
||||
sharedRingRemove(mnt)
|
||||
mnt.groupID = 0
|
||||
mnt.isShared = false
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported propagation type: %s", propTypeToString(pflag)))
|
||||
}
|
||||
mnt.propFlags = pflag
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -84,9 +85,8 @@ func (vfs *VirtualFilesystem) setPropagation(mnt *Mount, pflag uint32) error {
|
||||
//
|
||||
// +checklocks:vfs.mountMu
|
||||
func (vfs *VirtualFilesystem) addPeer(mnt *Mount, new *Mount) {
|
||||
mnt.propFlags |= linux.MS_SHARED
|
||||
sharedRingAdd(mnt, new)
|
||||
new.propFlags |= linux.MS_SHARED
|
||||
new.isShared = true
|
||||
new.groupID = mnt.groupID
|
||||
}
|
||||
|
||||
@@ -99,10 +99,10 @@ func (vfs *VirtualFilesystem) addPeer(mnt *Mount, new *Mount) {
|
||||
// +checklocksalias:mnt.vfs.mountMu=vfs.mountMu
|
||||
func (vfs *VirtualFilesystem) preparePropagationTree(mnt *Mount, vd VirtualDentry) map[*Mount]VirtualDentry {
|
||||
tree := map[*Mount]VirtualDentry{}
|
||||
if !vd.mount.shared() {
|
||||
if !vd.mount.isShared {
|
||||
return tree
|
||||
}
|
||||
if !mnt.shared() {
|
||||
if !mnt.isShared {
|
||||
vfs.setPropagation(mnt, linux.MS_SHARED)
|
||||
}
|
||||
for peer := vd.mount.sharedEntry.Next(); peer != vd.mount; peer = peer.sharedEntry.Next() {
|
||||
@@ -184,11 +184,9 @@ func (vfs *VirtualFilesystem) SetMountPropagationAt(ctx context.Context, creds *
|
||||
func (vfs *VirtualFilesystem) SetMountPropagation(mnt *Mount, propFlags uint32) {
|
||||
vfs.mountMu.Lock()
|
||||
defer vfs.mountMu.Unlock()
|
||||
if propFlags != mnt.propFlags {
|
||||
if propFlags&(linux.MS_SHARED|linux.MS_PRIVATE) != 0 {
|
||||
vfs.setPropagation(mnt, propFlags)
|
||||
} else {
|
||||
panic(fmt.Sprintf("unsupported propagation type: %s", propTypeToString(propFlags)))
|
||||
}
|
||||
if propFlags&(linux.MS_SHARED|linux.MS_PRIVATE) != 0 {
|
||||
vfs.setPropagation(mnt, propFlags)
|
||||
} else {
|
||||
panic(fmt.Sprintf("unsupported propagation type: %s", propTypeToString(propFlags)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "test/util/capability_util.h"
|
||||
#include "test/util/file_descriptor.h"
|
||||
#include "test/util/fs_util.h"
|
||||
#include "test/util/linux_capability_util.h"
|
||||
#include "test/util/mount_util.h"
|
||||
#include "test/util/multiprocess_util.h"
|
||||
#include "test/util/posix_error.h"
|
||||
@@ -1443,6 +1444,22 @@ TEST(MountTest, DeadMountsAreDecRefd) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MountTest, UmountSharedBind) {
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
|
||||
std::string home = NewTempAbsPath();
|
||||
ASSERT_NO_ERRNO(Mkdir(home));
|
||||
ASSERT_THAT(chdir(home.c_str()), SyscallSucceeds());
|
||||
constexpr char dirpath[] = "./file";
|
||||
|
||||
ASSERT_THAT(mkdir(dirpath, 0), SyscallSucceeds());
|
||||
ASSERT_THAT(mount(dirpath, dirpath, 0, MS_BIND, 0), SyscallSucceeds());
|
||||
ASSERT_THAT(mount(0, dirpath, 0, MS_SHARED, 0), SyscallSucceeds());
|
||||
ASSERT_THAT(mount(dirpath, dirpath, 0, MS_BIND, 0), SyscallSucceeds());
|
||||
ASSERT_THAT(mount(0, dirpath, 0, MS_SHARED, 0), SyscallSucceeds());
|
||||
ASSERT_THAT(umount2(dirpath, MNT_DETACH), SyscallSucceeds());
|
||||
ASSERT_THAT(umount2(dirpath, MNT_DETACH), SyscallSucceeds());
|
||||
}
|
||||
|
||||
TEST(MountTest, MountNamespace) {
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user