utils.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package caps // import "github.com/docker/docker/oci/caps"
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/docker/docker/errdefs"
  6. )
  7. var (
  8. allCaps []string
  9. // knownCapabilities is a map of all known capabilities, using capability
  10. // name as index. Nil values indicate that the capability is known, but either
  11. // not supported by the Kernel, or not available in the current environment,
  12. // for example, when running Docker-in-Docker with restricted capabilities.
  13. //
  14. // Capabilities are one of the security systems in Linux Security Module (LSM)
  15. // framework provided by the kernel.
  16. // For more details on capabilities, see http://man7.org/linux/man-pages/man7/capabilities.7.html
  17. knownCaps map[string]*struct{}
  18. )
  19. // GetAllCapabilities returns all capabilities that are availeble in the current
  20. // environment.
  21. func GetAllCapabilities() []string {
  22. initCaps()
  23. return allCaps
  24. }
  25. // knownCapabilities returns a map of all known capabilities, using capability
  26. // name as index. Nil values indicate that the capability is known, but either
  27. // not supported by the Kernel, or not available in the current environment, for
  28. // example, when running Docker-in-Docker with restricted capabilities.
  29. func knownCapabilities() map[string]*struct{} {
  30. initCaps()
  31. return knownCaps
  32. }
  33. // inSlice tests whether a string is contained in a slice of strings or not.
  34. func inSlice(slice []string, s string) bool {
  35. for _, ss := range slice {
  36. if s == ss {
  37. return true
  38. }
  39. }
  40. return false
  41. }
  42. const allCapabilities = "ALL"
  43. // NormalizeLegacyCapabilities normalizes, and validates CapAdd/CapDrop capabilities
  44. // by upper-casing them, and adding a CAP_ prefix (if not yet present).
  45. //
  46. // This function also accepts the "ALL" magic-value, that's used by CapAdd/CapDrop.
  47. func NormalizeLegacyCapabilities(caps []string) ([]string, error) {
  48. var (
  49. normalized []string
  50. capabilityList = knownCapabilities()
  51. )
  52. for _, c := range caps {
  53. c = strings.ToUpper(c)
  54. if c == allCapabilities {
  55. normalized = append(normalized, c)
  56. continue
  57. }
  58. if !strings.HasPrefix(c, "CAP_") {
  59. c = "CAP_" + c
  60. }
  61. if v, ok := capabilityList[c]; !ok {
  62. return nil, errdefs.InvalidParameter(fmt.Errorf("unknown capability: %q", c))
  63. } else if v == nil {
  64. return nil, errdefs.InvalidParameter(fmt.Errorf("capability not supported by your kernel or not available in the current environment: %q", c))
  65. }
  66. normalized = append(normalized, c)
  67. }
  68. return normalized, nil
  69. }
  70. // TweakCapabilities tweaks capabilities by adding, dropping, or overriding
  71. // capabilities in the basics capabilities list.
  72. func TweakCapabilities(basics, adds, drops []string, privileged bool) ([]string, error) {
  73. switch {
  74. case privileged:
  75. // Privileged containers get all capabilities
  76. return GetAllCapabilities(), nil
  77. case len(adds) == 0 && len(drops) == 0:
  78. // Nothing to tweak; we're done
  79. return basics, nil
  80. }
  81. capDrop, err := NormalizeLegacyCapabilities(drops)
  82. if err != nil {
  83. return nil, err
  84. }
  85. capAdd, err := NormalizeLegacyCapabilities(adds)
  86. if err != nil {
  87. return nil, err
  88. }
  89. var caps []string
  90. switch {
  91. case inSlice(capAdd, allCapabilities):
  92. // Add all capabilities except ones on capDrop
  93. for _, c := range GetAllCapabilities() {
  94. if !inSlice(capDrop, c) {
  95. caps = append(caps, c)
  96. }
  97. }
  98. case inSlice(capDrop, allCapabilities):
  99. // "Drop" all capabilities; use what's in capAdd instead
  100. caps = capAdd
  101. default:
  102. // First drop some capabilities
  103. for _, c := range basics {
  104. if !inSlice(capDrop, c) {
  105. caps = append(caps, c)
  106. }
  107. }
  108. // Then add the list of capabilities from capAdd
  109. caps = append(caps, capAdd...)
  110. }
  111. return caps, nil
  112. }