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