summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/proc/fds.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fs/proc/fds.go')
-rw-r--r--pkg/sentry/fs/proc/fds.go138
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
}