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)