github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/daemon/caps/utils.go (about)

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