github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/kernel/auth/credentials.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 auth 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/abi/linux" 19 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 20 ) 21 22 // Credentials contains information required to authorize privileged operations 23 // in a user namespace. 24 // 25 // +stateify savable 26 type Credentials struct { 27 // Real/effective/saved user/group IDs in the root user namespace. None of 28 // these should ever be NoID. 29 RealKUID KUID 30 EffectiveKUID KUID 31 SavedKUID KUID 32 RealKGID KGID 33 EffectiveKGID KGID 34 SavedKGID KGID 35 36 // Filesystem user/group IDs are not implemented. "... setfsuid() is 37 // nowadays unneeded and should be avoided in new applications (likewise 38 // for setfsgid(2))." - setfsuid(2) 39 40 // Supplementary groups used by set/getgroups. 41 // 42 // ExtraKGIDs slices are immutable, allowing multiple Credentials with the 43 // same ExtraKGIDs to share the same slice. 44 ExtraKGIDs []KGID 45 46 // The capability sets applicable to this set of credentials. 47 PermittedCaps CapabilitySet 48 InheritableCaps CapabilitySet 49 EffectiveCaps CapabilitySet 50 BoundingCaps CapabilitySet 51 // Ambient capabilities are not introduced until Linux 4.3. 52 53 // KeepCaps is the flag for PR_SET_KEEPCAPS which allow capabilities to be 54 // maintained after a switch from root user to non-root user via setuid(). 55 KeepCaps bool 56 57 // The user namespace associated with the owner of the credentials. 58 UserNamespace *UserNamespace 59 } 60 61 // NewAnonymousCredentials returns a set of credentials with no capabilities in 62 // any user namespace. 63 func NewAnonymousCredentials() *Credentials { 64 // Create a new root user namespace. Since the new namespace's owner is 65 // KUID 0 and the returned credentials have non-zero KUID/KGID, the 66 // returned credentials do not have any capabilities in the new namespace. 67 // Since the new namespace is not part of any existing user namespace 68 // hierarchy, the returned credentials do not have any capabilities in any 69 // other namespace. 70 return &Credentials{ 71 RealKUID: NobodyKUID, 72 EffectiveKUID: NobodyKUID, 73 SavedKUID: NobodyKUID, 74 RealKGID: NobodyKGID, 75 EffectiveKGID: NobodyKGID, 76 SavedKGID: NobodyKGID, 77 UserNamespace: NewRootUserNamespace(), 78 } 79 } 80 81 // NewRootCredentials returns a set of credentials with KUID and KGID 0 (i.e. 82 // global root) in user namespace ns. 83 func NewRootCredentials(ns *UserNamespace) *Credentials { 84 // I can't find documentation for this anywhere, but it's correct for the 85 // inheritable capability set to be initially empty (the capabilities test 86 // checks for this property). 87 return &Credentials{ 88 RealKUID: RootKUID, 89 EffectiveKUID: RootKUID, 90 SavedKUID: RootKUID, 91 RealKGID: RootKGID, 92 EffectiveKGID: RootKGID, 93 SavedKGID: RootKGID, 94 PermittedCaps: AllCapabilities, 95 EffectiveCaps: AllCapabilities, 96 BoundingCaps: AllCapabilities, 97 UserNamespace: ns, 98 } 99 } 100 101 // NewUserCredentials returns a set of credentials based on the given UID, GIDs, 102 // and capabilities in a given namespace. If all arguments are their zero 103 // values, this returns the same credentials as NewRootCredentials. 104 func NewUserCredentials(kuid KUID, kgid KGID, extraKGIDs []KGID, capabilities *TaskCapabilities, ns *UserNamespace) *Credentials { 105 creds := NewRootCredentials(ns) 106 107 // Set the UID. 108 uid := kuid 109 creds.RealKUID = uid 110 creds.EffectiveKUID = uid 111 creds.SavedKUID = uid 112 113 // Set GID. 114 gid := kgid 115 creds.RealKGID = gid 116 creds.EffectiveKGID = gid 117 creds.SavedKGID = gid 118 119 // Set additional GIDs. 120 creds.ExtraKGIDs = append(creds.ExtraKGIDs, extraKGIDs...) 121 122 // Set capabilities. 123 if capabilities != nil { 124 creds.PermittedCaps = capabilities.PermittedCaps 125 creds.EffectiveCaps = capabilities.EffectiveCaps 126 creds.BoundingCaps = capabilities.BoundingCaps 127 creds.InheritableCaps = capabilities.InheritableCaps 128 // TODO(github.com/SagerNet/issue/3166): Support ambient capabilities. 129 } else { 130 // If no capabilities are specified, grant capabilities consistent with 131 // setresuid + setresgid from NewRootCredentials to the given uid and 132 // gid. 133 if kuid == RootKUID { 134 creds.PermittedCaps = AllCapabilities 135 creds.EffectiveCaps = AllCapabilities 136 } else { 137 creds.PermittedCaps = 0 138 creds.EffectiveCaps = 0 139 } 140 creds.BoundingCaps = AllCapabilities 141 } 142 143 return creds 144 } 145 146 // Fork generates an identical copy of a set of credentials. 147 func (c *Credentials) Fork() *Credentials { 148 nc := new(Credentials) 149 *nc = *c // Copy-by-value; this is legal for all fields. 150 return nc 151 } 152 153 // InGroup returns true if c is in group kgid. Compare Linux's 154 // kernel/groups.c:in_group_p(). 155 func (c *Credentials) InGroup(kgid KGID) bool { 156 if c.EffectiveKGID == kgid { 157 return true 158 } 159 for _, extraKGID := range c.ExtraKGIDs { 160 if extraKGID == kgid { 161 return true 162 } 163 } 164 return false 165 } 166 167 // HasCapabilityIn returns true if c has capability cp in ns. 168 func (c *Credentials) HasCapabilityIn(cp linux.Capability, ns *UserNamespace) bool { 169 for { 170 // "1. A process has a capability inside a user namespace if it is a member 171 // of that namespace and it has the capability in its effective capability 172 // set." - user_namespaces(7) 173 if c.UserNamespace == ns { 174 return CapabilitySetOf(cp)&c.EffectiveCaps != 0 175 } 176 // "3. ... A process that resides in the parent of the user namespace and 177 // whose effective user ID matches the owner of the namespace has all 178 // capabilities in the namespace." 179 if c.UserNamespace == ns.parent && c.EffectiveKUID == ns.owner { 180 return true 181 } 182 // "2. If a process has a capability in a user namespace, then it has that 183 // capability in all child (and further removed descendant) namespaces as 184 // well." 185 if ns.parent == nil { 186 return false 187 } 188 ns = ns.parent 189 } 190 } 191 192 // HasCapability returns true if c has capability cp in its user namespace. 193 func (c *Credentials) HasCapability(cp linux.Capability) bool { 194 return c.HasCapabilityIn(cp, c.UserNamespace) 195 } 196 197 // UseUID checks that c can use uid in its user namespace, then translates it 198 // to the root user namespace. 199 // 200 // The checks UseUID does are common, but you should verify that it's doing 201 // exactly what you want. 202 func (c *Credentials) UseUID(uid UID) (KUID, error) { 203 // uid must be mapped. 204 kuid := c.UserNamespace.MapToKUID(uid) 205 if !kuid.Ok() { 206 return NoID, linuxerr.EINVAL 207 } 208 // If c has CAP_SETUID, then it can use any UID in its user namespace. 209 if c.HasCapability(linux.CAP_SETUID) { 210 return kuid, nil 211 } 212 // Otherwise, c must already have the UID as its real, effective, or saved 213 // set-user-ID. 214 if kuid == c.RealKUID || kuid == c.EffectiveKUID || kuid == c.SavedKUID { 215 return kuid, nil 216 } 217 return NoID, linuxerr.EPERM 218 } 219 220 // UseGID checks that c can use gid in its user namespace, then translates it 221 // to the root user namespace. 222 func (c *Credentials) UseGID(gid GID) (KGID, error) { 223 kgid := c.UserNamespace.MapToKGID(gid) 224 if !kgid.Ok() { 225 return NoID, linuxerr.EINVAL 226 } 227 if c.HasCapability(linux.CAP_SETGID) { 228 return kgid, nil 229 } 230 if kgid == c.RealKGID || kgid == c.EffectiveKGID || kgid == c.SavedKGID { 231 return kgid, nil 232 } 233 return NoID, linuxerr.EPERM 234 } 235 236 // SetUID translates the provided uid to the root user namespace and updates c's 237 // uids to it. This performs no permissions or capabilities checks, the caller 238 // is responsible for ensuring the calling context is permitted to modify c. 239 func (c *Credentials) SetUID(uid UID) error { 240 kuid := c.UserNamespace.MapToKUID(uid) 241 if !kuid.Ok() { 242 return linuxerr.EINVAL 243 } 244 c.RealKUID = kuid 245 c.EffectiveKUID = kuid 246 c.SavedKUID = kuid 247 return nil 248 } 249 250 // SetGID translates the provided gid to the root user namespace and updates c's 251 // gids to it. This performs no permissions or capabilities checks, the caller 252 // is responsible for ensuring the calling context is permitted to modify c. 253 func (c *Credentials) SetGID(gid GID) error { 254 kgid := c.UserNamespace.MapToKGID(gid) 255 if !kgid.Ok() { 256 return linuxerr.EINVAL 257 } 258 c.RealKGID = kgid 259 c.EffectiveKGID = kgid 260 c.SavedKGID = kgid 261 return nil 262 }