summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/kernel/ipc/object.go
blob: facd157c7403c5fc335cbab1ba537ee232ffcad4 (plain)
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
// 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/fs"
	"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
)

// 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

	// Creator is the user who created the IPC object. Immutable.
	Creator fs.FileOwner

	// Owner is the current owner of the IPC object.
	Owner fs.FileOwner

	// Perms is the access permissions the IPC object.
	Perms fs.FilePermissions
}

// 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 fs.FileOwner, perms fs.FilePermissions) *Object {
	return &Object{
		UserNS:  un,
		Key:     key,
		Creator: creator,
		Owner:   owner,
		Perms:   perms,
	}
}

// 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.Owner.UID == creds.EffectiveKUID || o.Creator.UID == 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 fs.PermMask) bool {
	p := o.Perms.Other
	if o.Owner.UID == creds.EffectiveKUID {
		p = o.Perms.User
	} else if creds.InGroup(o.Owner.GID) {
		p = o.Perms.Group
	}

	if p.SupersetOf(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.Perms = fs.FilePermsFromMode(mode)
	o.Owner.UID = uid
	o.Owner.GID = gid

	return nil
}