diff --git a/pkg/sentry/fsimpl/devtmpfs/BUILD b/pkg/sentry/fsimpl/devtmpfs/BUILD new file mode 100644 index 000000000..886ae937f --- /dev/null +++ b/pkg/sentry/fsimpl/devtmpfs/BUILD @@ -0,0 +1,21 @@ +load("//tools:defs.bzl", "go_library") + +package(default_applicable_licenses = ["//:license"]) + +licenses(["notice"]) + +go_library( + name = "devtmpfs", + srcs = [ + "devtmpfs.go", + "save_restore.go", + ], + visibility = ["//pkg/sentry:internal"], + deps = [ + "//pkg/context", + "//pkg/sentry/fsimpl/dev", + "//pkg/sentry/kernel/auth", + "//pkg/sentry/vfs", + "//pkg/sync", + ], +) diff --git a/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go b/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go new file mode 100644 index 000000000..e1ab3cfee --- /dev/null +++ b/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go @@ -0,0 +1,74 @@ +// 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 a singleton fsimpl/dev filesystem instance, +// analogous to Linux's devtmpfs. +package devtmpfs + +import ( + "gvisor.dev/gvisor/pkg/context" + "gvisor.dev/gvisor/pkg/sentry/fsimpl/dev" + "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. +// +// +stateify savable +type FilesystemType struct { + initOnce sync.Once `state:"nosave"` + 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 +} + +// Name implements vfs.FilesystemType.Name. +func (*FilesystemType) Name() string { + return Name +} + +// 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 := dev.FilesystemType{}.GetFilesystem(ctx, vfsObj, creds, source, opts) + 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 +} + +// Release implements vfs.FilesystemType.Release. +func (fst *FilesystemType) Release(ctx context.Context) { + if fst.fs != nil { + // Release the original reference obtained when creating the filesystem. + fst.root.DecRef(ctx) + fst.fs.DecRef(ctx) + } +} diff --git a/pkg/sentry/fsimpl/devtmpfs/save_restore.go b/pkg/sentry/fsimpl/devtmpfs/save_restore.go new file mode 100644 index 000000000..28832d850 --- /dev/null +++ b/pkg/sentry/fsimpl/devtmpfs/save_restore.go @@ -0,0 +1,23 @@ +// 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 + +// afterLoad is invoked by stateify. +func (fst *FilesystemType) afterLoad() { + if fst.fs != nil { + // Ensure that we don't create another filesystem. + fst.initOnce.Do(func() {}) + } +} diff --git a/runsc/boot/BUILD b/runsc/boot/BUILD index 8f905d461..8a2d1aa6c 100644 --- a/runsc/boot/BUILD +++ b/runsc/boot/BUILD @@ -64,6 +64,7 @@ go_library( "//pkg/sentry/fsimpl/cgroupfs", "//pkg/sentry/fsimpl/dev", "//pkg/sentry/fsimpl/devpts", + "//pkg/sentry/fsimpl/devtmpfs", "//pkg/sentry/fsimpl/erofs", "//pkg/sentry/fsimpl/fuse", "//pkg/sentry/fsimpl/gofer", diff --git a/runsc/boot/vfs.go b/runsc/boot/vfs.go index 7a0e9a508..f00767854 100644 --- a/runsc/boot/vfs.go +++ b/runsc/boot/vfs.go @@ -44,6 +44,7 @@ import ( "gvisor.dev/gvisor/pkg/sentry/fsimpl/cgroupfs" "gvisor.dev/gvisor/pkg/sentry/fsimpl/dev" "gvisor.dev/gvisor/pkg/sentry/fsimpl/devpts" + "gvisor.dev/gvisor/pkg/sentry/fsimpl/devtmpfs" "gvisor.dev/gvisor/pkg/sentry/fsimpl/erofs" "gvisor.dev/gvisor/pkg/sentry/fsimpl/fuse" "gvisor.dev/gvisor/pkg/sentry/fsimpl/gofer" @@ -108,6 +109,10 @@ func registerFilesystems(k *kernel.Kernel, info *containerInfo) error { AllowUserMount: true, }) vfsObj.MustRegisterFilesystemType(dev.Name, &dev.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{}) + vfsObj.MustRegisterFilesystemType(devtmpfs.Name, &devtmpfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{ + AllowUserMount: true, + AllowUserList: true, + }) vfsObj.MustRegisterFilesystemType(erofs.Name, &erofs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{ AllowUserList: true, })