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  }