mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
80d7bfd54d
- Add support for exact list of capabilities, support only OCI model - Support OCI model on CapAdd and CapDrop but remain backward compatibility - Create variable locally instead of declaring it at the top - Use const for magic "ALL" value - Rename `cap` variable as it overlaps with `cap()` built-in - Normalize and validate capabilities before use - Move validation for conflicting options to validateHostConfig() - TweakCapabilities: simplify logic to calculate capabilities Signed-off-by: Olli Janatuinen <olli.janatuinen@gmail.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
169 lines
4.3 KiB
Go
169 lines
4.3 KiB
Go
package caps // import "github.com/docker/docker/oci/caps"
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/docker/docker/errdefs"
|
|
"github.com/syndtr/gocapability/capability"
|
|
)
|
|
|
|
var capabilityList Capabilities
|
|
|
|
func init() {
|
|
last := capability.CAP_LAST_CAP
|
|
// hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
|
|
if last == capability.Cap(63) {
|
|
last = capability.CAP_BLOCK_SUSPEND
|
|
}
|
|
for _, cap := range capability.List() {
|
|
if cap > last {
|
|
continue
|
|
}
|
|
capabilityList = append(capabilityList,
|
|
&CapabilityMapping{
|
|
Key: "CAP_" + strings.ToUpper(cap.String()),
|
|
Value: cap,
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
type (
|
|
// CapabilityMapping maps linux capability name to its value of capability.Cap type
|
|
// Capabilities is one of the security systems in Linux Security Module (LSM)
|
|
// framework provided by the kernel.
|
|
// For more details on capabilities, see http://man7.org/linux/man-pages/man7/capabilities.7.html
|
|
CapabilityMapping struct {
|
|
Key string `json:"key,omitempty"`
|
|
Value capability.Cap `json:"value,omitempty"`
|
|
}
|
|
// Capabilities contains all CapabilityMapping
|
|
Capabilities []*CapabilityMapping
|
|
)
|
|
|
|
// String returns <key> of CapabilityMapping
|
|
func (c *CapabilityMapping) String() string {
|
|
return c.Key
|
|
}
|
|
|
|
// GetCapability returns CapabilityMapping which contains specific key
|
|
func GetCapability(key string) *CapabilityMapping {
|
|
for _, capp := range capabilityList {
|
|
if capp.Key == key {
|
|
cpy := *capp
|
|
return &cpy
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetAllCapabilities returns all of the capabilities
|
|
func GetAllCapabilities() []string {
|
|
output := make([]string, len(capabilityList))
|
|
for i, capability := range capabilityList {
|
|
output[i] = capability.String()
|
|
}
|
|
return output
|
|
}
|
|
|
|
// inSlice tests whether a string is contained in a slice of strings or not.
|
|
func inSlice(slice []string, s string) bool {
|
|
for _, ss := range slice {
|
|
if s == ss {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
const allCapabilities = "ALL"
|
|
|
|
// NormalizeLegacyCapabilities normalizes, and validates CapAdd/CapDrop capabilities
|
|
// by upper-casing them, and adding a CAP_ prefix (if not yet present).
|
|
//
|
|
// This function also accepts the "ALL" magic-value, that's used by CapAdd/CapDrop.
|
|
func NormalizeLegacyCapabilities(caps []string) ([]string, error) {
|
|
var normalized []string
|
|
|
|
valids := GetAllCapabilities()
|
|
for _, c := range caps {
|
|
c = strings.ToUpper(c)
|
|
if c == allCapabilities {
|
|
normalized = append(normalized, c)
|
|
continue
|
|
}
|
|
if !strings.HasPrefix(c, "CAP_") {
|
|
c = "CAP_" + c
|
|
}
|
|
if !inSlice(valids, c) {
|
|
return nil, errdefs.InvalidParameter(fmt.Errorf("unknown capability: %q", c))
|
|
}
|
|
normalized = append(normalized, c)
|
|
}
|
|
return normalized, nil
|
|
}
|
|
|
|
// ValidateCapabilities validates if caps only contains valid capabilities
|
|
func ValidateCapabilities(caps []string) error {
|
|
valids := GetAllCapabilities()
|
|
for _, c := range caps {
|
|
if !inSlice(valids, c) {
|
|
return errdefs.InvalidParameter(fmt.Errorf("unknown capability: %q", c))
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TweakCapabilities tweaks capabilities by adding, dropping, or overriding
|
|
// capabilities in the basics capabilities list.
|
|
func TweakCapabilities(basics, adds, drops, capabilities []string, privileged bool) ([]string, error) {
|
|
switch {
|
|
case privileged:
|
|
// Privileged containers get all capabilities
|
|
return GetAllCapabilities(), nil
|
|
case capabilities != nil:
|
|
// Use custom set of capabilities
|
|
if err := ValidateCapabilities(capabilities); err != nil {
|
|
return nil, err
|
|
}
|
|
return capabilities, nil
|
|
case len(adds) == 0 && len(drops) == 0:
|
|
// Nothing to tweak; we're done
|
|
return basics, nil
|
|
}
|
|
|
|
capDrop, err := NormalizeLegacyCapabilities(drops)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
capAdd, err := NormalizeLegacyCapabilities(adds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var caps []string
|
|
|
|
switch {
|
|
case inSlice(capAdd, allCapabilities):
|
|
// Add all capabilities except ones on capDrop
|
|
for _, c := range GetAllCapabilities() {
|
|
if !inSlice(capDrop, c) {
|
|
caps = append(caps, c)
|
|
}
|
|
}
|
|
case inSlice(capDrop, allCapabilities):
|
|
// "Drop" all capabilities; use what's in capAdd instead
|
|
caps = capAdd
|
|
default:
|
|
// First drop some capabilities
|
|
for _, c := range basics {
|
|
if !inSlice(capDrop, c) {
|
|
caps = append(caps, c)
|
|
}
|
|
}
|
|
// Then add the list of capabilities from capAdd
|
|
caps = append(caps, capAdd...)
|
|
}
|
|
return caps, nil
|
|
}
|