diff options
-rw-r--r-- | pkg/sentry/fsimpl/mqfs/BUILD | 1 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/mqfs/mqfs.go | 61 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/mqfs/registry.go | 34 | ||||
-rw-r--r-- | pkg/sentry/kernel/BUILD | 1 | ||||
-rw-r--r-- | pkg/sentry/kernel/ipc_namespace.go | 21 | ||||
-rw-r--r-- | pkg/sentry/kernel/mq/mq.go | 5 |
6 files changed, 96 insertions, 27 deletions
diff --git a/pkg/sentry/fsimpl/mqfs/BUILD b/pkg/sentry/fsimpl/mqfs/BUILD index 6892c6c25..e688b9b48 100644 --- a/pkg/sentry/fsimpl/mqfs/BUILD +++ b/pkg/sentry/fsimpl/mqfs/BUILD @@ -31,6 +31,7 @@ go_library( "//pkg/refsvfs2", "//pkg/sentry/fsimpl/kernfs", "//pkg/sentry/kernel/auth", + "//pkg/sentry/kernel/ipc", "//pkg/sentry/kernel/mq", "//pkg/sentry/vfs", "//pkg/sync", diff --git a/pkg/sentry/fsimpl/mqfs/mqfs.go b/pkg/sentry/fsimpl/mqfs/mqfs.go index a92012deb..ed559cd13 100644 --- a/pkg/sentry/fsimpl/mqfs/mqfs.go +++ b/pkg/sentry/fsimpl/mqfs/mqfs.go @@ -24,6 +24,8 @@ import ( "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs" "gvisor.dev/gvisor/pkg/sentry/kernel/auth" + "gvisor.dev/gvisor/pkg/sentry/kernel/ipc" + "gvisor.dev/gvisor/pkg/sentry/kernel/mq" "gvisor.dev/gvisor/pkg/sentry/vfs" ) @@ -47,28 +49,32 @@ func (FilesystemType) Release(ctx context.Context) {} // GetFilesystem implements vfs.FilesystemType.GetFilesystem. func (ft FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) { - devMinor, err := vfsObj.GetAnonBlockDevMinor() - if err != nil { - return nil, nil, err + // mqfs is initialized only once per ipc namespace. Each ipc namespace has + // a POSIX message registry with a root dentry, filesystem, and a + // disconnected mount. We want the fs to be consistent for all processes in + // the same ipc namespace, so instead of creating a new fs and root dentry, + // we retreive them using IPCNamespace.PosixQueues and use them. + + i := ipcNamespaceFromContext(ctx) + if i == nil { + return nil, nil, fmt.Errorf("mqfs.FilesystemType.GetFilesystem: ipc namespace doesn't exist") + } + defer i.DecRef(ctx) + + registry := i.PosixQueues() + if registry == nil { + return nil, nil, fmt.Errorf("mqfs.FilesystemType.GetFilesystem: ipc namespace doesn't have a POSIX registry") } + impl := registry.Impl().(*RegistryImpl) maxCachedDentries, err := maxCachedDentries(ctx, vfs.GenericParseMountOptions(opts.Data)) if err != nil { return nil, nil, err } + impl.fs.MaxCachedDentries = maxCachedDentries - fs := &filesystem{ - devMinor: devMinor, - Filesystem: kernfs.Filesystem{ - MaxCachedDentries: maxCachedDentries, - }, - } - fs.VFSFilesystem().Init(vfsObj, &ft, fs) - - var dentry kernfs.Dentry - dentry.InitRoot(&fs.Filesystem, fs.newRootInode(ctx, creds)) - - return fs.VFSFilesystem(), dentry.VFSDentry(), nil + impl.root.IncRef() + return impl.fs.VFSFilesystem(), impl.root.VFSDentry(), nil } // maxCachedDentries checks mopts for dentry_cache_limit. If a value is @@ -93,15 +99,40 @@ 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. func (fs *filesystem) Release(ctx context.Context) { fs.Filesystem.VFSFilesystem().VirtualFilesystem().PutAnonBlockDevMinor(fs.devMinor) fs.Filesystem.Release(ctx) + fs.root.DecRef(ctx) } // MountOptions implements vfs.FilesystemImpl.MountOptions. func (fs *filesystem) MountOptions() string { return fmt.Sprintf("dentry_cache_limit=%d", fs.MaxCachedDentries) } + +// ipcNamespace defines functions we need from kernel.IPCNamespace. We redefine +// ipcNamespace along with ipcNamespaceFromContext to avoid circular dependency +// with package sentry/kernel. +type ipcNamespace interface { + // PosixQueues returns a POSIX message queue registry. + PosixQueues() *mq.Registry + + // DecRef decrements ipcNamespace's number of references. + DecRef(ctx context.Context) +} + +// ipcNamespaceFromContext returns the IPC namespace in which ctx is executing. +// Copied from package sentry/kernel. +func ipcNamespaceFromContext(ctx context.Context) ipcNamespace { + if v := ctx.Value(ipc.CtxIPCNamespace); v != nil { + return v.(ipcNamespace) + } + return nil +} diff --git a/pkg/sentry/fsimpl/mqfs/registry.go b/pkg/sentry/fsimpl/mqfs/registry.go index 3875b39ee..9361b7eb4 100644 --- a/pkg/sentry/fsimpl/mqfs/registry.go +++ b/pkg/sentry/fsimpl/mqfs/registry.go @@ -50,12 +50,32 @@ type RegistryImpl struct { // NewRegistryImpl returns a new, initialized RegistryImpl, and takes a // reference on root. -func NewRegistryImpl(root *kernfs.Dentry, fs *filesystem) *RegistryImpl { - root.IncRef() - return &RegistryImpl{ - root: root, - fs: fs, +func NewRegistryImpl(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials) (*RegistryImpl, error) { + devMinor, err := vfsObj.GetAnonBlockDevMinor() + if err != nil { + return nil, err + } + + var dentry kernfs.Dentry + fs := &filesystem{ + devMinor: devMinor, + root: &dentry, + } + fs.VFSFilesystem().Init(vfsObj, &FilesystemType{}, fs) + + dentry.InitRoot(&fs.Filesystem, fs.newRootInode(ctx, creds)) + dentry.IncRef() + + mount, err := vfsObj.NewDisconnectedMount(fs.VFSFilesystem(), dentry.VFSDentry(), &vfs.MountOptions{}) + if err != nil { + return nil, err } + + return &RegistryImpl{ + root: &dentry, + fs: fs, + mount: mount, + }, nil } // Lookup implements mq.RegistryImpl.Lookup. @@ -83,11 +103,11 @@ func (r *RegistryImpl) New(ctx context.Context, name string, q *mq.Queue, perm l } fd := &queueFD{queue: q} - err = fd.Init(r.mount, r.root, qInode.data, &qInode.locks, 0 /* flags */) + err = fd.Init(r.mount, r.root, q, qInode.Locks(), 0 /* flags */) if err != nil { return nil, err } - return fd.VFSFileDescription(), nil + return &fd.vfsfd, nil } // Unlink implements mq.RegistryImpl.Unlink. diff --git a/pkg/sentry/kernel/BUILD b/pkg/sentry/kernel/BUILD index 6ff3deb97..9f30a7706 100644 --- a/pkg/sentry/kernel/BUILD +++ b/pkg/sentry/kernel/BUILD @@ -249,6 +249,7 @@ go_library( "//pkg/sentry/fs/timerfd", "//pkg/sentry/fsbridge", "//pkg/sentry/fsimpl/kernfs", + "//pkg/sentry/fsimpl/mqfs", "//pkg/sentry/fsimpl/pipefs", "//pkg/sentry/fsimpl/sockfs", "//pkg/sentry/fsimpl/timerfd", diff --git a/pkg/sentry/kernel/ipc_namespace.go b/pkg/sentry/kernel/ipc_namespace.go index aa9c3fb31..11b4545c6 100644 --- a/pkg/sentry/kernel/ipc_namespace.go +++ b/pkg/sentry/kernel/ipc_namespace.go @@ -15,12 +15,16 @@ package kernel import ( + "fmt" + "gvisor.dev/gvisor/pkg/context" + "gvisor.dev/gvisor/pkg/sentry/fsimpl/mqfs" "gvisor.dev/gvisor/pkg/sentry/kernel/auth" "gvisor.dev/gvisor/pkg/sentry/kernel/mq" "gvisor.dev/gvisor/pkg/sentry/kernel/msgqueue" "gvisor.dev/gvisor/pkg/sentry/kernel/semaphore" "gvisor.dev/gvisor/pkg/sentry/kernel/shm" + "gvisor.dev/gvisor/pkg/sentry/vfs" ) // IPCNamespace represents an IPC namespace. @@ -72,12 +76,19 @@ func (i *IPCNamespace) ShmRegistry() *shm.Registry { return i.shms } -// SetPosixQueues sets value of posixQueues if the value is currently nil, -// otherwise returns without doing anything. -func (i *IPCNamespace) SetPosixQueues(r *mq.Registry) { - if i.posixQueues == nil { - i.posixQueues = r +// InitPosixQueues creates a new POSIX queue registry, and returns an error if +// the registry was previously initialized. +func (i *IPCNamespace) InitPosixQueues(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials) error { + if i.posixQueues != nil { + return fmt.Errorf("IPCNamespace.InitPosixQueues: already initialized") + } + + impl, err := mqfs.NewRegistryImpl(ctx, vfsObj, creds) + if err != nil { + return err } + i.posixQueues = mq.NewRegistry(impl) + return nil } // PosixQueues returns the posix message queue registry for this namespace. diff --git a/pkg/sentry/kernel/mq/mq.go b/pkg/sentry/kernel/mq/mq.go index be46f78c8..739ea2f1c 100644 --- a/pkg/sentry/kernel/mq/mq.go +++ b/pkg/sentry/kernel/mq/mq.go @@ -79,6 +79,11 @@ func (r *Registry) Destroy(ctx context.Context) { r.impl.Destroy(ctx) } +// Impl returns RegistryImpl inside r. +func (r *Registry) Impl() RegistryImpl { + return r.impl +} + // Queue represents a POSIX message queue. // // +stateify savable |