utils_unix.go 3.1 KB

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