mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
88d35cd8f1
- Replace Add with TryInsertRange; for symmetry with RemoveRange, to establish
the convention that *Range methods perform an implicit search in the set, and
so that we can fork InsertRange which has Insert-like semantics (panics on
conflict), which the majority of callers want.
- Rename MergeRange and MergeAdjacent to MergeInsideRange and MergeOutsideRange
respectively; for the same convention, and to more clearly describe the
difference between these functions.
- Add MergePrev and MergeNext. These solve the longstanding problem of
requiring a separate call to Merge{Inside,Outside}Range (which will perform
additional searches) after mutating a set in a relatively simple manner.
- Add SplitBefore and SplitAfter, which are halves of Isolate. These are
slightly preferable to Isolate in many use cases for the latter (when
iterating segments within a range, only the first segment can include a key
before the start, so this saves some useless comparisons in almost every
iteration of such loops), and are useful in some more complex algorithms.
Also add LowerBoundSegmentSplitBefore and UpperBoundSegmentSplitAfter as
ergonomic aids for the former use case.
- Add {Visit,Mutate}[Full]Range, which are convenience wrappers around the
iterator API (including new functions) for simple use cases (and hence also
serve to demonstrate how the new iterator functions are used).
MutateFullRange in particular replaces ApplyContiguous and adds merging
during iteration.
- Add RemoveFullRange, which (analogous to {Visit,Mutate}FullRange) is a
variant of RemoveRange that checks that the range is fully covered by
segments.
- Add Unisolate, which combines MergePrev and MergeNext in the same way that
Isolate combines SplitBefore and SplitAfter. This is useful for merging after
mutation of a single segment.
- Add {First,Last,LowerBound,UpperBound}LargeEnoughGap, which are convenient
loop starters when using gap tracking.
- Replace SegmentDataSlices with FlatSegment, which is easier to use when
specifying "set literals" (as in tests).
- Make {prev,next}LargeEnoughGapHelper iterative rather than tail-recursive.
- Slightly optimize Iterator.{Prev,Next}NonEmpty: GapIterator.{Start,End} needs
to find the corresponding Iterator, so call Iterator.{Prev,Next}Segment
directly rather than doing so twice.
PiperOrigin-RevId: 583506148
134 lines
4.2 KiB
Go
134 lines
4.2 KiB
Go
// Copyright 2018 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 auth
|
|
|
|
import (
|
|
"math"
|
|
|
|
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
|
)
|
|
|
|
// A UserNamespace represents a user namespace. See user_namespaces(7) for
|
|
// details.
|
|
//
|
|
// +stateify savable
|
|
type UserNamespace struct {
|
|
// parent is this namespace's parent. If this is the root namespace, parent
|
|
// is nil. The parent pointer is immutable.
|
|
parent *UserNamespace
|
|
|
|
// owner is the effective UID of the namespace's creator in the root
|
|
// namespace. owner is immutable.
|
|
owner KUID
|
|
|
|
// Keys is the set of keys in this namespace.
|
|
Keys KeySet
|
|
|
|
// mu protects the following fields.
|
|
//
|
|
// If mu will be locked in multiple UserNamespaces, it must be locked in
|
|
// descendant namespaces before ancestors.
|
|
mu userNamespaceMutex `state:"nosave"`
|
|
|
|
// Mappings of user/group IDs between this namespace and its parent.
|
|
//
|
|
// All ID maps, once set, cannot be changed. This means that successful
|
|
// UID/GID translations cannot be racy.
|
|
uidMapFromParent idMapSet
|
|
uidMapToParent idMapSet
|
|
gidMapFromParent idMapSet
|
|
gidMapToParent idMapSet
|
|
|
|
// TODO(b/27454212): Support disabling setgroups(2).
|
|
}
|
|
|
|
// NewRootUserNamespace returns a UserNamespace that is appropriate for a
|
|
// system's root user namespace. Note that namespaces returned by separate calls
|
|
// to this function are *distinct* namespaces. Once a root namespace is created
|
|
// by this function, the returned value must be reused to refer to the same
|
|
// namespace.
|
|
func NewRootUserNamespace() *UserNamespace {
|
|
var ns UserNamespace
|
|
// """
|
|
// The initial user namespace has no parent namespace, but, for
|
|
// consistency, the kernel provides dummy user and group ID mapping files
|
|
// for this namespace. Looking at the uid_map file (gid_map is the same)
|
|
// from a shell in the initial namespace shows:
|
|
//
|
|
// $ cat /proc/$$/uid_map
|
|
// 0 0 4294967295
|
|
// """ - user_namespaces(7)
|
|
for _, m := range []*idMapSet{
|
|
&ns.uidMapFromParent,
|
|
&ns.uidMapToParent,
|
|
&ns.gidMapFromParent,
|
|
&ns.gidMapToParent,
|
|
} {
|
|
// Insertion into an empty map shouldn't fail.
|
|
m.InsertRange(idMapRange{0, math.MaxUint32}, 0)
|
|
}
|
|
return &ns
|
|
}
|
|
|
|
// Root returns the root of the user namespace tree containing ns.
|
|
func (ns *UserNamespace) Root() *UserNamespace {
|
|
for ns.parent != nil {
|
|
ns = ns.parent
|
|
}
|
|
return ns
|
|
}
|
|
|
|
// "The kernel imposes (since version 3.11) a limit of 32 nested levels of user
|
|
// namespaces." - user_namespaces(7)
|
|
const maxUserNamespaceDepth = 32
|
|
|
|
func (ns *UserNamespace) depth() int {
|
|
var i int
|
|
for ns != nil {
|
|
i++
|
|
ns = ns.parent
|
|
}
|
|
return i
|
|
}
|
|
|
|
// NewChildUserNamespace returns a new user namespace created by a caller with
|
|
// credentials c.
|
|
func (c *Credentials) NewChildUserNamespace() (*UserNamespace, error) {
|
|
if c.UserNamespace.depth() >= maxUserNamespaceDepth {
|
|
// "... Calls to unshare(2) or clone(2) that would cause this limit to
|
|
// be exceeded fail with the error EUSERS." - user_namespaces(7)
|
|
return nil, linuxerr.EUSERS
|
|
}
|
|
// "EPERM: CLONE_NEWUSER was specified in flags, but either the effective
|
|
// user ID or the effective group ID of the caller does not have a mapping
|
|
// in the parent namespace (see user_namespaces(7))." - clone(2)
|
|
// "CLONE_NEWUSER requires that the user ID and group ID of the calling
|
|
// process are mapped to user IDs and group IDs in the user namespace of
|
|
// the calling process at the time of the call." - unshare(2)
|
|
if !c.EffectiveKUID.In(c.UserNamespace).Ok() {
|
|
return nil, linuxerr.EPERM
|
|
}
|
|
if !c.EffectiveKGID.In(c.UserNamespace).Ok() {
|
|
return nil, linuxerr.EPERM
|
|
}
|
|
return &UserNamespace{
|
|
parent: c.UserNamespace,
|
|
owner: c.EffectiveKUID,
|
|
// "When a user namespace is created, it starts without a mapping of
|
|
// user IDs (group IDs) to the parent user namespace." -
|
|
// user_namespaces(7)
|
|
}, nil
|
|
}
|