summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/proc/proc.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fs/proc/proc.go')
-rw-r--r--pkg/sentry/fs/proc/proc.go152
1 files changed, 71 insertions, 81 deletions
diff --git a/pkg/sentry/fs/proc/proc.go b/pkg/sentry/fs/proc/proc.go
index 70e549c31..d1c699418 100644
--- a/pkg/sentry/fs/proc/proc.go
+++ b/pkg/sentry/fs/proc/proc.go
@@ -17,18 +17,17 @@ package proc
import (
"fmt"
- "io"
"sort"
"strconv"
"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/proc/seqfile"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/ramfs"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
"gvisor.googlesource.com/gvisor/pkg/sentry/socket/rpcinet"
- "gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
"gvisor.googlesource.com/gvisor/pkg/syserror"
)
@@ -46,32 +45,6 @@ type proc struct {
pidns *kernel.PIDNamespace
}
-// stubProcFSFile is a file type that can be used to return file contents
-// which are constant. This file is not writable and will always have mode
-// 0444.
-//
-// +stateify savable
-type stubProcFSFile struct {
- ramfs.Entry
-
- // contents are the immutable file contents that will always be returned.
- contents []byte
-}
-
-// DeprecatedPreadv implements fs.InodeOperations.DeprecatedPreadv.
-func (s *stubProcFSFile) DeprecatedPreadv(ctx context.Context, dst usermem.IOSequence, offset int64) (int64, error) {
- if offset < 0 {
- return 0, syserror.EINVAL
- }
-
- if offset >= int64(len(s.contents)) {
- return 0, io.EOF
- }
-
- n, err := dst.CopyOut(ctx, s.contents[offset:])
- return int64(n), err
-}
-
// New returns the root node of a partial simple procfs.
func New(ctx context.Context, msrc *fs.MountSource) (*fs.Inode, error) {
k := kernel.KernelFromContext(ctx)
@@ -83,29 +56,39 @@ func New(ctx context.Context, msrc *fs.MountSource) (*fs.Inode, error) {
return nil, fmt.Errorf("procfs requires a PID namespace")
}
- p := &proc{k: k, pidns: pidns}
- p.InitDir(ctx, map[string]*fs.Inode{
+ // Note that these are just the static members. There are dynamic
+ // members populated in Readdir and Lookup below.
+ contents := map[string]*fs.Inode{
+ "cpuinfo": newCPUInfo(ctx, msrc),
"filesystems": seqfile.NewSeqFileInode(ctx, &filesystemsData{}, msrc),
"loadavg": seqfile.NewSeqFileInode(ctx, &loadavgData{}, msrc),
"meminfo": seqfile.NewSeqFileInode(ctx, &meminfoData{k}, msrc),
- "mounts": newMountsSymlink(ctx, msrc),
+ "mounts": newProcInode(ramfs.NewSymlink(ctx, fs.RootOwner, "self/mounts"), msrc, fs.Symlink, nil),
+ "self": newSelf(ctx, pidns, msrc),
"stat": seqfile.NewSeqFileInode(ctx, &statData{k}, msrc),
+ "thread-self": newThreadSelf(ctx, pidns, msrc),
+ "uptime": newUptime(ctx, msrc),
"version": seqfile.NewSeqFileInode(ctx, &versionData{k}, msrc),
- }, fs.RootOwner, fs.FilePermsFromMode(0555))
+ }
+
+ // Construct the proc InodeOperations.
+ p := &proc{
+ Dir: *ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)),
+ k: k,
+ pidns: pidns,
+ }
+
+ // Add more contents that need proc to be initialized.
+ p.AddChild(ctx, "sys", p.newSysDir(ctx, msrc))
- p.AddChild(ctx, "cpuinfo", p.newCPUInfo(ctx, msrc))
// If we're using rpcinet we will let it manage /proc/net.
if _, ok := p.k.NetworkStack().(*rpcinet.Stack); ok {
- p.AddChild(ctx, "net", newRPCInetProcNet(ctx, msrc))
+ contents["net"] = newRPCInetProcNet(ctx, msrc)
} else {
- p.AddChild(ctx, "net", p.newNetDir(ctx, msrc))
+ contents["net"] = p.newNetDir(ctx, msrc)
}
- p.AddChild(ctx, "self", p.newSelf(ctx, msrc))
- p.AddChild(ctx, "sys", p.newSysDir(ctx, msrc))
- p.AddChild(ctx, "thread-self", p.newThreadSelf(ctx, msrc))
- p.AddChild(ctx, "uptime", p.newUptime(ctx, msrc))
- return newFile(p, msrc, fs.SpecialDirectory, nil), nil
+ return newProcInode(p, msrc, fs.SpecialDirectory, nil), nil
}
// self is a magical link.
@@ -118,26 +101,21 @@ type self struct {
}
// newSelf returns a new "self" node.
-func (p *proc) newSelf(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
- s := &self{pidns: p.pidns}
- s.InitSymlink(ctx, fs.RootOwner, "")
- return newFile(s, msrc, fs.Symlink, nil)
+func newSelf(ctx context.Context, pidns *kernel.PIDNamespace, msrc *fs.MountSource) *fs.Inode {
+ s := &self{
+ Symlink: *ramfs.NewSymlink(ctx, fs.RootOwner, ""),
+ pidns: pidns,
+ }
+ return newProcInode(s, msrc, fs.Symlink, nil)
}
// newThreadSelf returns a new "threadSelf" node.
-func (p *proc) newThreadSelf(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
- s := &threadSelf{pidns: p.pidns}
- s.InitSymlink(ctx, fs.RootOwner, "")
- return newFile(s, msrc, fs.Symlink, nil)
-}
-
-// newStubProcFsFile returns a procfs file with constant contents.
-func (p *proc) newStubProcFSFile(ctx context.Context, msrc *fs.MountSource, c []byte) *fs.Inode {
- u := &stubProcFSFile{
- contents: c,
+func newThreadSelf(ctx context.Context, pidns *kernel.PIDNamespace, msrc *fs.MountSource) *fs.Inode {
+ s := &threadSelf{
+ Symlink: *ramfs.NewSymlink(ctx, fs.RootOwner, ""),
+ pidns: pidns,
}
- u.InitEntry(ctx, fs.RootOwner, fs.FilePermsFromMode(0444))
- return newFile(u, msrc, fs.SpecialFile, nil)
+ return newProcInode(s, msrc, fs.Symlink, nil)
}
// Readlink implements fs.InodeOperations.Readlink.
@@ -145,13 +123,13 @@ func (s *self) Readlink(ctx context.Context, inode *fs.Inode) (string, error) {
if t := kernel.TaskFromContext(ctx); t != nil {
tgid := s.pidns.IDOfThreadGroup(t.ThreadGroup())
if tgid == 0 {
- return "", ramfs.ErrNotFound
+ return "", syserror.ENOENT
}
return strconv.FormatUint(uint64(tgid), 10), nil
}
// Who is reading this link?
- return "", ramfs.ErrInvalidOp
+ return "", syserror.EINVAL
}
// threadSelf is more magical than "self" link.
@@ -169,13 +147,13 @@ func (s *threadSelf) Readlink(ctx context.Context, inode *fs.Inode) (string, err
tgid := s.pidns.IDOfThreadGroup(t.ThreadGroup())
tid := s.pidns.IDOfTask(t)
if tid == 0 || tgid == 0 {
- return "", ramfs.ErrNotFound
+ return "", syserror.ENOENT
}
return fmt.Sprintf("%d/task/%d", tgid, tid), nil
}
// Who is reading this link?
- return "", ramfs.ErrInvalidOp
+ return "", syserror.EINVAL
}
// Lookup loads an Inode at name into a Dirent.
@@ -204,25 +182,44 @@ func (p *proc) Lookup(ctx context.Context, dir *fs.Inode, name string) (*fs.Dire
return fs.NewDirent(td, name), nil
}
-// Readdir synthesizes proc contents.
-func (p *proc) DeprecatedReaddir(ctx context.Context, dirCtx *fs.DirCtx, offset int) (int, error) {
- // Serialize normal contents.
- _, err := p.Dir.DeprecatedReaddir(ctx, dirCtx, offset)
- if err != nil {
- return offset, err
+// GetFile implements fs.InodeOperations.
+func (p *proc) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
+ return fs.NewFile(ctx, dirent, flags, &rootProcFile{iops: p}), nil
+}
+
+// rootProcFile implements fs.FileOperations for the proc directory.
+//
+// +stateify savable
+type rootProcFile struct {
+ fsutil.DirFileOperations `state:"nosave"`
+
+ iops *proc
+}
+
+var _ fs.FileOperations = (*rootProcFile)(nil)
+
+// Readdir implements fs.FileOperations.Readdir.
+func (rpf *rootProcFile) Readdir(ctx context.Context, file *fs.File, ser fs.DentrySerializer) (int64, error) {
+ offset := file.Offset()
+ dirCtx := &fs.DirCtx{
+ Serializer: ser,
}
- m := make(map[string]fs.DentAttr)
- var names []string
+ // Get normal directory contents from ramfs dir.
+ names, m := rpf.iops.Dir.Children()
- // Add special files.
- m["sys"] = fs.GenericDentAttr(fs.SpecialFile, device.ProcDevice)
- names = append(names, "sys")
+ // Add dot and dotdot.
+ root := fs.RootFromContext(ctx)
+ defer root.DecRef()
+ dot, dotdot := file.Dirent.GetDotAttrs(root)
+ names = append(names, ".", "..")
+ m["."] = dot
+ m[".."] = dotdot
// Collect tasks.
// Per linux we only include it in directory listings if it's the leader.
// But for whatever crazy reason, you can still walk to the given node.
- for _, tg := range p.pidns.ThreadGroups() {
+ for _, tg := range rpf.iops.pidns.ThreadGroups() {
if leader := tg.Leader(); leader != nil {
name := strconv.FormatUint(uint64(tg.ID()), 10)
m[name] = fs.GenericDentAttr(fs.SpecialDirectory, device.ProcDevice)
@@ -230,7 +227,7 @@ func (p *proc) DeprecatedReaddir(ctx context.Context, dirCtx *fs.DirCtx, offset
}
}
- if offset >= len(m) {
+ if offset >= int64(len(m)) {
return offset, nil
}
sort.Strings(names)
@@ -241,12 +238,5 @@ func (p *proc) DeprecatedReaddir(ctx context.Context, dirCtx *fs.DirCtx, offset
}
offset++
}
- return offset, err
-}
-
-// newMountsSymlink returns a symlink to "self/mounts".
-func newMountsSymlink(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
- s := &ramfs.Symlink{}
- s.InitSymlink(ctx, fs.RootOwner, "self/mounts")
- return newFile(s, msrc, fs.Symlink, nil)
+ return offset, nil
}