github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/kernel/ipc/object.go (about)

     1  // Copyright 2021 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 ipc defines functionality and utilities common to sysvipc mechanisms.
    16  //
    17  // Lock ordering: [shm/semaphore/msgqueue].Registry.mu -> Mechanism
    18  package ipc
    19  
    20  import (
    21  	"github.com/metacubex/gvisor/pkg/abi/linux"
    22  	"github.com/metacubex/gvisor/pkg/context"
    23  	"github.com/metacubex/gvisor/pkg/errors/linuxerr"
    24  	"github.com/metacubex/gvisor/pkg/sentry/kernel/auth"
    25  	"github.com/metacubex/gvisor/pkg/sentry/vfs"
    26  )
    27  
    28  // Key is a user-provided identifier for IPC objects.
    29  type Key int32
    30  
    31  // ID is a kernel identifier for IPC objects.
    32  type ID int32
    33  
    34  // Object represents an abstract IPC object with fields common to all IPC
    35  // mechanisms.
    36  //
    37  // +stateify savable
    38  type Object struct {
    39  	// User namespace which owns the IPC namespace which owns the IPC object.
    40  	// Immutable.
    41  	UserNS *auth.UserNamespace
    42  
    43  	// ID is a kernel identifier for the IPC object. Immutable.
    44  	ID ID
    45  
    46  	// Key is a user-provided identifier for the IPC object. Immutable.
    47  	Key Key
    48  
    49  	// CreatorUID is the UID of user who created the IPC object. Immutable.
    50  	CreatorUID auth.KUID
    51  
    52  	// CreatorGID is the GID of user who created the IPC object. Immutable.
    53  	CreatorGID auth.KGID
    54  
    55  	// OwnerUID is the UID of the current owner of the IPC object. Immutable.
    56  	OwnerUID auth.KUID
    57  
    58  	// OwnerGID is the GID of the current owner of the IPC object. Immutable.
    59  	OwnerGID auth.KGID
    60  
    61  	// Mode is the access permissions the IPC object.
    62  	Mode linux.FileMode
    63  }
    64  
    65  // Mechanism represents a SysV mechanism that holds an IPC object. It can also
    66  // be looked at as a container for an ipc.Object, which is by definition a fully
    67  // functional SysV object.
    68  type Mechanism interface {
    69  	// Lock behaves the same as Mutex.Lock on the mechanism.
    70  	Lock()
    71  
    72  	// Unlock behaves the same as Mutex.Unlock on the mechanism.
    73  	Unlock()
    74  
    75  	// Object returns a pointer to the mechanism's ipc.Object. Mechanism.Lock,
    76  	// and Mechanism.Unlock should be used when the object is used.
    77  	Object() *Object
    78  
    79  	// Destroy destroys the mechanism.
    80  	Destroy()
    81  }
    82  
    83  // NewObject returns a new, initialized ipc.Object. The newly returned object
    84  // doesn't have a valid ID. When the object is registered, the registry assigns
    85  // it a new unique ID.
    86  func NewObject(un *auth.UserNamespace, key Key, creator, owner *auth.Credentials, mode linux.FileMode) *Object {
    87  	return &Object{
    88  		UserNS:     un,
    89  		Key:        key,
    90  		CreatorUID: creator.EffectiveKUID,
    91  		CreatorGID: creator.EffectiveKGID,
    92  		OwnerUID:   owner.EffectiveKUID,
    93  		OwnerGID:   owner.EffectiveKGID,
    94  		Mode:       mode,
    95  	}
    96  }
    97  
    98  // CheckOwnership verifies whether an IPC object may be accessed using creds as
    99  // an owner. See ipc/util.c:ipcctl_obtain_check() in Linux.
   100  func (o *Object) CheckOwnership(creds *auth.Credentials) bool {
   101  	if o.OwnerUID == creds.EffectiveKUID || o.CreatorUID == creds.EffectiveKUID {
   102  		return true
   103  	}
   104  
   105  	// Tasks with CAP_SYS_ADMIN may bypass ownership checks. Strangely, Linux
   106  	// doesn't use CAP_IPC_OWNER for this despite CAP_IPC_OWNER being documented
   107  	// for use to "override IPC ownership checks".
   108  	return creds.HasCapabilityIn(linux.CAP_SYS_ADMIN, o.UserNS)
   109  }
   110  
   111  // CheckPermissions verifies whether an IPC object is accessible using creds for
   112  // access described by req. See ipc/util.c:ipcperms() in Linux.
   113  func (o *Object) CheckPermissions(creds *auth.Credentials, req vfs.AccessTypes) bool {
   114  	perms := uint16(o.Mode.Permissions())
   115  	if o.OwnerUID == creds.EffectiveKUID {
   116  		perms >>= 6
   117  	} else if creds.InGroup(o.OwnerGID) {
   118  		perms >>= 3
   119  	}
   120  
   121  	if uint16(req)&perms == uint16(req) {
   122  		return true
   123  	}
   124  	return creds.HasCapabilityIn(linux.CAP_IPC_OWNER, o.UserNS)
   125  }
   126  
   127  // Set modifies attributes for an IPC object. See *ctl(IPC_SET).
   128  //
   129  // Precondition: Mechanism.mu must be held.
   130  func (o *Object) Set(ctx context.Context, perm *linux.IPCPerm) error {
   131  	creds := auth.CredentialsFromContext(ctx)
   132  	uid := creds.UserNamespace.MapToKUID(auth.UID(perm.UID))
   133  	gid := creds.UserNamespace.MapToKGID(auth.GID(perm.GID))
   134  	if !uid.Ok() || !gid.Ok() {
   135  		// The man pages don't specify an errno for invalid uid/gid, but EINVAL
   136  		// is generally used for invalid arguments.
   137  		return linuxerr.EINVAL
   138  	}
   139  
   140  	if !o.CheckOwnership(creds) {
   141  		// "The argument cmd has the value IPC_SET or IPC_RMID, but the
   142  		//  effective user ID of the calling process is not the creator (as
   143  		//  found in msg_perm.cuid) or the owner (as found in msg_perm.uid)
   144  		//  of the message queue, and the caller is not privileged (Linux:
   145  		//  does not have the CAP_SYS_ADMIN capability)."
   146  		return linuxerr.EPERM
   147  	}
   148  
   149  	// User may only modify the lower 9 bits of the mode. All the other bits are
   150  	// always 0 for the underlying inode.
   151  	mode := linux.FileMode(perm.Mode & 0x1ff)
   152  
   153  	o.Mode = mode
   154  	o.OwnerUID = uid
   155  	o.OwnerGID = gid
   156  
   157  	return nil
   158  }