github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/daemon/caps/utils_unix.go (about)

     1  // +build !windows
     2  
     3  package caps
     4  
     5  import (
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/syndtr/gocapability/capability"
    10  )
    11  
    12  var capabilityList Capabilities
    13  
    14  func init() {
    15  	last := capability.CAP_LAST_CAP
    16  	// hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
    17  	if last == capability.Cap(63) {
    18  		last = capability.CAP_BLOCK_SUSPEND
    19  	}
    20  	for _, cap := range capability.List() {
    21  		if cap > last {
    22  			continue
    23  		}
    24  		capabilityList = append(capabilityList,
    25  			&CapabilityMapping{
    26  				Key:   "CAP_" + strings.ToUpper(cap.String()),
    27  				Value: cap,
    28  			},
    29  		)
    30  	}
    31  }
    32  
    33  type (
    34  	// CapabilityMapping maps linux capability name to its value of capability.Cap type
    35  	// Capabilities is one of the security systems in Linux Security Module (LSM)
    36  	// framework provided by the kernel.
    37  	// For more details on capabilities, see http://man7.org/linux/man-pages/man7/capabilities.7.html
    38  	CapabilityMapping struct {
    39  		Key   string         `json:"key,omitempty"`
    40  		Value capability.Cap `json:"value,omitempty"`
    41  	}
    42  	// Capabilities contains all CapabilityMapping
    43  	Capabilities []*CapabilityMapping
    44  )
    45  
    46  // String returns <key> of CapabilityMapping
    47  func (c *CapabilityMapping) String() string {
    48  	return c.Key
    49  }
    50  
    51  // GetCapability returns CapabilityMapping which contains specific key
    52  func GetCapability(key string) *CapabilityMapping {
    53  	for _, capp := range capabilityList {
    54  		if capp.Key == key {
    55  			cpy := *capp
    56  			return &cpy
    57  		}
    58  	}
    59  	return nil
    60  }
    61  
    62  // GetAllCapabilities returns all of the capabilities
    63  func GetAllCapabilities() []string {
    64  	output := make([]string, len(capabilityList))
    65  	for i, capability := range capabilityList {
    66  		output[i] = capability.String()
    67  	}
    68  	return output
    69  }
    70  
    71  // inSlice tests whether a string is contained in a slice of strings or not.
    72  // Comparison is case insensitive
    73  func inSlice(slice []string, s string) bool {
    74  	for _, ss := range slice {
    75  		if strings.ToLower(s) == strings.ToLower(ss) {
    76  			return true
    77  		}
    78  	}
    79  	return false
    80  }
    81  
    82  // TweakCapabilities can tweak capabilities by adding or dropping capabilities
    83  // based on the basics capabilities.
    84  func TweakCapabilities(basics, adds, drops []string) ([]string, error) {
    85  	var (
    86  		newCaps []string
    87  		allCaps = GetAllCapabilities()
    88  	)
    89  
    90  	// FIXME(tonistiigi): docker format is without CAP_ prefix, oci is with prefix
    91  	// Currently they are mixed in here. We should do conversion in one place.
    92  
    93  	// look for invalid cap in the drop list
    94  	for _, cap := range drops {
    95  		if strings.ToLower(cap) == "all" {
    96  			continue
    97  		}
    98  
    99  		if !inSlice(allCaps, "CAP_"+cap) {
   100  			return nil, fmt.Errorf("Unknown capability drop: %q", cap)
   101  		}
   102  	}
   103  
   104  	// handle --cap-add=all
   105  	if inSlice(adds, "all") {
   106  		basics = allCaps
   107  	}
   108  
   109  	if !inSlice(drops, "all") {
   110  		for _, cap := range basics {
   111  			// skip `all` already handled above
   112  			if strings.ToLower(cap) == "all" {
   113  				continue
   114  			}
   115  
   116  			// if we don't drop `all`, add back all the non-dropped caps
   117  			if !inSlice(drops, cap[4:]) {
   118  				newCaps = append(newCaps, strings.ToUpper(cap))
   119  			}
   120  		}
   121  	}
   122  
   123  	for _, cap := range adds {
   124  		// skip `all` already handled above
   125  		if strings.ToLower(cap) == "all" {
   126  			continue
   127  		}
   128  
   129  		cap = "CAP_" + cap
   130  
   131  		if !inSlice(allCaps, cap) {
   132  			return nil, fmt.Errorf("Unknown capability to add: %q", cap)
   133  		}
   134  
   135  		// add cap if not already in the list
   136  		if !inSlice(newCaps, cap) {
   137  			newCaps = append(newCaps, strings.ToUpper(cap))
   138  		}
   139  	}
   140  	return newCaps, nil
   141  }