github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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/metacubex/gvisor/pkg/abi/linux"
    22  	"github.com/metacubex/gvisor/pkg/context"
    23  	"github.com/metacubex/gvisor/pkg/errors/linuxerr"
    24  	"github.com/metacubex/gvisor/pkg/sentry/fsimpl/kernfs"
    25  	"github.com/metacubex/gvisor/pkg/sentry/kernel"
    26  	"github.com/metacubex/gvisor/pkg/sentry/kernel/auth"
    27  	"github.com/metacubex/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  }