github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/proc/subtasks.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package proc 16 17 import ( 18 "sort" 19 "strconv" 20 21 "github.com/SagerNet/gvisor/pkg/abi/linux" 22 "github.com/SagerNet/gvisor/pkg/context" 23 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 24 "github.com/SagerNet/gvisor/pkg/sentry/fsimpl/kernfs" 25 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 26 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 27 "github.com/SagerNet/gvisor/pkg/sentry/vfs" 28 "github.com/SagerNet/gvisor/pkg/syserror" 29 ) 30 31 // subtasksInode represents the inode for /proc/[pid]/task/ directory. 32 // 33 // +stateify savable 34 type subtasksInode struct { 35 implStatFS 36 kernfs.InodeAlwaysValid 37 kernfs.InodeAttrs 38 kernfs.InodeDirectoryNoNewChildren 39 kernfs.InodeNotSymlink 40 kernfs.InodeTemporary 41 kernfs.OrderedChildren 42 subtasksInodeRefs 43 44 locks vfs.FileLocks 45 46 fs *filesystem 47 task *kernel.Task 48 pidns *kernel.PIDNamespace 49 cgroupControllers map[string]string 50 } 51 52 var _ kernfs.Inode = (*subtasksInode)(nil) 53 54 func (fs *filesystem) newSubtasks(ctx context.Context, task *kernel.Task, pidns *kernel.PIDNamespace, cgroupControllers map[string]string) kernfs.Inode { 55 subInode := &subtasksInode{ 56 fs: fs, 57 task: task, 58 pidns: pidns, 59 cgroupControllers: cgroupControllers, 60 } 61 // Note: credentials are overridden by taskOwnedInode. 62 subInode.InodeAttrs.Init(ctx, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555) 63 subInode.OrderedChildren.Init(kernfs.OrderedChildrenOptions{}) 64 subInode.InitRefs() 65 66 inode := &taskOwnedInode{Inode: subInode, owner: task} 67 return inode 68 } 69 70 // Lookup implements kernfs.inodeDirectory.Lookup. 71 func (i *subtasksInode) Lookup(ctx context.Context, name string) (kernfs.Inode, error) { 72 tid, err := strconv.ParseUint(name, 10, 32) 73 if err != nil { 74 return nil, syserror.ENOENT 75 } 76 77 subTask := i.pidns.TaskWithID(kernel.ThreadID(tid)) 78 if subTask == nil { 79 return nil, syserror.ENOENT 80 } 81 if subTask.ThreadGroup() != i.task.ThreadGroup() { 82 return nil, syserror.ENOENT 83 } 84 return i.fs.newTaskInode(ctx, subTask, i.pidns, false, i.cgroupControllers) 85 } 86 87 // IterDirents implements kernfs.inodeDirectory.IterDirents. 88 func (i *subtasksInode) IterDirents(ctx context.Context, mnt *vfs.Mount, cb vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) { 89 tasks := i.task.ThreadGroup().MemberIDs(i.pidns) 90 if len(tasks) == 0 { 91 return offset, syserror.ENOENT 92 } 93 if relOffset >= int64(len(tasks)) { 94 return offset, nil 95 } 96 97 tids := make([]int, 0, len(tasks)) 98 for _, tid := range tasks { 99 tids = append(tids, int(tid)) 100 } 101 102 sort.Ints(tids) 103 for _, tid := range tids[relOffset:] { 104 dirent := vfs.Dirent{ 105 Name: strconv.FormatUint(uint64(tid), 10), 106 Type: linux.DT_DIR, 107 Ino: i.fs.NextIno(), 108 NextOff: offset + 1, 109 } 110 if err := cb.Handle(dirent); err != nil { 111 return offset, err 112 } 113 offset++ 114 } 115 return offset, nil 116 } 117 118 // +stateify savable 119 type subtasksFD struct { 120 kernfs.GenericDirectoryFD 121 122 task *kernel.Task 123 } 124 125 func (fd *subtasksFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback) error { 126 if fd.task.ExitState() >= kernel.TaskExitZombie { 127 return syserror.ENOENT 128 } 129 return fd.GenericDirectoryFD.IterDirents(ctx, cb) 130 } 131 132 // Seek implements vfs.FileDescriptionImpl.Seek. 133 func (fd *subtasksFD) Seek(ctx context.Context, offset int64, whence int32) (int64, error) { 134 if fd.task.ExitState() >= kernel.TaskExitZombie { 135 return 0, syserror.ENOENT 136 } 137 return fd.GenericDirectoryFD.Seek(ctx, offset, whence) 138 } 139 140 // Stat implements vfs.FileDescriptionImpl.Stat. 141 func (fd *subtasksFD) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) { 142 if fd.task.ExitState() >= kernel.TaskExitZombie { 143 return linux.Statx{}, syserror.ENOENT 144 } 145 return fd.GenericDirectoryFD.Stat(ctx, opts) 146 } 147 148 // SetStat implements vfs.FileDescriptionImpl.SetStat. 149 func (fd *subtasksFD) SetStat(ctx context.Context, opts vfs.SetStatOptions) error { 150 if fd.task.ExitState() >= kernel.TaskExitZombie { 151 return syserror.ENOENT 152 } 153 return fd.GenericDirectoryFD.SetStat(ctx, opts) 154 } 155 156 // Open implements kernfs.Inode.Open. 157 func (i *subtasksInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) { 158 fd := &subtasksFD{task: i.task} 159 if err := fd.Init(&i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{ 160 SeekEnd: kernfs.SeekEndZero, 161 }); err != nil { 162 return nil, err 163 } 164 if err := fd.VFSFileDescription().Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil { 165 return nil, err 166 } 167 return fd.VFSFileDescription(), nil 168 } 169 170 // Stat implements kernfs.Inode.Stat. 171 func (i *subtasksInode) Stat(ctx context.Context, vsfs *vfs.Filesystem, opts vfs.StatOptions) (linux.Statx, error) { 172 stat, err := i.InodeAttrs.Stat(ctx, vsfs, opts) 173 if err != nil { 174 return linux.Statx{}, err 175 } 176 if opts.Mask&linux.STATX_NLINK != 0 { 177 stat.Nlink += uint32(i.task.ThreadGroup().Count()) 178 } 179 return stat, nil 180 } 181 182 // SetStat implements kernfs.Inode.SetStat not allowing inode attributes to be changed. 183 func (*subtasksInode) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error { 184 return linuxerr.EPERM 185 } 186 187 // DecRef implements kernfs.Inode.DecRef. 188 func (i *subtasksInode) DecRef(ctx context.Context) { 189 i.subtasksInodeRefs.DecRef(func() { i.Destroy(ctx) }) 190 }