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 }