From dc8450b5676d4c4ac9bcfa23cabd862e0060527d Mon Sep 17 00:00:00 2001 From: Nicolas Lacasse Date: Mon, 14 Jan 2019 20:33:29 -0800 Subject: Remove fs.Handle, ramfs.Entry, and all the DeprecatedFileOperations. More helper structs have been added to the fsutil package to make it easier to implement fs.InodeOperations and fs.FileOperations. PiperOrigin-RevId: 229305982 Change-Id: Ib6f8d3862f4216745116857913dbfa351530223b --- pkg/sentry/fs/proc/proc.go | 152 +++++++++++++++++++++------------------------ 1 file changed, 71 insertions(+), 81 deletions(-) (limited to 'pkg/sentry/fs/proc/proc.go') 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 } -- cgit v1.2.3