mirror of
https://github.com/containers/skopeo.git
synced 2025-08-25 09:39:03 +00:00
As the title says. In preparation of Skopeo v1.17.0 to go out with Podman v5.3, this gets the c/* projects to: containers/storage: v1.56.0 containers/image: v5.33.0 containers/common: v0.61.0 Signed-off-by: tomsweeneyredhat <tsweeney@redhat.com>
198 lines
4.7 KiB
Go
198 lines
4.7 KiB
Go
package capabilities
|
|
|
|
// Copyright 2013-2018 Docker, Inc.
|
|
|
|
// NOTE: this package has been copied from github.com/docker/docker but been
|
|
// changed significantly to fit the needs of libpod.
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/moby/sys/capability"
|
|
)
|
|
|
|
var (
|
|
// ErrUnknownCapability is thrown when an unknown capability is processed.
|
|
ErrUnknownCapability = errors.New("unknown capability")
|
|
|
|
// ContainerImageLabels - label can indicate the required
|
|
// capabilities required by containers to run the container image.
|
|
ContainerImageLabels = []string{"io.containers.capabilities"}
|
|
)
|
|
|
|
// All is a special value used to add/drop all known capabilities.
|
|
// Useful on the CLI for `--cap-add=all` etc.
|
|
const All = "ALL"
|
|
|
|
func capName(c capability.Cap) string {
|
|
return "CAP_" + strings.ToUpper(c.String())
|
|
}
|
|
|
|
// capStrList returns all capabilities supported by the currently running kernel,
|
|
// or an error if the list can not be obtained.
|
|
var capStrList = sync.OnceValues(func() ([]string, error) {
|
|
list, err := capability.ListSupported()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
caps := make([]string, len(list))
|
|
for i, c := range list {
|
|
caps[i] = capName(c)
|
|
}
|
|
slices.Sort(caps)
|
|
return caps, nil
|
|
})
|
|
|
|
// BoundingSet returns the capabilities in the current bounding set.
|
|
func BoundingSet() ([]string, error) {
|
|
return boundingSet()
|
|
}
|
|
|
|
var boundingSet = sync.OnceValues(func() ([]string, error) {
|
|
currentCaps, err := capability.NewPid2(0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = currentCaps.Load()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
list, err := capability.ListSupported()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var r []string
|
|
for _, c := range list {
|
|
if !currentCaps.Get(capability.BOUNDING, c) {
|
|
continue
|
|
}
|
|
r = append(r, capName(c))
|
|
}
|
|
slices.Sort(r)
|
|
return r, nil
|
|
})
|
|
|
|
// AllCapabilities returns all capabilities supported by the running kernel.
|
|
func AllCapabilities() []string {
|
|
list, _ := capStrList()
|
|
return list
|
|
}
|
|
|
|
// NormalizeCapabilities normalizes caps by adding a "CAP_" prefix (if not yet
|
|
// present).
|
|
func NormalizeCapabilities(caps []string) ([]string, error) {
|
|
all, err := capStrList()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
normalized := make([]string, 0, len(caps))
|
|
for _, c := range caps {
|
|
c = strings.ToUpper(c)
|
|
if c == All {
|
|
normalized = append(normalized, c)
|
|
continue
|
|
}
|
|
if !strings.HasPrefix(c, "CAP_") {
|
|
c = "CAP_" + c
|
|
}
|
|
if !slices.Contains(all, c) {
|
|
return nil, fmt.Errorf("%q: %w", c, ErrUnknownCapability)
|
|
}
|
|
normalized = append(normalized, c)
|
|
}
|
|
slices.Sort(normalized)
|
|
return normalized, nil
|
|
}
|
|
|
|
// ValidateCapabilities validates if caps only contains valid capabilities.
|
|
func ValidateCapabilities(caps []string) error {
|
|
all, err := capStrList()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, c := range caps {
|
|
if !slices.Contains(all, c) {
|
|
return fmt.Errorf("%q: %w", c, ErrUnknownCapability)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MergeCapabilities computes a set of capabilities by adding capabilities
|
|
// to or dropping them from base.
|
|
//
|
|
// Note that:
|
|
// "ALL" in capAdd adds returns known capabilities
|
|
// "All" in capDrop returns only the capabilities specified in capAdd
|
|
func MergeCapabilities(base, adds, drops []string) ([]string, error) {
|
|
// Normalize the base capabilities
|
|
base, err := NormalizeCapabilities(base)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(adds) == 0 && len(drops) == 0 {
|
|
// Nothing to tweak; we're done
|
|
return base, nil
|
|
}
|
|
capDrop, err := NormalizeCapabilities(drops)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
capAdd, err := NormalizeCapabilities(adds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if slices.Contains(capDrop, All) {
|
|
if slices.Contains(capAdd, All) {
|
|
return nil, errors.New("adding all caps and removing all caps not allowed")
|
|
}
|
|
// "Drop" all capabilities; return what's in capAdd instead
|
|
slices.Sort(capAdd)
|
|
return capAdd, nil
|
|
}
|
|
|
|
if slices.Contains(capAdd, All) {
|
|
base, err = BoundingSet()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
capAdd = []string{}
|
|
} else {
|
|
for _, add := range capAdd {
|
|
if slices.Contains(capDrop, add) {
|
|
return nil, fmt.Errorf("capability %q cannot be dropped and added", add)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, drop := range capDrop {
|
|
if slices.Contains(capAdd, drop) {
|
|
return nil, fmt.Errorf("capability %q cannot be dropped and added", drop)
|
|
}
|
|
}
|
|
|
|
caps := make([]string, 0, len(base)+len(capAdd))
|
|
// Drop any capabilities in capDrop that are in base
|
|
for _, cap := range base {
|
|
if slices.Contains(capDrop, cap) {
|
|
continue
|
|
}
|
|
caps = append(caps, cap)
|
|
}
|
|
|
|
// Add any capabilities in capAdd that are not in base
|
|
for _, cap := range capAdd {
|
|
if slices.Contains(base, cap) {
|
|
continue
|
|
}
|
|
caps = append(caps, cap)
|
|
}
|
|
slices.Sort(caps)
|
|
return caps, nil
|
|
}
|