diff options
-rw-r--r-- | pkg/sentry/control/proc.go | 2 | ||||
-rw-r--r-- | pkg/sentry/kernel/kernel.go | 9 | ||||
-rwxr-xr-x | pkg/sentry/kernel/kernel_state_autogen.go | 4 | ||||
-rwxr-xr-x | pkg/sentry/vfs/dentry.go | 4 | ||||
-rwxr-xr-x | pkg/sentry/vfs/device.go | 3 | ||||
-rwxr-xr-x | pkg/sentry/vfs/filesystem.go | 2 | ||||
-rwxr-xr-x | pkg/sentry/vfs/filesystem_type.go | 1 | ||||
-rwxr-xr-x | pkg/sentry/vfs/mount.go | 4 | ||||
-rwxr-xr-x | pkg/sentry/vfs/mount_unsafe.go | 8 | ||||
-rwxr-xr-x | pkg/sentry/vfs/vfs.go | 35 | ||||
-rwxr-xr-x | pkg/sentry/vfs/vfs_state_autogen.go | 162 |
11 files changed, 207 insertions, 27 deletions
diff --git a/pkg/sentry/control/proc.go b/pkg/sentry/control/proc.go index 8973754c8..5457ba5e7 100644 --- a/pkg/sentry/control/proc.go +++ b/pkg/sentry/control/proc.go @@ -199,7 +199,7 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI } paths := fs.GetPath(initArgs.Envv) - vfsObj := proc.Kernel.VFS + vfsObj := proc.Kernel.VFS() file, err := ResolveExecutablePath(ctx, vfsObj, initArgs.WorkingDirectory, initArgs.Argv[0], paths) if err != nil { return nil, 0, nil, fmt.Errorf("error finding executable %q in PATH %v: %v", initArgs.Argv[0], paths, err) diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index 2665f057c..ea21af33f 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -246,7 +246,7 @@ type Kernel struct { SpecialOpts // VFS keeps the filesystem state used across the kernel. - VFS *vfs.VirtualFilesystem + vfs vfs.VirtualFilesystem } // InitKernelArgs holds arguments to Init. @@ -815,7 +815,7 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID, FollowFinalSymlink: true, } var err error - wd, err = k.VFS.GetDentryAt(ctx, args.Credentials, &pop, &vfs.GetDentryOptions{ + wd, err = k.VFS().GetDentryAt(ctx, args.Credentials, &pop, &vfs.GetDentryOptions{ CheckSearchable: true, }) if err != nil { @@ -1506,3 +1506,8 @@ func (k *Kernel) EmitUnimplementedEvent(ctx context.Context) { Registers: t.Arch().StateData().Proto(), }) } + +// VFS returns the virtual filesystem for the kernel. +func (k *Kernel) VFS() *vfs.VirtualFilesystem { + return &k.vfs +} diff --git a/pkg/sentry/kernel/kernel_state_autogen.go b/pkg/sentry/kernel/kernel_state_autogen.go index edbaf9db8..8948ca886 100755 --- a/pkg/sentry/kernel/kernel_state_autogen.go +++ b/pkg/sentry/kernel/kernel_state_autogen.go @@ -156,7 +156,7 @@ func (x *Kernel) save(m state.Map) { m.Save("nextSocketEntry", &x.nextSocketEntry) m.Save("DirentCacheLimiter", &x.DirentCacheLimiter) m.Save("SpecialOpts", &x.SpecialOpts) - m.Save("VFS", &x.VFS) + m.Save("vfs", &x.vfs) } func (x *Kernel) afterLoad() {} @@ -189,7 +189,7 @@ func (x *Kernel) load(m state.Map) { m.Load("nextSocketEntry", &x.nextSocketEntry) m.Load("DirentCacheLimiter", &x.DirentCacheLimiter) m.Load("SpecialOpts", &x.SpecialOpts) - m.Load("VFS", &x.VFS) + m.Load("vfs", &x.vfs) m.LoadValue("danglingEndpoints", new([]tcpip.Endpoint), func(y interface{}) { x.loadDanglingEndpoints(y.([]tcpip.Endpoint)) }) m.LoadValue("deviceRegistry", new(*device.Registry), func(y interface{}) { x.loadDeviceRegistry(y.(*device.Registry)) }) } diff --git a/pkg/sentry/vfs/dentry.go b/pkg/sentry/vfs/dentry.go index 486a76475..35b208721 100755 --- a/pkg/sentry/vfs/dentry.go +++ b/pkg/sentry/vfs/dentry.go @@ -71,6 +71,8 @@ import ( // lifetime. Dentry reference counts only indicate the extent to which VFS // requires Dentries to exist; Filesystems may elect to cache or discard // Dentries with zero references. +// +// +stateify savable type Dentry struct { // parent is this Dentry's parent in this Filesystem. If this Dentry is // independent, parent is nil. @@ -89,7 +91,7 @@ type Dentry struct { children map[string]*Dentry // mu synchronizes disowning and mounting over this Dentry. - mu sync.Mutex + mu sync.Mutex `state:"nosave"` // impl is the DentryImpl associated with this Dentry. impl is immutable. // This should be the last field in Dentry. diff --git a/pkg/sentry/vfs/device.go b/pkg/sentry/vfs/device.go index 3af2aa58d..bda5576fa 100755 --- a/pkg/sentry/vfs/device.go +++ b/pkg/sentry/vfs/device.go @@ -56,6 +56,7 @@ type Device interface { Open(ctx context.Context, mnt *Mount, d *Dentry, opts OpenOptions) (*FileDescription, error) } +// +stateify savable type registeredDevice struct { dev Device opts RegisterDeviceOptions @@ -63,6 +64,8 @@ type registeredDevice struct { // RegisterDeviceOptions contains options to // VirtualFilesystem.RegisterDevice(). +// +// +stateify savable type RegisterDeviceOptions struct { // GroupName is the name shown for this device registration in // /proc/devices. If GroupName is empty, this registration will not be diff --git a/pkg/sentry/vfs/filesystem.go b/pkg/sentry/vfs/filesystem.go index a06a6caf3..556976d0b 100755 --- a/pkg/sentry/vfs/filesystem.go +++ b/pkg/sentry/vfs/filesystem.go @@ -29,6 +29,8 @@ import ( // Filesystem methods require that a reference is held. // // Filesystem is analogous to Linux's struct super_block. +// +// +stateify savable type Filesystem struct { // refs is the reference count. refs is accessed using atomic memory // operations. diff --git a/pkg/sentry/vfs/filesystem_type.go b/pkg/sentry/vfs/filesystem_type.go index c58b70728..bb9cada81 100755 --- a/pkg/sentry/vfs/filesystem_type.go +++ b/pkg/sentry/vfs/filesystem_type.go @@ -44,6 +44,7 @@ type GetFilesystemOptions struct { InternalData interface{} } +// +stateify savable type registeredFilesystemType struct { fsType FilesystemType opts RegisterFilesystemTypeOptions diff --git a/pkg/sentry/vfs/mount.go b/pkg/sentry/vfs/mount.go index ad2c9fcf4..9912df799 100755 --- a/pkg/sentry/vfs/mount.go +++ b/pkg/sentry/vfs/mount.go @@ -38,6 +38,8 @@ import ( // // Mount is analogous to Linux's struct mount. (gVisor does not distinguish // between struct mount and struct vfsmount.) +// +// +stateify savable type Mount struct { // vfs, fs, and root are immutable. References are held on fs and root. // @@ -85,6 +87,8 @@ type Mount struct { // MountNamespace methods require that a reference is held. // // MountNamespace is analogous to Linux's struct mnt_namespace. +// +// +stateify savable type MountNamespace struct { // root is the MountNamespace's root mount. root is immutable. root *Mount diff --git a/pkg/sentry/vfs/mount_unsafe.go b/pkg/sentry/vfs/mount_unsafe.go index bd90d36c4..1fe766a44 100755 --- a/pkg/sentry/vfs/mount_unsafe.go +++ b/pkg/sentry/vfs/mount_unsafe.go @@ -64,6 +64,8 @@ func (mnt *Mount) storeKey(vd VirtualDentry) { // (provided mutation is sufficiently uncommon). // // mountTable.Init() must be called on new mountTables before use. +// +// +stateify savable type mountTable struct { // mountTable is implemented as a seqcount-protected hash table that // resolves collisions with linear probing, featuring Robin Hood insertion @@ -75,8 +77,8 @@ type mountTable struct { // intrinsics and inline assembly, limiting the performance of this // approach.) - seq sync.SeqCount - seed uint32 // for hashing keys + seq sync.SeqCount `state:"nosave"` + seed uint32 // for hashing keys // size holds both length (number of elements) and capacity (number of // slots): capacity is stored as its base-2 log (referred to as order) in @@ -89,7 +91,7 @@ type mountTable struct { // length and cap in separate uint32s) for ~free. size uint64 - slots unsafe.Pointer // []mountSlot; never nil after Init + slots unsafe.Pointer `state:"nosave"` // []mountSlot; never nil after Init } type mountSlot struct { diff --git a/pkg/sentry/vfs/vfs.go b/pkg/sentry/vfs/vfs.go index 51deae313..8f29031b2 100755 --- a/pkg/sentry/vfs/vfs.go +++ b/pkg/sentry/vfs/vfs.go @@ -46,11 +46,13 @@ import ( // // There is no analogue to the VirtualFilesystem type in Linux, as the // equivalent state in Linux is global. +// +// +stateify savable type VirtualFilesystem struct { // mountMu serializes mount mutations. // // mountMu is analogous to Linux's namespace_sem. - mountMu sync.Mutex + mountMu sync.Mutex `state:"nosave"` // mounts maps (mount parent, mount point) pairs to mounts. (Since mounts // are uniquely namespaced, including mount parent in the key correctly @@ -89,44 +91,42 @@ type VirtualFilesystem struct { // devices contains all registered Devices. devices is protected by // devicesMu. - devicesMu sync.RWMutex + devicesMu sync.RWMutex `state:"nosave"` devices map[devTuple]*registeredDevice // anonBlockDevMinor contains all allocated anonymous block device minor // numbers. anonBlockDevMinorNext is a lower bound for the smallest // unallocated anonymous block device number. anonBlockDevMinorNext and // anonBlockDevMinor are protected by anonBlockDevMinorMu. - anonBlockDevMinorMu sync.Mutex + anonBlockDevMinorMu sync.Mutex `state:"nosave"` anonBlockDevMinorNext uint32 anonBlockDevMinor map[uint32]struct{} // fsTypes contains all registered FilesystemTypes. fsTypes is protected by // fsTypesMu. - fsTypesMu sync.RWMutex + fsTypesMu sync.RWMutex `state:"nosave"` fsTypes map[string]*registeredFilesystemType // filesystems contains all Filesystems. filesystems is protected by // filesystemsMu. - filesystemsMu sync.Mutex + filesystemsMu sync.Mutex `state:"nosave"` filesystems map[*Filesystem]struct{} } -// New returns a new VirtualFilesystem with no mounts or FilesystemTypes. -func New() *VirtualFilesystem { - vfs := &VirtualFilesystem{ - mountpoints: make(map[*Dentry]map[*Mount]struct{}), - devices: make(map[devTuple]*registeredDevice), - anonBlockDevMinorNext: 1, - anonBlockDevMinor: make(map[uint32]struct{}), - fsTypes: make(map[string]*registeredFilesystemType), - filesystems: make(map[*Filesystem]struct{}), - } +// Init initializes a new VirtualFilesystem with no mounts or FilesystemTypes. +func (vfs *VirtualFilesystem) Init() error { + vfs.mountpoints = make(map[*Dentry]map[*Mount]struct{}) + vfs.devices = make(map[devTuple]*registeredDevice) + vfs.anonBlockDevMinorNext = 1 + vfs.anonBlockDevMinor = make(map[uint32]struct{}) + vfs.fsTypes = make(map[string]*registeredFilesystemType) + vfs.filesystems = make(map[*Filesystem]struct{}) vfs.mounts.Init() // Construct vfs.anonMount. anonfsDevMinor, err := vfs.GetAnonBlockDevMinor() if err != nil { - panic(fmt.Sprintf("VirtualFilesystem.GetAnonBlockDevMinor() failed during VirtualFilesystem construction: %v", err)) + return err } anonfs := anonFilesystem{ devMinor: anonfsDevMinor, @@ -137,8 +137,7 @@ func New() *VirtualFilesystem { fs: &anonfs.vfsfs, refs: 1, } - - return vfs + return nil } // PathOperation specifies the path operated on by a VFS method. diff --git a/pkg/sentry/vfs/vfs_state_autogen.go b/pkg/sentry/vfs/vfs_state_autogen.go index 3f14d460c..243646328 100755 --- a/pkg/sentry/vfs/vfs_state_autogen.go +++ b/pkg/sentry/vfs/vfs_state_autogen.go @@ -9,6 +9,51 @@ import ( "gvisor.dev/gvisor/pkg/state" ) +func (x *Dentry) beforeSave() {} +func (x *Dentry) save(m state.Map) { + x.beforeSave() + m.Save("parent", &x.parent) + m.Save("name", &x.name) + m.Save("flags", &x.flags) + m.Save("mounts", &x.mounts) + m.Save("children", &x.children) + m.Save("impl", &x.impl) +} + +func (x *Dentry) afterLoad() {} +func (x *Dentry) load(m state.Map) { + m.Load("parent", &x.parent) + m.Load("name", &x.name) + m.Load("flags", &x.flags) + m.Load("mounts", &x.mounts) + m.Load("children", &x.children) + m.Load("impl", &x.impl) +} + +func (x *registeredDevice) beforeSave() {} +func (x *registeredDevice) save(m state.Map) { + x.beforeSave() + m.Save("dev", &x.dev) + m.Save("opts", &x.opts) +} + +func (x *registeredDevice) afterLoad() {} +func (x *registeredDevice) load(m state.Map) { + m.Load("dev", &x.dev) + m.Load("opts", &x.opts) +} + +func (x *RegisterDeviceOptions) beforeSave() {} +func (x *RegisterDeviceOptions) save(m state.Map) { + x.beforeSave() + m.Save("GroupName", &x.GroupName) +} + +func (x *RegisterDeviceOptions) afterLoad() {} +func (x *RegisterDeviceOptions) load(m state.Map) { + m.Load("GroupName", &x.GroupName) +} + func (x *epollInterestList) beforeSave() {} func (x *epollInterestList) save(m state.Map) { x.beforeSave() @@ -35,6 +80,114 @@ func (x *epollInterestEntry) load(m state.Map) { m.Load("prev", &x.prev) } +func (x *Filesystem) beforeSave() {} +func (x *Filesystem) save(m state.Map) { + x.beforeSave() + m.Save("refs", &x.refs) + m.Save("vfs", &x.vfs) + m.Save("impl", &x.impl) +} + +func (x *Filesystem) afterLoad() {} +func (x *Filesystem) load(m state.Map) { + m.Load("refs", &x.refs) + m.Load("vfs", &x.vfs) + m.Load("impl", &x.impl) +} + +func (x *registeredFilesystemType) beforeSave() {} +func (x *registeredFilesystemType) save(m state.Map) { + x.beforeSave() + m.Save("fsType", &x.fsType) + m.Save("opts", &x.opts) +} + +func (x *registeredFilesystemType) afterLoad() {} +func (x *registeredFilesystemType) load(m state.Map) { + m.Load("fsType", &x.fsType) + m.Load("opts", &x.opts) +} + +func (x *Mount) beforeSave() {} +func (x *Mount) save(m state.Map) { + x.beforeSave() + m.Save("vfs", &x.vfs) + m.Save("fs", &x.fs) + m.Save("root", &x.root) + m.Save("key", &x.key) + m.Save("ns", &x.ns) + m.Save("refs", &x.refs) + m.Save("children", &x.children) + m.Save("umounted", &x.umounted) + m.Save("writers", &x.writers) +} + +func (x *Mount) afterLoad() {} +func (x *Mount) load(m state.Map) { + m.Load("vfs", &x.vfs) + m.Load("fs", &x.fs) + m.Load("root", &x.root) + m.Load("key", &x.key) + m.Load("ns", &x.ns) + m.Load("refs", &x.refs) + m.Load("children", &x.children) + m.Load("umounted", &x.umounted) + m.Load("writers", &x.writers) +} + +func (x *MountNamespace) beforeSave() {} +func (x *MountNamespace) save(m state.Map) { + x.beforeSave() + m.Save("root", &x.root) + m.Save("refs", &x.refs) + m.Save("mountpoints", &x.mountpoints) +} + +func (x *MountNamespace) afterLoad() {} +func (x *MountNamespace) load(m state.Map) { + m.Load("root", &x.root) + m.Load("refs", &x.refs) + m.Load("mountpoints", &x.mountpoints) +} + +func (x *mountTable) beforeSave() {} +func (x *mountTable) save(m state.Map) { + x.beforeSave() + m.Save("seed", &x.seed) + m.Save("size", &x.size) +} + +func (x *mountTable) afterLoad() {} +func (x *mountTable) load(m state.Map) { + m.Load("seed", &x.seed) + m.Load("size", &x.size) +} + +func (x *VirtualFilesystem) beforeSave() {} +func (x *VirtualFilesystem) save(m state.Map) { + x.beforeSave() + m.Save("mounts", &x.mounts) + m.Save("mountpoints", &x.mountpoints) + m.Save("anonMount", &x.anonMount) + m.Save("devices", &x.devices) + m.Save("anonBlockDevMinorNext", &x.anonBlockDevMinorNext) + m.Save("anonBlockDevMinor", &x.anonBlockDevMinor) + m.Save("fsTypes", &x.fsTypes) + m.Save("filesystems", &x.filesystems) +} + +func (x *VirtualFilesystem) afterLoad() {} +func (x *VirtualFilesystem) load(m state.Map) { + m.Load("mounts", &x.mounts) + m.Load("mountpoints", &x.mountpoints) + m.Load("anonMount", &x.anonMount) + m.Load("devices", &x.devices) + m.Load("anonBlockDevMinorNext", &x.anonBlockDevMinorNext) + m.Load("anonBlockDevMinor", &x.anonBlockDevMinor) + m.Load("fsTypes", &x.fsTypes) + m.Load("filesystems", &x.filesystems) +} + func (x *VirtualDentry) beforeSave() {} func (x *VirtualDentry) save(m state.Map) { x.beforeSave() @@ -49,7 +202,16 @@ func (x *VirtualDentry) load(m state.Map) { } func init() { + state.Register("pkg/sentry/vfs.Dentry", (*Dentry)(nil), state.Fns{Save: (*Dentry).save, Load: (*Dentry).load}) + state.Register("pkg/sentry/vfs.registeredDevice", (*registeredDevice)(nil), state.Fns{Save: (*registeredDevice).save, Load: (*registeredDevice).load}) + state.Register("pkg/sentry/vfs.RegisterDeviceOptions", (*RegisterDeviceOptions)(nil), state.Fns{Save: (*RegisterDeviceOptions).save, Load: (*RegisterDeviceOptions).load}) state.Register("pkg/sentry/vfs.epollInterestList", (*epollInterestList)(nil), state.Fns{Save: (*epollInterestList).save, Load: (*epollInterestList).load}) state.Register("pkg/sentry/vfs.epollInterestEntry", (*epollInterestEntry)(nil), state.Fns{Save: (*epollInterestEntry).save, Load: (*epollInterestEntry).load}) + state.Register("pkg/sentry/vfs.Filesystem", (*Filesystem)(nil), state.Fns{Save: (*Filesystem).save, Load: (*Filesystem).load}) + state.Register("pkg/sentry/vfs.registeredFilesystemType", (*registeredFilesystemType)(nil), state.Fns{Save: (*registeredFilesystemType).save, Load: (*registeredFilesystemType).load}) + state.Register("pkg/sentry/vfs.Mount", (*Mount)(nil), state.Fns{Save: (*Mount).save, Load: (*Mount).load}) + state.Register("pkg/sentry/vfs.MountNamespace", (*MountNamespace)(nil), state.Fns{Save: (*MountNamespace).save, Load: (*MountNamespace).load}) + state.Register("pkg/sentry/vfs.mountTable", (*mountTable)(nil), state.Fns{Save: (*mountTable).save, Load: (*mountTable).load}) + state.Register("pkg/sentry/vfs.VirtualFilesystem", (*VirtualFilesystem)(nil), state.Fns{Save: (*VirtualFilesystem).save, Load: (*VirtualFilesystem).load}) state.Register("pkg/sentry/vfs.VirtualDentry", (*VirtualDentry)(nil), state.Fns{Save: (*VirtualDentry).save, Load: (*VirtualDentry).load}) } |