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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
// 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
import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/vfs"
)
// Registry is similar to Object, but for registries. It represent an abstract
// SysV IPC registry with fields common to all SysV registries. Registry is not
// thread-safe, and should be protected using a mutex.
//
// +stateify savable
type Registry struct {
// UserNS owning the IPC namespace this registry belongs to. Immutable.
UserNS *auth.UserNamespace
// objects is a map of IDs to IPC mechanisms.
objects map[ID]Mechanism
// KeysToIDs maps a lookup key to an ID.
keysToIDs map[Key]ID
// lastIDUsed is used to find the next available ID for object creation.
lastIDUsed ID
}
// NewRegistry return a new, initialized ipc.Registry.
func NewRegistry(userNS *auth.UserNamespace) *Registry {
return &Registry{
UserNS: userNS,
objects: make(map[ID]Mechanism),
keysToIDs: make(map[Key]ID),
}
}
// Find uses key to search for and return a SysV mechanism. Find returns an
// error if an object is found by shouldn't be, or if the user doesn't have
// permission to use the object. If no object is found, Find checks create
// flag, and returns an error only if it's false.
func (r *Registry) Find(ctx context.Context, key Key, mode linux.FileMode, create, exclusive bool) (Mechanism, error) {
if id, ok := r.keysToIDs[key]; ok {
mech := r.objects[id]
mech.Lock()
defer mech.Unlock()
obj := mech.Object()
creds := auth.CredentialsFromContext(ctx)
if !obj.CheckPermissions(creds, vfs.AccessTypes(mode&linux.ModeOtherAll)) {
// The [calling process / user] does not have permission to access
// the set, and does not have the CAP_IPC_OWNER capability in the
// user namespace that governs its IPC namespace.
return nil, linuxerr.EACCES
}
if create && exclusive {
// IPC_CREAT and IPC_EXCL were specified, but an object already
// exists for key.
return nil, linuxerr.EEXIST
}
return mech, nil
}
if !create {
// No object exists for key and msgflg did not specify IPC_CREAT.
return nil, linuxerr.ENOENT
}
return nil, nil
}
// Register adds the given object into Registry.Objects, and assigns it a new
// ID. It returns an error if all IDs are exhausted.
func (r *Registry) Register(m Mechanism) error {
id, err := r.newID()
if err != nil {
return err
}
obj := m.Object()
obj.ID = id
r.objects[id] = m
r.keysToIDs[obj.Key] = id
return nil
}
// newID finds the first unused ID in the registry, and returns an error if
// non is found.
func (r *Registry) newID() (ID, error) {
// Find the next available ID.
for id := r.lastIDUsed + 1; id != r.lastIDUsed; id++ {
// Handle wrap around.
if id < 0 {
id = 0
continue
}
if r.objects[id] == nil {
r.lastIDUsed = id
return id, nil
}
}
log.Warningf("ids exhausted, they may be leaking")
// The man pages for shmget(2) mention that ENOSPC should be used if "All
// possible shared memory IDs have been taken (SHMMNI)". Other SysV
// mechanisms don't have a specific errno for running out of IDs, but they
// return ENOSPC if the max number of objects is exceeded, so we assume that
// it's the same case.
return 0, linuxerr.ENOSPC
}
// Remove removes the mechanism with the given id from the registry, and calls
// mechanism.Destroy to perform mechanism-specific removal.
func (r *Registry) Remove(id ID, creds *auth.Credentials) error {
mech := r.objects[id]
if mech == nil {
return linuxerr.EINVAL
}
mech.Lock()
defer mech.Unlock()
obj := mech.Object()
// The effective user ID of the calling process must match the creator or
// owner of the [mechanism], or the caller must be privileged.
if !obj.CheckOwnership(creds) {
return linuxerr.EPERM
}
delete(r.objects, obj.ID)
delete(r.keysToIDs, obj.Key)
mech.Destroy()
return nil
}
// ForAllObjects executes a given function for all given objects.
func (r *Registry) ForAllObjects(f func(o Mechanism)) {
for _, o := range r.objects {
f(o)
}
}
// FindByID returns the mechanism with the given ID, nil if non exists.
func (r *Registry) FindByID(id ID) Mechanism {
return r.objects[id]
}
// DissociateKey removes the association between a mechanism and its key
// (deletes it from r.keysToIDs), preventing it from being discovered by any new
// process, but not necessarily destroying it. If the given key doesn't exist,
// nothing is changed.
func (r *Registry) DissociateKey(key Key) {
delete(r.keysToIDs, key)
}
// DissociateID removes the association between a mechanism and its ID (deletes
// it from r.objects). An ID can't be removed unless the associated key is
// removed already, this is done to prevent the users from acquiring nil a
// Mechanism.
//
// Precondition: must be preceded by a call to r.DissociateKey.
func (r *Registry) DissociateID(id ID) {
delete(r.objects, id)
}
// ObjectCount returns the number of registered objects.
func (r *Registry) ObjectCount() int {
return len(r.objects)
}
// LastIDUsed returns the last used ID.
func (r *Registry) LastIDUsed() ID {
return r.lastIDUsed
}
|