github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/proc/inode.go (about)

     1  // Copyright 2018 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  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    19  	"github.com/SagerNet/gvisor/pkg/context"
    20  	"github.com/SagerNet/gvisor/pkg/hostarch"
    21  	"github.com/SagerNet/gvisor/pkg/sentry/fs"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/fs/fsutil"
    23  	"github.com/SagerNet/gvisor/pkg/sentry/fs/proc/device"
    24  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    25  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/auth"
    26  	"github.com/SagerNet/gvisor/pkg/sentry/mm"
    27  )
    28  
    29  // LINT.IfChange
    30  
    31  // taskOwnedInodeOps wraps an fs.InodeOperations and overrides the UnstableAttr
    32  // method to return either the task or root as the owner, depending on the
    33  // task's dumpability.
    34  //
    35  // +stateify savable
    36  type taskOwnedInodeOps struct {
    37  	fs.InodeOperations
    38  
    39  	// t is the task that owns this file.
    40  	t *kernel.Task
    41  }
    42  
    43  // UnstableAttr implement fs.InodeOperations.UnstableAttr.
    44  func (i *taskOwnedInodeOps) UnstableAttr(ctx context.Context, inode *fs.Inode) (fs.UnstableAttr, error) {
    45  	uattr, err := i.InodeOperations.UnstableAttr(ctx, inode)
    46  	if err != nil {
    47  		return fs.UnstableAttr{}, err
    48  	}
    49  
    50  	// By default, set the task owner as the file owner.
    51  	creds := i.t.Credentials()
    52  	uattr.Owner = fs.FileOwner{creds.EffectiveKUID, creds.EffectiveKGID}
    53  
    54  	// Linux doesn't apply dumpability adjustments to world
    55  	// readable/executable directories so that applications can stat
    56  	// /proc/PID to determine the effective UID of a process. See
    57  	// fs/proc/base.c:task_dump_owner.
    58  	if fs.IsDir(inode.StableAttr) && uattr.Perms == fs.FilePermsFromMode(0555) {
    59  		return uattr, nil
    60  	}
    61  
    62  	// If the task is not dumpable, then root (in the namespace preferred)
    63  	// owns the file.
    64  	var m *mm.MemoryManager
    65  	i.t.WithMuLocked(func(t *kernel.Task) {
    66  		m = t.MemoryManager()
    67  	})
    68  
    69  	if m == nil {
    70  		uattr.Owner.UID = auth.RootKUID
    71  		uattr.Owner.GID = auth.RootKGID
    72  	} else if m.Dumpability() != mm.UserDumpable {
    73  		if kuid := creds.UserNamespace.MapToKUID(auth.RootUID); kuid.Ok() {
    74  			uattr.Owner.UID = kuid
    75  		} else {
    76  			uattr.Owner.UID = auth.RootKUID
    77  		}
    78  		if kgid := creds.UserNamespace.MapToKGID(auth.RootGID); kgid.Ok() {
    79  			uattr.Owner.GID = kgid
    80  		} else {
    81  			uattr.Owner.GID = auth.RootKGID
    82  		}
    83  	}
    84  
    85  	return uattr, nil
    86  }
    87  
    88  // staticFileInodeOps is an InodeOperations implementation that can be used to
    89  // return file contents which are constant. This file is not writable and will
    90  // always have mode 0444.
    91  //
    92  // +stateify savable
    93  type staticFileInodeOps struct {
    94  	fsutil.InodeDenyWriteChecker     `state:"nosave"`
    95  	fsutil.InodeNoExtendedAttributes `state:"nosave"`
    96  	fsutil.InodeNoopAllocate         `state:"nosave"`
    97  	fsutil.InodeNoopRelease          `state:"nosave"`
    98  	fsutil.InodeNoopTruncate         `state:"nosave"`
    99  	fsutil.InodeNoopWriteOut         `state:"nosave"`
   100  	fsutil.InodeNotDirectory         `state:"nosave"`
   101  	fsutil.InodeNotMappable          `state:"nosave"`
   102  	fsutil.InodeNotSocket            `state:"nosave"`
   103  	fsutil.InodeNotSymlink           `state:"nosave"`
   104  	fsutil.InodeVirtual              `state:"nosave"`
   105  
   106  	fsutil.InodeSimpleAttributes
   107  	fsutil.InodeStaticFileGetter
   108  }
   109  
   110  var _ fs.InodeOperations = (*staticFileInodeOps)(nil)
   111  
   112  // newStaticFileInode returns a procfs InodeOperations with static contents.
   113  func newStaticProcInode(ctx context.Context, msrc *fs.MountSource, contents []byte) *fs.Inode {
   114  	iops := &staticFileInodeOps{
   115  		InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, fs.RootOwner, fs.FilePermsFromMode(0444), linux.PROC_SUPER_MAGIC),
   116  		InodeStaticFileGetter: fsutil.InodeStaticFileGetter{
   117  			Contents: contents,
   118  		},
   119  	}
   120  	return newProcInode(ctx, iops, msrc, fs.SpecialFile, nil)
   121  }
   122  
   123  // newProcInode creates a new inode from the given inode operations.
   124  func newProcInode(ctx context.Context, iops fs.InodeOperations, msrc *fs.MountSource, typ fs.InodeType, t *kernel.Task) *fs.Inode {
   125  	sattr := fs.StableAttr{
   126  		DeviceID:  device.ProcDevice.DeviceID(),
   127  		InodeID:   device.ProcDevice.NextIno(),
   128  		BlockSize: hostarch.PageSize,
   129  		Type:      typ,
   130  	}
   131  	if t != nil {
   132  		iops = &taskOwnedInodeOps{iops, t}
   133  	}
   134  	return fs.NewInode(ctx, iops, msrc, sattr)
   135  }
   136  
   137  // LINT.ThenChange(../../fsimpl/proc/tasks.go)