summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyush Ranjan <ayushranjan@google.com>2021-10-26 11:56:09 -0700
committergVisor bot <gvisor-bot@google.com>2021-10-26 11:59:21 -0700
commit763d7e6e396d8d4c67d650e02bd2350b22606ada (patch)
tree690226ef6653e159c485e0cf374560db9952be77
parent8b2e8caad400fd3e7d3e4e235d26dd2d556bf65c (diff)
Obtain ref on root dentry in mqfs.GetFilesystem.
As documented in FilesystemType.GetFilesystem, a reference should be taken on the returned dentry and filesystem by GetFilesystem implementation. mqfs did not do that. Additionally cleanup and clarify ref counting of dentry, filesystem and mount in mqfs. Reported-by: syzbot+a2c54bfb6e1525228e5f@syzkaller.appspotmail.com Reported-by: syzbot+ccd305cdab11cfebbfff@syzkaller.appspotmail.com PiperOrigin-RevId: 405700565
-rw-r--r--pkg/sentry/fsimpl/mqfs/mqfs.go5
-rw-r--r--pkg/sentry/fsimpl/mqfs/registry.go23
-rw-r--r--pkg/sentry/fsimpl/mqfs/root.go9
-rw-r--r--pkg/sentry/vfs/filesystem_type.go2
-rw-r--r--test/syscalls/linux/BUILD1
-rw-r--r--test/syscalls/linux/mq.cc22
6 files changed, 27 insertions, 35 deletions
diff --git a/pkg/sentry/fsimpl/mqfs/mqfs.go b/pkg/sentry/fsimpl/mqfs/mqfs.go
index c2b53c9d0..9b3704217 100644
--- a/pkg/sentry/fsimpl/mqfs/mqfs.go
+++ b/pkg/sentry/fsimpl/mqfs/mqfs.go
@@ -75,6 +75,7 @@ func (ft FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualF
impl.fs.MaxCachedDentries = maxCachedDentries
impl.fs.VFSFilesystem().IncRef()
+ impl.root.IncRef()
return impl.fs.VFSFilesystem(), impl.root.VFSDentry(), nil
}
@@ -100,10 +101,6 @@ func maxCachedDentries(ctx context.Context, mopts map[string]string) (_ uint64,
type filesystem struct {
kernfs.Filesystem
devMinor uint32
-
- // root is the filesystem's root dentry. Since we take a reference on it in
- // GetFilesystem, we should release it when the fs is released.
- root *kernfs.Dentry
}
// Release implements vfs.FilesystemImpl.Release.
diff --git a/pkg/sentry/fsimpl/mqfs/registry.go b/pkg/sentry/fsimpl/mqfs/registry.go
index c8fbe4d33..e470ffadc 100644
--- a/pkg/sentry/fsimpl/mqfs/registry.go
+++ b/pkg/sentry/fsimpl/mqfs/registry.go
@@ -57,16 +57,19 @@ func NewRegistryImpl(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *
return nil, err
}
- var dentry kernfs.Dentry
fs := &filesystem{
devMinor: devMinor,
- root: &dentry,
}
fs.VFSFilesystem().Init(vfsObj, &FilesystemType{}, fs)
vfsfs := fs.VFSFilesystem()
+ // NewDisconnectedMount will obtain a ref on dentry and vfsfs which is
+ // transferred to mount. vfsfs was initiated with 1 ref already. So get rid
+ // of the extra ref.
+ defer vfsfs.DecRef(ctx)
+ // dentry is initialized with 1 ref which is transferred to fs.
+ var dentry kernfs.Dentry
dentry.InitRoot(&fs.Filesystem, fs.newRootInode(ctx, creds))
- defer vfsfs.DecRef(ctx) // NewDisconnectedMount will obtain a ref on success.
mount, err := vfsObj.NewDisconnectedMount(vfsfs, dentry.VFSDentry(), &vfs.MountOptions{})
if err != nil {
@@ -82,7 +85,7 @@ func NewRegistryImpl(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *
// Get implements mq.RegistryImpl.Get.
func (r *RegistryImpl) Get(ctx context.Context, name string, access mq.AccessType, block bool, flags uint32) (*vfs.FileDescription, bool, error) {
- inode, err := r.lookup(ctx, name)
+ inode, err := r.root.Inode().(*rootInode).Lookup(ctx, name)
if err != nil {
return nil, false, nil
}
@@ -120,7 +123,7 @@ func (r *RegistryImpl) Unlink(ctx context.Context, name string) error {
}
root := r.root.Inode().(*rootInode)
- inode, err := r.lookup(ctx, name)
+ inode, err := root.Lookup(ctx, name)
if err != nil {
return err
}
@@ -133,16 +136,6 @@ func (r *RegistryImpl) Destroy(ctx context.Context) {
r.mount.DecRef(ctx)
}
-// lookup retreives a kernfs.Inode using a name.
-func (r *RegistryImpl) lookup(ctx context.Context, name string) (kernfs.Inode, error) {
- inode := r.root.Inode().(*rootInode)
- lookup, err := inode.Lookup(ctx, name)
- if err != nil {
- return nil, err
- }
- return lookup, nil
-}
-
// newFD returns a new file description created using the given queue and inode.
func (r *RegistryImpl) newFD(q *mq.Queue, inode *queueInode, access mq.AccessType, block bool, flags uint32) (*vfs.FileDescription, error) {
view, err := mq.NewView(q, access, block)
diff --git a/pkg/sentry/fsimpl/mqfs/root.go b/pkg/sentry/fsimpl/mqfs/root.go
index 37b5749fb..922e669e2 100644
--- a/pkg/sentry/fsimpl/mqfs/root.go
+++ b/pkg/sentry/fsimpl/mqfs/root.go
@@ -34,7 +34,6 @@ type rootInode struct {
kernfs.InodeNotSymlink
kernfs.InodeTemporary
kernfs.OrderedChildren
- implStatFS
locks vfs.FileLocks
}
@@ -77,13 +76,7 @@ func (*rootInode) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, v
return linuxerr.EPERM
}
-// implStatFS provides an implementation of kernfs.Inode.StatFS for message
-// queues to be embedded in inodes.
-//
-// +stateify savable
-type implStatFS struct{}
-
// StatFS implements kernfs.Inode.StatFS.
-func (*implStatFS) StatFS(context.Context, *vfs.Filesystem) (linux.Statfs, error) {
+func (*rootInode) StatFS(context.Context, *vfs.Filesystem) (linux.Statfs, error) {
return vfs.GenericStatFS(linux.MQUEUE_MAGIC), nil
}
diff --git a/pkg/sentry/vfs/filesystem_type.go b/pkg/sentry/vfs/filesystem_type.go
index 9d54cc4ed..70d6eb85e 100644
--- a/pkg/sentry/vfs/filesystem_type.go
+++ b/pkg/sentry/vfs/filesystem_type.go
@@ -28,7 +28,7 @@ import (
type FilesystemType interface {
// GetFilesystem returns a Filesystem configured by the given options,
// along with its mount root. A reference is taken on the returned
- // Filesystem and Dentry.
+ // Filesystem and Dentry whose ownership is transferred to the caller.
GetFilesystem(ctx context.Context, vfsObj *VirtualFilesystem, creds *auth.Credentials, source string, opts GetFilesystemOptions) (*Filesystem, *Dentry, error)
// Name returns the name of this FilesystemType.
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index 9d975c614..6217ff4dc 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -4209,6 +4209,7 @@ cc_binary(
linkstatic = 1,
deps = [
"//test/util:capability_util",
+ "//test/util:cleanup",
"//test/util:fs_util",
"//test/util:mount_util",
"//test/util:posix_error",
diff --git a/test/syscalls/linux/mq.cc b/test/syscalls/linux/mq.cc
index 839877a67..013994fd9 100644
--- a/test/syscalls/linux/mq.cc
+++ b/test/syscalls/linux/mq.cc
@@ -22,6 +22,7 @@
#include <string>
#include "test/util/capability_util.h"
+#include "test/util/cleanup.h"
#include "test/util/fs_util.h"
#include "test/util/mount_util.h"
#include "test/util/posix_error.h"
@@ -286,18 +287,25 @@ TEST(MqTest, Mount) {
TEST(MqTest, MountSeveral) {
SKIP_IF(IsRunningWithVFS1() ||
!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
+ constexpr int numMounts = 3;
+ // mountDirs should outlive mountCUs and queue so that its destructor succeeds
+ // in unlinking the mountpoints and does not interfere with queue destruction.
+ testing::TempPath mountDirs[numMounts];
+ testing::Cleanup mountCUs[numMounts];
PosixQueue queue = ASSERT_NO_ERRNO_AND_VALUE(
MqOpen(O_RDWR | O_CREAT | O_EXCL, 0777, nullptr));
- auto const dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
- // Assign the pointer so it doesn't get destroyed before the second mount is
- // created.
- auto mnt =
- ASSERT_NO_ERRNO_AND_VALUE(Mount("none", dir1.path(), "mqueue", 0, "", 0));
+ for (int i = 0; i < numMounts; ++i) {
+ mountDirs[i] = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ mountCUs[i] = ASSERT_NO_ERRNO_AND_VALUE(
+ Mount("none", mountDirs[i].path(), "mqueue", 0, "", 0));
+ }
- auto const dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
- ASSERT_NO_ERRNO(Mount("none", dir2.path(), "mqueue", 0, "", 0));
+ // Ensure that queue is visible from all mounts.
+ for (int i = 0; i < numMounts; ++i) {
+ ASSERT_NO_ERRNO(Stat(JoinPath(mountDirs[i].path(), queue.name())));
+ }
}
// Test mounting mqueue and opening a queue as normal file.