|
@@ -4,6 +4,7 @@ import (
|
|
|
"fmt"
|
|
|
"strings"
|
|
|
|
|
|
+ "github.com/docker/docker/errdefs"
|
|
|
"github.com/syndtr/gocapability/capability"
|
|
|
)
|
|
|
|
|
@@ -67,73 +68,102 @@ func GetAllCapabilities() []string {
|
|
|
}
|
|
|
|
|
|
// inSlice tests whether a string is contained in a slice of strings or not.
|
|
|
-// Comparison is case insensitive
|
|
|
func inSlice(slice []string, s string) bool {
|
|
|
for _, ss := range slice {
|
|
|
- if strings.ToLower(s) == strings.ToLower(ss) {
|
|
|
+ if s == ss {
|
|
|
return true
|
|
|
}
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
|
|
|
-// TweakCapabilities can tweak capabilities by adding or dropping capabilities
|
|
|
-// based on the basics capabilities.
|
|
|
-func TweakCapabilities(basics, adds, drops []string) ([]string, error) {
|
|
|
- var (
|
|
|
- newCaps []string
|
|
|
- allCaps = GetAllCapabilities()
|
|
|
- )
|
|
|
+const allCapabilities = "ALL"
|
|
|
|
|
|
- // FIXME(tonistiigi): docker format is without CAP_ prefix, oci is with prefix
|
|
|
- // Currently they are mixed in here. We should do conversion in one place.
|
|
|
+// 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
|
|
|
|
|
|
- // look for invalid cap in the drop list
|
|
|
- for _, cap := range drops {
|
|
|
- if strings.ToLower(cap) == "all" {
|
|
|
+ valids := GetAllCapabilities()
|
|
|
+ for _, c := range caps {
|
|
|
+ c = strings.ToUpper(c)
|
|
|
+ if c == allCapabilities {
|
|
|
+ normalized = append(normalized, c)
|
|
|
continue
|
|
|
}
|
|
|
-
|
|
|
- if !inSlice(allCaps, "CAP_"+cap) {
|
|
|
- return nil, fmt.Errorf("Unknown capability drop: %q", cap)
|
|
|
+ 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
|
|
|
+}
|
|
|
|
|
|
- // handle --cap-add=all
|
|
|
- if inSlice(adds, "all") {
|
|
|
- basics = allCaps
|
|
|
+// 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
|
|
|
+}
|
|
|
|
|
|
- if !inSlice(drops, "all") {
|
|
|
- for _, cap := range basics {
|
|
|
- // skip `all` already handled above
|
|
|
- if strings.ToLower(cap) == "all" {
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- // if we don't drop `all`, add back all the non-dropped caps
|
|
|
- if !inSlice(drops, cap[4:]) {
|
|
|
- newCaps = append(newCaps, strings.ToUpper(cap))
|
|
|
- }
|
|
|
+// 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
|
|
|
}
|
|
|
|
|
|
- for _, cap := range adds {
|
|
|
- // skip `all` already handled above
|
|
|
- if strings.ToLower(cap) == "all" {
|
|
|
- continue
|
|
|
- }
|
|
|
+ capDrop, err := NormalizeLegacyCapabilities(drops)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ capAdd, err := NormalizeLegacyCapabilities(adds)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
|
|
|
- cap = "CAP_" + cap
|
|
|
+ var caps []string
|
|
|
|
|
|
- if !inSlice(allCaps, cap) {
|
|
|
- return nil, fmt.Errorf("Unknown capability to add: %q", cap)
|
|
|
+ switch {
|
|
|
+ case inSlice(capAdd, allCapabilities):
|
|
|
+ // Add all capabilities except ones on capDrop
|
|
|
+ for _, c := range GetAllCapabilities() {
|
|
|
+ if !inSlice(capDrop, c) {
|
|
|
+ caps = append(caps, c)
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- // add cap if not already in the list
|
|
|
- if !inSlice(newCaps, cap) {
|
|
|
- newCaps = append(newCaps, strings.ToUpper(cap))
|
|
|
+ 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 newCaps, nil
|
|
|
+ return caps, nil
|
|
|
}
|