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