Add socket filesystem and global disconnected socket mount for VFS2.
A socket mount where anonymous sockets will reside is added to the VirtualFilesystem. Socketfs is built on top of kernfs. Updates #1476, #1478, #1484, #1485. PiperOrigin-RevId: 304095251
This commit is contained in:
parent
57e67e32b5
commit
639d94f9f7
|
@ -0,0 +1,16 @@
|
|||
load("//tools:defs.bzl", "go_library")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
go_library(
|
||||
name = "sockfs",
|
||||
srcs = ["sockfs.go"],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
"//pkg/context",
|
||||
"//pkg/sentry/fsimpl/kernfs",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/syserror",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package sockfs provides a filesystem implementation for anonymous sockets.
|
||||
package sockfs
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
)
|
||||
|
||||
// NewFilesystem creates a new sockfs filesystem.
|
||||
//
|
||||
// Note that there should only ever be one instance of sockfs.Filesystem,
|
||||
// backing a global socket mount.
|
||||
func NewFilesystem(vfsObj *vfs.VirtualFilesystem) *vfs.Filesystem {
|
||||
fs, _, err := filesystemType{}.GetFilesystem(nil, vfsObj, nil, "", vfs.GetFilesystemOptions{})
|
||||
if err != nil {
|
||||
panic("failed to create sockfs filesystem")
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
// filesystemType implements vfs.FilesystemType.
|
||||
type filesystemType struct{}
|
||||
|
||||
// GetFilesystem implements FilesystemType.GetFilesystem.
|
||||
func (fsType filesystemType) GetFilesystem(_ context.Context, vfsObj *vfs.VirtualFilesystem, _ *auth.Credentials, _ string, _ vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
|
||||
fs := &filesystem{}
|
||||
fs.Init(vfsObj, fsType)
|
||||
return fs.VFSFilesystem(), nil, nil
|
||||
}
|
||||
|
||||
// Name implements FilesystemType.Name.
|
||||
//
|
||||
// Note that registering sockfs is unnecessary, except for the fact that it
|
||||
// will not show up under /proc/filesystems as a result. This is a very minor
|
||||
// discrepancy from Linux.
|
||||
func (filesystemType) Name() string {
|
||||
return "sockfs"
|
||||
}
|
||||
|
||||
// filesystem implements vfs.FilesystemImpl.
|
||||
type filesystem struct {
|
||||
kernfs.Filesystem
|
||||
}
|
||||
|
||||
// inode implements kernfs.Inode.
|
||||
type inode struct {
|
||||
kernfs.InodeNotDirectory
|
||||
kernfs.InodeNotSymlink
|
||||
kernfs.InodeAttrs
|
||||
kernfs.InodeNoopRefCount
|
||||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *inode) Open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
return nil, syserror.ENXIO
|
||||
}
|
|
@ -169,6 +169,7 @@ go_library(
|
|||
"//pkg/sentry/fs/lock",
|
||||
"//pkg/sentry/fs/timerfd",
|
||||
"//pkg/sentry/fsbridge",
|
||||
"//pkg/sentry/fsimpl/sockfs",
|
||||
"//pkg/sentry/hostcpu",
|
||||
"//pkg/sentry/inet",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
|
|
|
@ -50,6 +50,7 @@ import (
|
|||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/timerfd"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/sockfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/hostcpu"
|
||||
"gvisor.dev/gvisor/pkg/sentry/inet"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
|
@ -225,6 +226,11 @@ type Kernel struct {
|
|||
// by extMu.
|
||||
nextSocketEntry uint64
|
||||
|
||||
// socketMount is a disconnected vfs.Mount, not included in k.vfs,
|
||||
// representing a sockfs.filesystem. socketMount is used to back
|
||||
// VirtualDentries representing anonymous sockets.
|
||||
socketMount *vfs.Mount
|
||||
|
||||
// deviceRegistry is used to save/restore device.SimpleDevices.
|
||||
deviceRegistry struct{} `state:".(*device.Registry)"`
|
||||
|
||||
|
@ -348,6 +354,19 @@ func (k *Kernel) Init(args InitKernelArgs) error {
|
|||
k.monotonicClock = &timekeeperClock{tk: args.Timekeeper, c: sentrytime.Monotonic}
|
||||
k.futexes = futex.NewManager()
|
||||
k.netlinkPorts = port.New()
|
||||
if VFS2Enabled {
|
||||
if err := k.vfs.Init(); err != nil {
|
||||
return fmt.Errorf("failed to initialize VFS: %v", err)
|
||||
}
|
||||
fs := sockfs.NewFilesystem(&k.vfs)
|
||||
// NewDisconnectedMount will take an additional reference on fs.
|
||||
defer fs.DecRef()
|
||||
sm, err := k.vfs.NewDisconnectedMount(fs, nil, &vfs.MountOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize socket mount: %v", err)
|
||||
}
|
||||
k.socketMount = sm
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1452,6 +1471,11 @@ func (k *Kernel) ListSockets() []*SocketEntry {
|
|||
return socks
|
||||
}
|
||||
|
||||
// SocketMount returns the global socket mount.
|
||||
func (k *Kernel) SocketMount() *vfs.Mount {
|
||||
return k.socketMount
|
||||
}
|
||||
|
||||
// supervisorContext is a privileged context.
|
||||
type supervisorContext struct {
|
||||
context.NoopSleeper
|
||||
|
|
|
@ -257,6 +257,8 @@ TEST_P(UnixSocketPairTest, ShutdownWrite) {
|
|||
|
||||
TEST_P(UnixSocketPairTest, SocketReopenFromProcfs) {
|
||||
// TODO(b/122310852): We should be returning ENXIO and NOT EIO.
|
||||
// TODO(github.dev/issue/1624): This should be resolved in VFS2. Verify
|
||||
// that this is the case and delete the SKIP_IF once we delete VFS1.
|
||||
SKIP_IF(IsRunningOnGvisor());
|
||||
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
|
||||
|
||||
|
|
Loading…
Reference in New Issue