github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/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/MerlinKodo/gvisor/pkg/abi/linux" 22 "github.com/MerlinKodo/gvisor/pkg/context" 23 "github.com/MerlinKodo/gvisor/pkg/errors/linuxerr" 24 "github.com/MerlinKodo/gvisor/pkg/sentry/fsimpl/kernfs" 25 "github.com/MerlinKodo/gvisor/pkg/sentry/kernel" 26 "github.com/MerlinKodo/gvisor/pkg/sentry/kernel/auth" 27 "github.com/MerlinKodo/gvisor/pkg/sentry/vfs" 28 ) 29 30 // subtasksInode represents the inode for /proc/[pid]/task/ directory. 31 // 32 // +stateify savable 33 type subtasksInode struct { 34 implStatFS 35 kernfs.InodeAlwaysValid 36 kernfs.InodeAttrs 37 kernfs.InodeDirectoryNoNewChildren 38 kernfs.InodeNotAnonymous 39 kernfs.InodeNotSymlink 40 kernfs.InodeTemporary 41 kernfs.InodeWatches 42 kernfs.OrderedChildren 43 subtasksInodeRefs 44 45 locks vfs.FileLocks 46 47 fs *filesystem 48 task *kernel.Task 49 pidns *kernel.PIDNamespace 50 cgroupControllers map[string]string 51 } 52 53 var _ kernfs.Inode = (*subtasksInode)(nil) 54 55 func (fs *filesystem) newSubtasks(ctx context.Context, task *kernel.Task, pidns *kernel.PIDNamespace, cgroupControllers map[string]string) kernfs.Inode { 56 subInode := &subtasksInode{ 57 fs: fs, 58 task: task, 59 pidns: pidns, 60 cgroupControllers: cgroupControllers, 61 } 62 // Note: credentials are overridden by taskOwnedInode. 63 subInode.InodeAttrs.Init(ctx, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555) 64 subInode.OrderedChildren.Init(kernfs.OrderedChildrenOptions{}) 65 subInode.InitRefs() 66 67 inode := &taskOwnedInode{Inode: subInode, owner: task} 68 return inode 69 } 70 71 // Lookup implements kernfs.inodeDirectory.Lookup. 72 func (i *subtasksInode) Lookup(ctx context.Context, name string) (kernfs.Inode, error) { 73 tid, err := strconv.ParseUint(name, 10, 32) 74 if err != nil { 75 return nil, linuxerr.ENOENT 76 } 77 78 subTask := i.pidns.TaskWithID(kernel.ThreadID(tid)) 79 if subTask == nil { 80 return nil, linuxerr.ENOENT 81 } 82 if subTask.ThreadGroup() != i.task.ThreadGroup() { 83 return nil, linuxerr.ENOENT 84 } 85 return i.fs.newTaskInode(ctx, subTask, i.pidns, false, i.cgroupControllers) 86 } 87 88 // IterDirents implements kernfs.inodeDirectory.IterDirents. 89 func (i *subtasksInode) IterDirents(ctx context.Context, mnt *vfs.Mount, cb vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) { 90 tasks := i.task.ThreadGroup().MemberIDs(i.pidns) 91 if len(tasks) == 0 { 92 return offset, linuxerr.ENOENT 93 } 94 if relOffset >= int64(len(tasks)) { 95 return offset, nil 96 } 97 98 tids := make([]int, 0, len(tasks)) 99 for _, tid := range tasks { 100 tids = append(tids, int(tid)) 101 } 102 103 sort.Ints(tids) 104 for _, tid := range tids[relOffset:] { 105 dirent := vfs.Dirent{ 106 Name: strconv.FormatUint(uint64(tid), 10), 107 Type: linux.DT_DIR, 108 Ino: i.fs.NextIno(), 109 NextOff: offset + 1, 110 } 111 if err := cb.Handle(dirent); err != nil { 112 return offset, err 113 } 114 offset++ 115 } 116 return offset, nil 117 } 118 119 // +stateify savable 120 type subtasksFD struct { 121 kernfs.GenericDirectoryFD 122 123 task *kernel.Task 124 } 125 126 func (fd *subtasksFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback) error { 127 if fd.task.ExitState() >= kernel.TaskExitZombie { 128 return linuxerr.ENOENT 129 } 130 return fd.GenericDirectoryFD.IterDirents(ctx, cb) 131 } 132 133 // Seek implements vfs.FileDescriptionImpl.Seek. 134 func (fd *subtasksFD) Seek(ctx context.Context, offset int64, whence int32) (int64, error) { 135 if fd.task.ExitState() >= kernel.TaskExitZombie { 136 return 0, linuxerr.ENOENT 137 } 138 return fd.GenericDirectoryFD.Seek(ctx, offset, whence) 139 } 140 141 // Stat implements vfs.FileDescriptionImpl.Stat. 142 func (fd *subtasksFD) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) { 143 if fd.task.ExitState() >= kernel.TaskExitZombie { 144 return linux.Statx{}, linuxerr.ENOENT 145 } 146 return fd.GenericDirectoryFD.Stat(ctx, opts) 147 } 148 149 // SetStat implements vfs.FileDescriptionImpl.SetStat. 150 func (fd *subtasksFD) SetStat(ctx context.Context, opts vfs.SetStatOptions) error { 151 if fd.task.ExitState() >= kernel.TaskExitZombie { 152 return linuxerr.ENOENT 153 } 154 return fd.GenericDirectoryFD.SetStat(ctx, opts) 155 } 156 157 // Open implements kernfs.Inode.Open. 158 func (i *subtasksInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) { 159 fd := &subtasksFD{task: i.task} 160 if err := fd.Init(&i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{ 161 SeekEnd: kernfs.SeekEndZero, 162 }); err != nil { 163 return nil, err 164 } 165 if err := fd.VFSFileDescription().Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil { 166 return nil, err 167 } 168 return fd.VFSFileDescription(), nil 169 } 170 171 // Stat implements kernfs.Inode.Stat. 172 func (i *subtasksInode) Stat(ctx context.Context, vsfs *vfs.Filesystem, opts vfs.StatOptions) (linux.Statx, error) { 173 stat, err := i.InodeAttrs.Stat(ctx, vsfs, opts) 174 if err != nil { 175 return linux.Statx{}, err 176 } 177 if opts.Mask&linux.STATX_NLINK != 0 { 178 stat.Nlink += uint32(i.task.ThreadGroup().Count()) 179 } 180 return stat, nil 181 } 182 183 // SetStat implements kernfs.Inode.SetStat not allowing inode attributes to be changed. 184 func (*subtasksInode) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error { 185 return linuxerr.EPERM 186 } 187 188 // DecRef implements kernfs.Inode.DecRef. 189 func (i *subtasksInode) DecRef(ctx context.Context) { 190 i.subtasksInodeRefs.DecRef(func() { i.Destroy(ctx) }) 191 }