github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/context.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 fs 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/abi/linux" 19 "github.com/SagerNet/gvisor/pkg/context" 20 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 21 ) 22 23 // contextID is the fs package's type for context.Context.Value keys. 24 type contextID int 25 26 const ( 27 // CtxRoot is a Context.Value key for a Dirent. 28 CtxRoot contextID = iota 29 30 // CtxDirentCacheLimiter is a Context.Value key for DirentCacheLimiter. 31 CtxDirentCacheLimiter 32 ) 33 34 // ContextCanAccessFile determines whether `file` can be accessed in the requested way 35 // (for reading, writing, or execution) using the caller's credentials and user 36 // namespace, as does Linux's fs/namei.c:generic_permission. 37 func ContextCanAccessFile(ctx context.Context, inode *Inode, reqPerms PermMask) bool { 38 creds := auth.CredentialsFromContext(ctx) 39 uattr, err := inode.UnstableAttr(ctx) 40 if err != nil { 41 return false 42 } 43 44 p := uattr.Perms.Other 45 // Are we owner or in group? 46 if uattr.Owner.UID == creds.EffectiveKUID { 47 p = uattr.Perms.User 48 } else if creds.InGroup(uattr.Owner.GID) { 49 p = uattr.Perms.Group 50 } 51 52 // Do not allow programs to be executed if MS_NOEXEC is set. 53 if IsFile(inode.StableAttr) && reqPerms.Execute && inode.MountSource.Flags.NoExec { 54 return false 55 } 56 57 // Are permissions satisfied without capability checks? 58 if p.SupersetOf(reqPerms) { 59 return true 60 } 61 62 if IsDir(inode.StableAttr) { 63 // CAP_DAC_OVERRIDE can override any perms on directories. 64 if inode.CheckCapability(ctx, linux.CAP_DAC_OVERRIDE) { 65 return true 66 } 67 68 // CAP_DAC_READ_SEARCH can normally only override Read perms, 69 // but for directories it can also override execution. 70 if !reqPerms.Write && inode.CheckCapability(ctx, linux.CAP_DAC_READ_SEARCH) { 71 return true 72 } 73 } 74 75 // CAP_DAC_OVERRIDE can always override Read/Write. 76 // Can override executable only when at least one execute bit is set. 77 if !reqPerms.Execute || uattr.Perms.AnyExecute() { 78 if inode.CheckCapability(ctx, linux.CAP_DAC_OVERRIDE) { 79 return true 80 } 81 } 82 83 // Read perms can be overridden by CAP_DAC_READ_SEARCH. 84 if reqPerms.OnlyRead() && inode.CheckCapability(ctx, linux.CAP_DAC_READ_SEARCH) { 85 return true 86 } 87 return false 88 } 89 90 // FileOwnerFromContext returns a FileOwner using the effective user and group 91 // IDs used by ctx. 92 func FileOwnerFromContext(ctx context.Context) FileOwner { 93 creds := auth.CredentialsFromContext(ctx) 94 return FileOwner{creds.EffectiveKUID, creds.EffectiveKGID} 95 } 96 97 // RootFromContext returns the root of the virtual filesystem observed by ctx, 98 // or nil if ctx is not associated with a virtual filesystem. If 99 // RootFromContext returns a non-nil fs.Dirent, a reference is taken on it. 100 func RootFromContext(ctx context.Context) *Dirent { 101 if v := ctx.Value(CtxRoot); v != nil { 102 return v.(*Dirent) 103 } 104 return nil 105 } 106 107 // DirentCacheLimiterFromContext returns the DirentCacheLimiter used by ctx, or 108 // nil if ctx does not have a dirent cache limiter. 109 func DirentCacheLimiterFromContext(ctx context.Context) *DirentCacheLimiter { 110 if v := ctx.Value(CtxDirentCacheLimiter); v != nil { 111 return v.(*DirentCacheLimiter) 112 } 113 return nil 114 } 115 116 type rootContext struct { 117 context.Context 118 root *Dirent 119 } 120 121 // WithRoot returns a copy of ctx with the given root. 122 func WithRoot(ctx context.Context, root *Dirent) context.Context { 123 return &rootContext{ 124 Context: ctx, 125 root: root, 126 } 127 } 128 129 // Value implements Context.Value. 130 func (rc rootContext) Value(key interface{}) interface{} { 131 switch key { 132 case CtxRoot: 133 rc.root.IncRef() 134 return rc.root 135 default: 136 return rc.Context.Value(key) 137 } 138 }