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