github.com/afbjorklund/moby@v20.10.5+incompatible/oci/caps/utils.go (about) 1 package caps // import "github.com/docker/docker/oci/caps" 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/docker/docker/errdefs" 8 "github.com/syndtr/gocapability/capability" 9 ) 10 11 var capabilityList Capabilities 12 13 func init() { 14 last := capability.CAP_LAST_CAP 15 // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap 16 if last == capability.Cap(63) { 17 last = capability.CAP_BLOCK_SUSPEND 18 } 19 if last > capability.CAP_AUDIT_READ { 20 // Prevents docker from setting CAP_PERFMON, CAP_BPF, and CAP_CHECKPOINT_RESTORE 21 // capabilities on privileged (or CAP_ALL) containers on Kernel 5.8 and up. 22 // While these kernels support these capabilities, the current release of 23 // runc ships with an older version of /gocapability/capability, and does 24 // not know about them, causing an error to be produced. 25 // 26 // FIXME remove once https://github.com/opencontainers/runc/commit/6dfbe9b80707b1ca188255e8def15263348e0f9a 27 // is included in a runc release and once we stop supporting containerd 1.3.x 28 // (which ships with runc v1.0.0-rc92) 29 last = capability.CAP_AUDIT_READ 30 } 31 for _, cap := range capability.List() { 32 if cap > last { 33 continue 34 } 35 capabilityList = append(capabilityList, 36 &CapabilityMapping{ 37 Key: "CAP_" + strings.ToUpper(cap.String()), 38 Value: cap, 39 }, 40 ) 41 } 42 } 43 44 type ( 45 // CapabilityMapping maps linux capability name to its value of capability.Cap type 46 // Capabilities is one of the security systems in Linux Security Module (LSM) 47 // framework provided by the kernel. 48 // For more details on capabilities, see http://man7.org/linux/man-pages/man7/capabilities.7.html 49 CapabilityMapping struct { 50 Key string `json:"key,omitempty"` 51 Value capability.Cap `json:"value,omitempty"` 52 } 53 // Capabilities contains all CapabilityMapping 54 Capabilities []*CapabilityMapping 55 ) 56 57 // String returns <key> of CapabilityMapping 58 func (c *CapabilityMapping) String() string { 59 return c.Key 60 } 61 62 // GetCapability returns CapabilityMapping which contains specific key 63 func GetCapability(key string) *CapabilityMapping { 64 for _, capp := range capabilityList { 65 if capp.Key == key { 66 cpy := *capp 67 return &cpy 68 } 69 } 70 return nil 71 } 72 73 // GetAllCapabilities returns all of the capabilities 74 func GetAllCapabilities() []string { 75 output := make([]string, len(capabilityList)) 76 for i, capability := range capabilityList { 77 output[i] = capability.String() 78 } 79 return output 80 } 81 82 // inSlice tests whether a string is contained in a slice of strings or not. 83 func inSlice(slice []string, s string) bool { 84 for _, ss := range slice { 85 if s == ss { 86 return true 87 } 88 } 89 return false 90 } 91 92 const allCapabilities = "ALL" 93 94 // NormalizeLegacyCapabilities normalizes, and validates CapAdd/CapDrop capabilities 95 // by upper-casing them, and adding a CAP_ prefix (if not yet present). 96 // 97 // This function also accepts the "ALL" magic-value, that's used by CapAdd/CapDrop. 98 func NormalizeLegacyCapabilities(caps []string) ([]string, error) { 99 var normalized []string 100 101 valids := GetAllCapabilities() 102 for _, c := range caps { 103 c = strings.ToUpper(c) 104 if c == allCapabilities { 105 normalized = append(normalized, c) 106 continue 107 } 108 if !strings.HasPrefix(c, "CAP_") { 109 c = "CAP_" + c 110 } 111 if !inSlice(valids, c) { 112 return nil, errdefs.InvalidParameter(fmt.Errorf("unknown capability: %q", c)) 113 } 114 normalized = append(normalized, c) 115 } 116 return normalized, nil 117 } 118 119 // ValidateCapabilities validates if caps only contains valid capabilities 120 func ValidateCapabilities(caps []string) error { 121 valids := GetAllCapabilities() 122 for _, c := range caps { 123 if !inSlice(valids, c) { 124 return errdefs.InvalidParameter(fmt.Errorf("unknown capability: %q", c)) 125 } 126 } 127 return nil 128 } 129 130 // TweakCapabilities tweaks capabilities by adding, dropping, or overriding 131 // capabilities in the basics capabilities list. 132 func TweakCapabilities(basics, adds, drops []string, privileged bool) ([]string, error) { 133 switch { 134 case privileged: 135 // Privileged containers get all capabilities 136 return GetAllCapabilities(), nil 137 case len(adds) == 0 && len(drops) == 0: 138 // Nothing to tweak; we're done 139 return basics, nil 140 } 141 142 capDrop, err := NormalizeLegacyCapabilities(drops) 143 if err != nil { 144 return nil, err 145 } 146 capAdd, err := NormalizeLegacyCapabilities(adds) 147 if err != nil { 148 return nil, err 149 } 150 151 var caps []string 152 153 switch { 154 case inSlice(capAdd, allCapabilities): 155 // Add all capabilities except ones on capDrop 156 for _, c := range GetAllCapabilities() { 157 if !inSlice(capDrop, c) { 158 caps = append(caps, c) 159 } 160 } 161 case inSlice(capDrop, allCapabilities): 162 // "Drop" all capabilities; use what's in capAdd instead 163 caps = capAdd 164 default: 165 // First drop some capabilities 166 for _, c := range basics { 167 if !inSlice(capDrop, c) { 168 caps = append(caps, c) 169 } 170 } 171 // Then add the list of capabilities from capAdd 172 caps = append(caps, capAdd...) 173 } 174 return caps, nil 175 }