diff options
Diffstat (limited to 'pkg/sentry/fs/proc/fds.go')
-rw-r--r-- | pkg/sentry/fs/proc/fds.go | 138 |
1 files changed, 82 insertions, 56 deletions
diff --git a/pkg/sentry/fs/proc/fds.go b/pkg/sentry/fs/proc/fds.go index 5acbce75e..b8a0a5eff 100644 --- a/pkg/sentry/fs/proc/fds.go +++ b/pkg/sentry/fs/proc/fds.go @@ -21,11 +21,11 @@ import ( "gvisor.googlesource.com/gvisor/pkg/sentry/context" "gvisor.googlesource.com/gvisor/pkg/sentry/fs" + "gvisor.googlesource.com/gvisor/pkg/sentry/fs/fsutil" "gvisor.googlesource.com/gvisor/pkg/sentry/fs/proc/device" "gvisor.googlesource.com/gvisor/pkg/sentry/fs/ramfs" "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/kdefs" - "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" "gvisor.googlesource.com/gvisor/pkg/syserror" ) @@ -55,7 +55,7 @@ func walkDescriptors(t *kernel.Task, p string, toInode func(*fs.File, kernel.FDF // readDescriptors reads fds in the task starting at offset, and calls the // toDentAttr callback for each to get a DentAttr, which it then emits. This is // a helper for implementing fs.InodeOperations.Readdir. -func readDescriptors(t *kernel.Task, c *fs.DirCtx, offset int, toDentAttr func(int) fs.DentAttr) (int, error) { +func readDescriptors(t *kernel.Task, c *fs.DirCtx, offset int64, toDentAttr func(int) fs.DentAttr) (int64, error) { var fds kernel.FDs t.WithMuLocked(func(t *kernel.Task) { if fdm := t.FDMap(); fdm != nil { @@ -69,7 +69,7 @@ func readDescriptors(t *kernel.Task, c *fs.DirCtx, offset int, toDentAttr func(i } // Find the fd to start at. - idx := sort.SearchInts(fdInts, offset) + idx := sort.SearchInts(fdInts, int(offset)) if idx == len(fdInts) { return offset, nil } @@ -80,28 +80,32 @@ func readDescriptors(t *kernel.Task, c *fs.DirCtx, offset int, toDentAttr func(i name := strconv.FormatUint(uint64(fd), 10) if err := c.DirEmit(name, toDentAttr(fd)); err != nil { // Returned offset is the next fd to serialize. - return fd, err + return int64(fd), err } } // We serialized them all. Next offset should be higher than last // serialized fd. - return fd + 1, nil + return int64(fd + 1), nil } -// fd is a single file in /proc/TID/fd/. +// fd implements fs.InodeOperations for a file in /proc/TID/fd/. type fd struct { ramfs.Symlink *fs.File } +var _ fs.InodeOperations = (*fd)(nil) + // newFd returns a new fd based on an existing file. // // This inherits one reference to the file. func newFd(t *kernel.Task, f *fs.File, msrc *fs.MountSource) *fs.Inode { - fd := &fd{File: f} - // RootOwner by default, is overridden in UnstableAttr() - fd.InitSymlink(t, fs.RootOwner, "") - return newFile(fd, msrc, fs.Symlink, t) + fd := &fd{ + // RootOwner overridden by taskOwnedInodeOps.UnstableAttrs(). + Symlink: *ramfs.NewSymlink(t, fs.RootOwner, ""), + File: f, + } + return newProcInode(fd, msrc, fs.Symlink, t) } // GetFile returns the fs.File backing this fd. The dirent and flags @@ -142,7 +146,7 @@ func (f *fd) Close() error { return nil } -// fdDir implements /proc/TID/fd. +// fdDir is an InodeOperations for /proc/TID/fd. // // +stateify savable type fdDir struct { @@ -154,11 +158,15 @@ type fdDir struct { t *kernel.Task } +var _ fs.InodeOperations = (*fdDir)(nil) + // newFdDir creates a new fdDir. func newFdDir(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { - f := &fdDir{t: t} - f.InitDir(t, nil, fs.RootOwner, fs.FilePermissions{User: fs.PermMask{Read: true, Execute: true}}) - return newFile(f, msrc, fs.SpecialDirectory, t) + f := &fdDir{ + Dir: *ramfs.NewDir(t, nil, fs.RootOwner, fs.FilePermissions{User: fs.PermMask{Read: true, Execute: true}}), + t: t, + } + return newProcInode(f, msrc, fs.SpecialDirectory, t) } // Check implements InodeOperations.Check. @@ -191,49 +199,55 @@ func (f *fdDir) Lookup(ctx context.Context, dir *fs.Inode, p string) (*fs.Dirent return fs.NewDirent(n, p), nil } -// DeprecatedReaddir lists fds in /proc/TID/fd. -func (f *fdDir) DeprecatedReaddir(ctx context.Context, dirCtx *fs.DirCtx, offset int) (int, error) { - return readDescriptors(f.t, dirCtx, offset, func(fd int) fs.DentAttr { - return fs.GenericDentAttr(fs.Symlink, device.ProcDevice) +// GetFile implements fs.FileOperations.GetFile. +func (f *fdDir) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) { + fops := &fdDirFile{ + isInfoFile: false, + t: f.t, + } + return fs.NewFile(ctx, dirent, flags, fops), nil +} + +// +stateify savable +type fdDirFile struct { + fsutil.DirFileOperations `state:"nosave"` + + isInfoFile bool + + t *kernel.Task +} + +var _ fs.FileOperations = (*fdDirFile)(nil) + +// Readdir implements fs.FileOperations.Readdir. +func (f *fdDirFile) Readdir(ctx context.Context, file *fs.File, ser fs.DentrySerializer) (int64, error) { + dirCtx := &fs.DirCtx{ + Serializer: ser, + } + typ := fs.RegularFile + if f.isInfoFile { + typ = fs.Symlink + } + return readDescriptors(f.t, dirCtx, file.Offset(), func(fd int) fs.DentAttr { + return fs.GenericDentAttr(typ, device.ProcDevice) }) } -// fdInfo is a single file in /proc/TID/fdinfo/. +// fdInfoInode is a single file in /proc/TID/fdinfo/. // // +stateify savable -type fdInfo struct { - ramfs.File +type fdInfoInode struct { + staticFileInodeOps file *fs.File flags fs.FileFlags fdFlags kernel.FDFlags } -// newFdInfo returns a new fdInfo based on an existing file. -func newFdInfo(t *kernel.Task, file *fs.File, fdFlags kernel.FDFlags, msrc *fs.MountSource) *fs.Inode { - fdi := &fdInfo{file: file, flags: file.Flags(), fdFlags: fdFlags} - fdi.InitFile(t, fs.RootOwner, fs.FilePermissions{User: fs.PermMask{Read: true}}) - // TODO: Get pos, locks, and other data. For now we only - // have flags. - // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt - - flags := file.Flags().ToLinux() | fdFlags.ToLinuxFileFlags() - fdi.Append([]byte(fmt.Sprintf("flags:\t0%o\n", flags))) - return newFile(fdi, msrc, fs.SpecialFile, t) -} - -// DeprecatedPwritev implements fs.HandleOperations.DeprecatedPwritev. -func (*fdInfo) DeprecatedPwritev(ctx context.Context, src usermem.IOSequence, offset int64) (int64, error) { - return 0, ramfs.ErrInvalidOp -} - -// Truncate implements fs.InodeOperations.Truncate. -func (*fdInfo) Truncate(ctx context.Context, inode *fs.Inode, size int64) error { - return ramfs.ErrInvalidOp -} +var _ fs.InodeOperations = (*fdInfoInode)(nil) -func (f *fdInfo) Release(ctx context.Context) { - f.File.Release(ctx) +// Release implements fs.InodeOperations.Release. +func (f *fdInfoInode) Release(ctx context.Context) { f.file.DecRef() } @@ -249,25 +263,37 @@ type fdInfoDir struct { // newFdInfoDir creates a new fdInfoDir. func newFdInfoDir(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { - fdid := &fdInfoDir{t: t} - fdid.InitDir(t, nil, fs.RootOwner, fs.FilePermsFromMode(0500)) - return newFile(fdid, msrc, fs.SpecialDirectory, t) + fdid := &fdInfoDir{ + Dir: *ramfs.NewDir(t, nil, fs.RootOwner, fs.FilePermsFromMode(0500)), + t: t, + } + return newProcInode(fdid, msrc, fs.SpecialDirectory, t) } // Lookup loads an fd in /proc/TID/fdinfo into a Dirent. func (fdid *fdInfoDir) Lookup(ctx context.Context, dir *fs.Inode, p string) (*fs.Dirent, error) { - n, err := walkDescriptors(fdid.t, p, func(file *fs.File, fdFlags kernel.FDFlags) *fs.Inode { - return newFdInfo(fdid.t, file, fdFlags, dir.MountSource) + inode, err := walkDescriptors(fdid.t, p, func(file *fs.File, fdFlags kernel.FDFlags) *fs.Inode { + // TODO: Using a static inode here means that the + // data can be out-of-date if, for instance, the flags on the + // FD change before we read this file. We should switch to + // generating the data on Read(). Also, we should include pos, + // locks, and other data. For now we only have flags. + // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt + flags := file.Flags().ToLinux() | fdFlags.ToLinuxFileFlags() + contents := []byte(fmt.Sprintf("flags:\t0%o\n", flags)) + return newStaticProcInode(ctx, dir.MountSource, contents) }) if err != nil { return nil, err } - return fs.NewDirent(n, p), nil + return fs.NewDirent(inode, p), nil } -// DeprecatedReaddir lists fds in /proc/TID/fdinfo. -func (fdid *fdInfoDir) DeprecatedReaddir(ctx context.Context, dirCtx *fs.DirCtx, offset int) (int, error) { - return readDescriptors(fdid.t, dirCtx, offset, func(fd int) fs.DentAttr { - return fs.GenericDentAttr(fs.RegularFile, device.ProcDevice) - }) +// GetFile implements fs.FileOperations.GetFile. +func (fdid *fdInfoDir) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) { + fops := &fdDirFile{ + isInfoFile: true, + t: fdid.t, + } + return fs.NewFile(ctx, dirent, flags, fops), nil } |