utils.go 4.3 KB

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