diff options
Diffstat (limited to 'pkg/sentry/fsimpl/devtmpfs')
-rw-r--r-- | pkg/sentry/fsimpl/devtmpfs/BUILD | 33 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/devtmpfs/devtmpfs.go | 191 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/devtmpfs/devtmpfs_test.go | 122 |
3 files changed, 0 insertions, 346 deletions
diff --git a/pkg/sentry/fsimpl/devtmpfs/BUILD b/pkg/sentry/fsimpl/devtmpfs/BUILD deleted file mode 100644 index aa0c2ad8c..000000000 --- a/pkg/sentry/fsimpl/devtmpfs/BUILD +++ /dev/null @@ -1,33 +0,0 @@ -load("//tools:defs.bzl", "go_library", "go_test") - -licenses(["notice"]) - -go_library( - name = "devtmpfs", - srcs = ["devtmpfs.go"], - visibility = ["//pkg/sentry:internal"], - deps = [ - "//pkg/abi/linux", - "//pkg/context", - "//pkg/fspath", - "//pkg/sentry/fsimpl/tmpfs", - "//pkg/sentry/kernel/auth", - "//pkg/sentry/vfs", - "//pkg/sync", - ], -) - -go_test( - name = "devtmpfs_test", - size = "small", - srcs = ["devtmpfs_test.go"], - library = ":devtmpfs", - deps = [ - "//pkg/abi/linux", - "//pkg/fspath", - "//pkg/sentry/contexttest", - "//pkg/sentry/fsimpl/tmpfs", - "//pkg/sentry/kernel/auth", - "//pkg/sentry/vfs", - ], -) diff --git a/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go b/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go deleted file mode 100644 index abd4f24e7..000000000 --- a/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go +++ /dev/null @@ -1,191 +0,0 @@ -// 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 devtmpfs provides an implementation of /dev based on tmpfs, -// analogous to Linux's devtmpfs. -package devtmpfs - -import ( - "fmt" - - "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/context" - "gvisor.dev/gvisor/pkg/fspath" - "gvisor.dev/gvisor/pkg/sentry/fsimpl/tmpfs" - "gvisor.dev/gvisor/pkg/sentry/kernel/auth" - "gvisor.dev/gvisor/pkg/sentry/vfs" - "gvisor.dev/gvisor/pkg/sync" -) - -// Name is the default filesystem name. -const Name = "devtmpfs" - -// FilesystemType implements vfs.FilesystemType. -type FilesystemType struct { - initOnce sync.Once - initErr error - - // fs is the tmpfs filesystem that backs all mounts of this FilesystemType. - // root is fs' root. fs and root are immutable. - fs *vfs.Filesystem - root *vfs.Dentry -} - -// GetFilesystem implements vfs.FilesystemType.GetFilesystem. -func (fst *FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) { - fst.initOnce.Do(func() { - fs, root, err := tmpfs.FilesystemType{}.GetFilesystem(ctx, vfsObj, creds, "" /* source */, vfs.GetFilesystemOptions{ - Data: "mode=0755", // opts from drivers/base/devtmpfs.c:devtmpfs_init() - }) - if err != nil { - fst.initErr = err - return - } - fst.fs = fs - fst.root = root - }) - if fst.initErr != nil { - return nil, nil, fst.initErr - } - fst.fs.IncRef() - fst.root.IncRef() - return fst.fs, fst.root, nil -} - -// Accessor allows devices to create device special files in devtmpfs. -type Accessor struct { - vfsObj *vfs.VirtualFilesystem - mntns *vfs.MountNamespace - root vfs.VirtualDentry - creds *auth.Credentials -} - -// NewAccessor returns an Accessor that supports creation of device special -// files in the devtmpfs instance registered with name fsTypeName in vfsObj. -func NewAccessor(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, fsTypeName string) (*Accessor, error) { - mntns, err := vfsObj.NewMountNamespace(ctx, creds, "devtmpfs" /* source */, fsTypeName, &vfs.GetFilesystemOptions{}) - if err != nil { - return nil, err - } - return &Accessor{ - vfsObj: vfsObj, - mntns: mntns, - root: mntns.Root(), - creds: creds, - }, nil -} - -// Release must be called when a is no longer in use. -func (a *Accessor) Release() { - a.root.DecRef() - a.mntns.DecRef() -} - -// accessorContext implements context.Context by extending an existing -// context.Context with an Accessor's values for VFS-relevant state. -type accessorContext struct { - context.Context - a *Accessor -} - -func (a *Accessor) wrapContext(ctx context.Context) *accessorContext { - return &accessorContext{ - Context: ctx, - a: a, - } -} - -// Value implements context.Context.Value. -func (ac *accessorContext) Value(key interface{}) interface{} { - switch key { - case vfs.CtxMountNamespace: - ac.a.mntns.IncRef() - return ac.a.mntns - case vfs.CtxRoot: - ac.a.root.IncRef() - return ac.a.root - default: - return ac.Context.Value(key) - } -} - -func (a *Accessor) pathOperationAt(pathname string) *vfs.PathOperation { - return &vfs.PathOperation{ - Root: a.root, - Start: a.root, - Path: fspath.Parse(pathname), - } -} - -// CreateDeviceFile creates a device special file at the given pathname in the -// devtmpfs instance accessed by the Accessor. -func (a *Accessor) CreateDeviceFile(ctx context.Context, pathname string, kind vfs.DeviceKind, major, minor uint32, perms uint16) error { - mode := (linux.FileMode)(perms) - switch kind { - case vfs.BlockDevice: - mode |= linux.S_IFBLK - case vfs.CharDevice: - mode |= linux.S_IFCHR - default: - panic(fmt.Sprintf("invalid vfs.DeviceKind: %v", kind)) - } - // NOTE: Linux's devtmpfs refuses to automatically delete files it didn't - // create, which it recognizes by storing a pointer to the kdevtmpfs struct - // thread in struct inode::i_private. Accessor doesn't yet support deletion - // of files at all, and probably won't as long as we don't need to support - // kernel modules, so this is moot for now. - return a.vfsObj.MknodAt(a.wrapContext(ctx), a.creds, a.pathOperationAt(pathname), &vfs.MknodOptions{ - Mode: mode, - DevMajor: major, - DevMinor: minor, - }) -} - -// UserspaceInit creates symbolic links and mount points in the devtmpfs -// instance accessed by the Accessor that are created by userspace in Linux. It -// does not create mounts. -func (a *Accessor) UserspaceInit(ctx context.Context) error { - actx := a.wrapContext(ctx) - - // systemd: src/shared/dev-setup.c:dev_setup() - for _, symlink := range []struct { - source string - target string - }{ - // /proc/kcore is not implemented. - {source: "fd", target: "/proc/self/fd"}, - {source: "stdin", target: "/proc/self/fd/0"}, - {source: "stdout", target: "/proc/self/fd/1"}, - {source: "stderr", target: "/proc/self/fd/2"}, - } { - if err := a.vfsObj.SymlinkAt(actx, a.creds, a.pathOperationAt(symlink.source), symlink.target); err != nil { - return fmt.Errorf("failed to create symlink %q => %q: %v", symlink.source, symlink.target, err) - } - } - - // systemd: src/core/mount-setup.c:mount_table - for _, dir := range []string{ - "shm", - "pts", - } { - if err := a.vfsObj.MkdirAt(actx, a.creds, a.pathOperationAt(dir), &vfs.MkdirOptions{ - // systemd: src/core/mount-setup.c:mount_one() - Mode: 0755, - }); err != nil { - return fmt.Errorf("failed to create directory %q: %v", dir, err) - } - } - - return nil -} diff --git a/pkg/sentry/fsimpl/devtmpfs/devtmpfs_test.go b/pkg/sentry/fsimpl/devtmpfs/devtmpfs_test.go deleted file mode 100644 index b6d52c015..000000000 --- a/pkg/sentry/fsimpl/devtmpfs/devtmpfs_test.go +++ /dev/null @@ -1,122 +0,0 @@ -// 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 devtmpfs - -import ( - "testing" - - "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/fspath" - "gvisor.dev/gvisor/pkg/sentry/contexttest" - "gvisor.dev/gvisor/pkg/sentry/fsimpl/tmpfs" - "gvisor.dev/gvisor/pkg/sentry/kernel/auth" - "gvisor.dev/gvisor/pkg/sentry/vfs" -) - -func TestDevtmpfs(t *testing.T) { - ctx := contexttest.Context(t) - creds := auth.CredentialsFromContext(ctx) - - vfsObj := &vfs.VirtualFilesystem{} - if err := vfsObj.Init(); err != nil { - t.Fatalf("VFS init: %v", err) - } - // Register tmpfs just so that we can have a root filesystem that isn't - // devtmpfs. - vfsObj.MustRegisterFilesystemType("tmpfs", tmpfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{ - AllowUserMount: true, - }) - vfsObj.MustRegisterFilesystemType("devtmpfs", &FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{ - AllowUserMount: true, - }) - - // Create a test mount namespace with devtmpfs mounted at "/dev". - const devPath = "/dev" - mntns, err := vfsObj.NewMountNamespace(ctx, creds, "tmpfs" /* source */, "tmpfs" /* fsTypeName */, &vfs.GetFilesystemOptions{}) - if err != nil { - t.Fatalf("failed to create tmpfs root mount: %v", err) - } - defer mntns.DecRef() - root := mntns.Root() - defer root.DecRef() - devpop := vfs.PathOperation{ - Root: root, - Start: root, - Path: fspath.Parse(devPath), - } - if err := vfsObj.MkdirAt(ctx, creds, &devpop, &vfs.MkdirOptions{ - Mode: 0755, - }); err != nil { - t.Fatalf("failed to create mount point: %v", err) - } - if err := vfsObj.MountAt(ctx, creds, "devtmpfs" /* source */, &devpop, "devtmpfs" /* fsTypeName */, &vfs.MountOptions{}); err != nil { - t.Fatalf("failed to mount devtmpfs: %v", err) - } - - a, err := NewAccessor(ctx, vfsObj, creds, "devtmpfs") - if err != nil { - t.Fatalf("failed to create devtmpfs.Accessor: %v", err) - } - defer a.Release() - - // Create "userspace-initialized" files using a devtmpfs.Accessor. - if err := a.UserspaceInit(ctx); err != nil { - t.Fatalf("failed to userspace-initialize devtmpfs: %v", err) - } - // Created files should be visible in the test mount namespace. - abspath := devPath + "/fd" - target, err := vfsObj.ReadlinkAt(ctx, creds, &vfs.PathOperation{ - Root: root, - Start: root, - Path: fspath.Parse(abspath), - }) - if want := "/proc/self/fd"; err != nil || target != want { - t.Fatalf("readlink(%q): got (%q, %v), wanted (%q, nil)", abspath, target, err, want) - } - - // Create a dummy device special file using a devtmpfs.Accessor. - const ( - pathInDev = "dummy" - kind = vfs.CharDevice - major = 12 - minor = 34 - perms = 0600 - wantMode = linux.S_IFCHR | perms - ) - if err := a.CreateDeviceFile(ctx, pathInDev, kind, major, minor, perms); err != nil { - t.Fatalf("failed to create device file: %v", err) - } - // The device special file should be visible in the test mount namespace. - abspath = devPath + "/" + pathInDev - stat, err := vfsObj.StatAt(ctx, creds, &vfs.PathOperation{ - Root: root, - Start: root, - Path: fspath.Parse(abspath), - }, &vfs.StatOptions{ - Mask: linux.STATX_TYPE | linux.STATX_MODE, - }) - if err != nil { - t.Fatalf("failed to stat device file at %q: %v", abspath, err) - } - if stat.Mode != wantMode { - t.Errorf("device file mode: got %v, wanted %v", stat.Mode, wantMode) - } - if stat.RdevMajor != major { - t.Errorf("major device number: got %v, wanted %v", stat.RdevMajor, major) - } - if stat.RdevMinor != minor { - t.Errorf("minor device number: got %v, wanted %v", stat.RdevMinor, minor) - } -} |