diff options
Diffstat (limited to 'pkg/sentry/fsimpl/proc')
-rw-r--r-- | pkg/sentry/fsimpl/proc/proc_state_autogen.go | 118 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/task.go | 2 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/task_files.go | 111 |
3 files changed, 209 insertions, 22 deletions
diff --git a/pkg/sentry/fsimpl/proc/proc_state_autogen.go b/pkg/sentry/fsimpl/proc/proc_state_autogen.go index f87739c23..e32e7671c 100644 --- a/pkg/sentry/fsimpl/proc/proc_state_autogen.go +++ b/pkg/sentry/fsimpl/proc/proc_state_autogen.go @@ -920,35 +920,121 @@ func (s *statmData) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(1, &s.task) } -func (s *statusData) StateTypeName() string { - return "pkg/sentry/fsimpl/proc.statusData" +func (s *statusInode) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.statusInode" } -func (s *statusData) StateFields() []string { +func (s *statusInode) StateFields() []string { return []string{ - "DynamicBytesFile", + "InodeAttrs", + "InodeNoStatFS", + "InodeNoopRefCount", + "InodeNotDirectory", + "InodeNotSymlink", "task", "pidns", + "locks", } } -func (s *statusData) beforeSave() {} +func (s *statusInode) beforeSave() {} // +checklocksignore -func (s *statusData) StateSave(stateSinkObject state.Sink) { +func (s *statusInode) StateSave(stateSinkObject state.Sink) { s.beforeSave() - stateSinkObject.Save(0, &s.DynamicBytesFile) - stateSinkObject.Save(1, &s.task) - stateSinkObject.Save(2, &s.pidns) + stateSinkObject.Save(0, &s.InodeAttrs) + stateSinkObject.Save(1, &s.InodeNoStatFS) + stateSinkObject.Save(2, &s.InodeNoopRefCount) + stateSinkObject.Save(3, &s.InodeNotDirectory) + stateSinkObject.Save(4, &s.InodeNotSymlink) + stateSinkObject.Save(5, &s.task) + stateSinkObject.Save(6, &s.pidns) + stateSinkObject.Save(7, &s.locks) } -func (s *statusData) afterLoad() {} +func (s *statusInode) afterLoad() {} // +checklocksignore -func (s *statusData) StateLoad(stateSourceObject state.Source) { - stateSourceObject.Load(0, &s.DynamicBytesFile) - stateSourceObject.Load(1, &s.task) - stateSourceObject.Load(2, &s.pidns) +func (s *statusInode) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.InodeAttrs) + stateSourceObject.Load(1, &s.InodeNoStatFS) + stateSourceObject.Load(2, &s.InodeNoopRefCount) + stateSourceObject.Load(3, &s.InodeNotDirectory) + stateSourceObject.Load(4, &s.InodeNotSymlink) + stateSourceObject.Load(5, &s.task) + stateSourceObject.Load(6, &s.pidns) + stateSourceObject.Load(7, &s.locks) +} + +func (s *statusFD) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.statusFD" +} + +func (s *statusFD) StateFields() []string { + return []string{ + "statusFDLowerBase", + "DynamicBytesFileDescriptionImpl", + "LockFD", + "vfsfd", + "inode", + "task", + "pidns", + "userns", + } +} + +func (s *statusFD) beforeSave() {} + +// +checklocksignore +func (s *statusFD) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.statusFDLowerBase) + stateSinkObject.Save(1, &s.DynamicBytesFileDescriptionImpl) + stateSinkObject.Save(2, &s.LockFD) + stateSinkObject.Save(3, &s.vfsfd) + stateSinkObject.Save(4, &s.inode) + stateSinkObject.Save(5, &s.task) + stateSinkObject.Save(6, &s.pidns) + stateSinkObject.Save(7, &s.userns) +} + +func (s *statusFD) afterLoad() {} + +// +checklocksignore +func (s *statusFD) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.statusFDLowerBase) + stateSourceObject.Load(1, &s.DynamicBytesFileDescriptionImpl) + stateSourceObject.Load(2, &s.LockFD) + stateSourceObject.Load(3, &s.vfsfd) + stateSourceObject.Load(4, &s.inode) + stateSourceObject.Load(5, &s.task) + stateSourceObject.Load(6, &s.pidns) + stateSourceObject.Load(7, &s.userns) +} + +func (s *statusFDLowerBase) StateTypeName() string { + return "pkg/sentry/fsimpl/proc.statusFDLowerBase" +} + +func (s *statusFDLowerBase) StateFields() []string { + return []string{ + "FileDescriptionDefaultImpl", + } +} + +func (s *statusFDLowerBase) beforeSave() {} + +// +checklocksignore +func (s *statusFDLowerBase) StateSave(stateSinkObject state.Sink) { + s.beforeSave() + stateSinkObject.Save(0, &s.FileDescriptionDefaultImpl) +} + +func (s *statusFDLowerBase) afterLoad() {} + +// +checklocksignore +func (s *statusFDLowerBase) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &s.FileDescriptionDefaultImpl) } func (i *ioData) StateTypeName() string { @@ -2317,7 +2403,9 @@ func init() { state.Register((*smapsData)(nil)) state.Register((*taskStatData)(nil)) state.Register((*statmData)(nil)) - state.Register((*statusData)(nil)) + state.Register((*statusInode)(nil)) + state.Register((*statusFD)(nil)) + state.Register((*statusFDLowerBase)(nil)) state.Register((*ioData)(nil)) state.Register((*oomScoreAdj)(nil)) state.Register((*exeSymlink)(nil)) diff --git a/pkg/sentry/fsimpl/proc/task.go b/pkg/sentry/fsimpl/proc/task.go index cbbc0935a..f54811edf 100644 --- a/pkg/sentry/fsimpl/proc/task.go +++ b/pkg/sentry/fsimpl/proc/task.go @@ -78,7 +78,7 @@ func (fs *filesystem) newTaskInode(ctx context.Context, task *kernel.Task, pidns "smaps": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, &smapsData{task: task}), "stat": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, &taskStatData{task: task, pidns: pidns, tgstats: isThreadGroup}), "statm": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, &statmData{task: task}), - "status": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, &statusData{task: task, pidns: pidns}), + "status": fs.newStatusInode(ctx, task, pidns, fs.NextIno(), 0444), "uid_map": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0644, &idMapData{task: task, gids: false}), } if isThreadGroup { diff --git a/pkg/sentry/fsimpl/proc/task_files.go b/pkg/sentry/fsimpl/proc/task_files.go index 5bb6bc372..0ce3ed797 100644 --- a/pkg/sentry/fsimpl/proc/task_files.go +++ b/pkg/sentry/fsimpl/proc/task_files.go @@ -661,34 +661,119 @@ func (s *statmData) Generate(ctx context.Context, buf *bytes.Buffer) error { return nil } -// statusData implements vfs.DynamicBytesSource for /proc/[pid]/status. +// statusInode implements kernfs.Inode for /proc/[pid]/status. // // +stateify savable -type statusData struct { - kernfs.DynamicBytesFile +type statusInode struct { + kernfs.InodeAttrs + kernfs.InodeNoStatFS + kernfs.InodeNoopRefCount + kernfs.InodeNotDirectory + kernfs.InodeNotSymlink task *kernel.Task pidns *kernel.PIDNamespace + locks vfs.FileLocks } -var _ dynamicInode = (*statusData)(nil) +// statusFD implements vfs.FileDescriptionImpl and vfs.DynamicByteSource for +// /proc/[pid]/status. +// +// +stateify savable +type statusFD struct { + statusFDLowerBase + vfs.DynamicBytesFileDescriptionImpl + vfs.LockFD + + vfsfd vfs.FileDescription + + inode *statusInode + task *kernel.Task + pidns *kernel.PIDNamespace + userns *auth.UserNamespace // equivalent to struct file::f_cred::user_ns +} + +// statusFDLowerBase is a dumb hack to ensure that statusFD prefers +// vfs.DynamicBytesFileDescriptionImpl methods to vfs.FileDescriptinDefaultImpl +// methods. +// +// +stateify savable +type statusFDLowerBase struct { + vfs.FileDescriptionDefaultImpl +} + +func (fs *filesystem) newStatusInode(ctx context.Context, task *kernel.Task, pidns *kernel.PIDNamespace, ino uint64, perm linux.FileMode) kernfs.Inode { + // Note: credentials are overridden by taskOwnedInode. + inode := &statusInode{ + task: task, + pidns: pidns, + } + inode.InodeAttrs.Init(ctx, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, linux.ModeRegular|perm) + return &taskOwnedInode{Inode: inode, owner: task} +} + +// Open implements kernfs.Inode.Open. +func (s *statusInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) { + fd := &statusFD{ + inode: s, + task: s.task, + pidns: s.pidns, + userns: rp.Credentials().UserNamespace, + } + fd.LockFD.Init(&s.locks) + if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil { + return nil, err + } + fd.SetDataSource(fd) + return &fd.vfsfd, nil +} + +// SetStat implements kernfs.Inode.SetStat. +func (*statusInode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error { + return linuxerr.EPERM +} + +// Release implements vfs.FileDescriptionImpl.Release. +func (s *statusFD) Release(ctx context.Context) { +} + +// Stat implements vfs.FileDescriptionImpl.Stat. +func (s *statusFD) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) { + fs := s.vfsfd.VirtualDentry().Mount().Filesystem() + return s.inode.Stat(ctx, fs, opts) +} + +// SetStat implements vfs.FileDescriptionImpl.SetStat. +func (s *statusFD) SetStat(ctx context.Context, opts vfs.SetStatOptions) error { + return linuxerr.EPERM +} // Generate implements vfs.DynamicBytesSource.Generate. -func (s *statusData) Generate(ctx context.Context, buf *bytes.Buffer) error { +func (s *statusFD) Generate(ctx context.Context, buf *bytes.Buffer) error { fmt.Fprintf(buf, "Name:\t%s\n", s.task.Name()) fmt.Fprintf(buf, "State:\t%s\n", s.task.StateStatus()) fmt.Fprintf(buf, "Tgid:\t%d\n", s.pidns.IDOfThreadGroup(s.task.ThreadGroup())) fmt.Fprintf(buf, "Pid:\t%d\n", s.pidns.IDOfTask(s.task)) + ppid := kernel.ThreadID(0) if parent := s.task.Parent(); parent != nil { ppid = s.pidns.IDOfThreadGroup(parent.ThreadGroup()) } fmt.Fprintf(buf, "PPid:\t%d\n", ppid) + tpid := kernel.ThreadID(0) if tracer := s.task.Tracer(); tracer != nil { tpid = s.pidns.IDOfTask(tracer) } fmt.Fprintf(buf, "TracerPid:\t%d\n", tpid) + + creds := s.task.Credentials() + ruid := creds.RealKUID.In(s.userns).OrOverflow() + euid := creds.EffectiveKUID.In(s.userns).OrOverflow() + suid := creds.SavedKUID.In(s.userns).OrOverflow() + rgid := creds.RealKGID.In(s.userns).OrOverflow() + egid := creds.EffectiveKGID.In(s.userns).OrOverflow() + sgid := creds.SavedKGID.In(s.userns).OrOverflow() var fds int var vss, rss, data uint64 s.task.WithMuLocked(func(t *kernel.Task) { @@ -701,12 +786,26 @@ func (s *statusData) Generate(ctx context.Context, buf *bytes.Buffer) error { data = mm.VirtualDataSize() } }) + // Filesystem user/group IDs aren't implemented; effective UID/GID are used + // instead. + fmt.Fprintf(buf, "Uid:\t%d\t%d\t%d\t%d\n", ruid, euid, suid, euid) + fmt.Fprintf(buf, "Gid:\t%d\t%d\t%d\t%d\n", rgid, egid, sgid, egid) fmt.Fprintf(buf, "FDSize:\t%d\n", fds) + buf.WriteString("Groups:\t ") + // There is a space between each pair of supplemental GIDs, as well as an + // unconditional trailing space that some applications actually depend on. + var sep string + for _, kgid := range creds.ExtraKGIDs { + fmt.Fprintf(buf, "%s%d", sep, kgid.In(s.userns).OrOverflow()) + sep = " " + } + buf.WriteString(" \n") + fmt.Fprintf(buf, "VmSize:\t%d kB\n", vss>>10) fmt.Fprintf(buf, "VmRSS:\t%d kB\n", rss>>10) fmt.Fprintf(buf, "VmData:\t%d kB\n", data>>10) + fmt.Fprintf(buf, "Threads:\t%d\n", s.task.ThreadGroup().Count()) - creds := s.task.Credentials() fmt.Fprintf(buf, "CapInh:\t%016x\n", creds.InheritableCaps) fmt.Fprintf(buf, "CapPrm:\t%016x\n", creds.PermittedCaps) fmt.Fprintf(buf, "CapEff:\t%016x\n", creds.EffectiveCaps) |