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  }