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
|
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 (
"strings"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/syndtr/gocapability/capability"
)
var (
// Used internally and populated during init().
capabilityList []string
// ErrUnknownCapability is thrown when an unknown capability is processed.
ErrUnknownCapability = errors.New("unknown capability")
)
// All is a special value used to add/drop all known capababilities.
// Useful on the CLI for `--cap-add=all` etc.
const All = "ALL"
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, "CAP_"+strings.ToUpper(cap.String()))
}
}
// AllCapabilities returns all known capabilities.
func AllCapabilities() []string {
return capabilityList
}
// normalizeCapabilities normalizes caps by adding a "CAP_" prefix (if not yet
// present).
func normalizeCapabilities(caps []string) ([]string, error) {
normalized := make([]string, len(caps))
for i, c := range caps {
c = strings.ToUpper(c)
if c == All {
normalized = append(normalized, c)
continue
}
if !strings.HasPrefix(c, "CAP_") {
c = "CAP_" + c
}
if !util.StringInSlice(c, capabilityList) {
return nil, errors.Wrapf(ErrUnknownCapability, "%q", c)
}
normalized[i] = c
}
return normalized, nil
}
// ValidateCapabilities validates if caps only contains valid capabilities.
func ValidateCapabilities(caps []string) error {
for _, c := range caps {
if !util.StringInSlice(c, capabilityList) {
return errors.Wrapf(ErrUnknownCapability, "%q", c)
}
}
return nil
}
// MergeCapabilities computes a set of capabilities by adding capapbitilities
// to or dropping them from base.
//
// Note that "ALL" will cause all known capabilities to be added/dropped but
// the ones specified to be dropped/added.
func MergeCapabilities(base, adds, drops []string) ([]string, error) {
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
}
// Make sure that capDrop and capAdd are distinct sets.
for _, drop := range capDrop {
if util.StringInSlice(drop, capAdd) {
return nil, errors.Errorf("capability %q cannot be dropped and added", drop)
}
}
var caps []string
switch {
case util.StringInSlice(All, capAdd):
// Add all capabilities except ones on capDrop
for _, c := range capabilityList {
if !util.StringInSlice(c, capDrop) {
caps = append(caps, c)
}
}
case util.StringInSlice(All, capDrop):
// "Drop" all capabilities; use what's in capAdd instead
caps = capAdd
default:
// First drop some capabilities
for _, c := range base {
if !util.StringInSlice(c, capDrop) {
caps = append(caps, c)
}
}
// Then add the list of capabilities from capAdd
caps = append(caps, capAdd...)
}
return caps, nil
}
|