capabilities.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. //go:build linux
  2. // +build linux
  3. package capabilities
  4. import (
  5. "sort"
  6. "strings"
  7. "github.com/opencontainers/runc/libcontainer/configs"
  8. "github.com/sirupsen/logrus"
  9. "github.com/syndtr/gocapability/capability"
  10. )
  11. const allCapabilityTypes = capability.CAPS | capability.BOUNDING | capability.AMBIENT
  12. var (
  13. capabilityMap map[string]capability.Cap
  14. capTypes = []capability.CapType{
  15. capability.BOUNDING,
  16. capability.PERMITTED,
  17. capability.INHERITABLE,
  18. capability.EFFECTIVE,
  19. capability.AMBIENT,
  20. }
  21. )
  22. func init() {
  23. capabilityMap = make(map[string]capability.Cap, capability.CAP_LAST_CAP+1)
  24. for _, c := range capability.List() {
  25. if c > capability.CAP_LAST_CAP {
  26. continue
  27. }
  28. capabilityMap["CAP_"+strings.ToUpper(c.String())] = c
  29. }
  30. }
  31. // KnownCapabilities returns the list of the known capabilities.
  32. // Used by `runc features`.
  33. func KnownCapabilities() []string {
  34. list := capability.List()
  35. res := make([]string, len(list))
  36. for i, c := range list {
  37. res[i] = "CAP_" + strings.ToUpper(c.String())
  38. }
  39. return res
  40. }
  41. // New creates a new Caps from the given Capabilities config. Unknown Capabilities
  42. // or Capabilities that are unavailable in the current environment are ignored,
  43. // printing a warning instead.
  44. func New(capConfig *configs.Capabilities) (*Caps, error) {
  45. var (
  46. err error
  47. c Caps
  48. )
  49. unknownCaps := make(map[string]struct{})
  50. c.caps = map[capability.CapType][]capability.Cap{
  51. capability.BOUNDING: capSlice(capConfig.Bounding, unknownCaps),
  52. capability.EFFECTIVE: capSlice(capConfig.Effective, unknownCaps),
  53. capability.INHERITABLE: capSlice(capConfig.Inheritable, unknownCaps),
  54. capability.PERMITTED: capSlice(capConfig.Permitted, unknownCaps),
  55. capability.AMBIENT: capSlice(capConfig.Ambient, unknownCaps),
  56. }
  57. if c.pid, err = capability.NewPid2(0); err != nil {
  58. return nil, err
  59. }
  60. if err = c.pid.Load(); err != nil {
  61. return nil, err
  62. }
  63. if len(unknownCaps) > 0 {
  64. logrus.Warn("ignoring unknown or unavailable capabilities: ", mapKeys(unknownCaps))
  65. }
  66. return &c, nil
  67. }
  68. // capSlice converts the slice of capability names in caps, to their numeric
  69. // equivalent, and returns them as a slice. Unknown or unavailable capabilities
  70. // are not returned, but appended to unknownCaps.
  71. func capSlice(caps []string, unknownCaps map[string]struct{}) []capability.Cap {
  72. var out []capability.Cap
  73. for _, c := range caps {
  74. if v, ok := capabilityMap[c]; !ok {
  75. unknownCaps[c] = struct{}{}
  76. } else {
  77. out = append(out, v)
  78. }
  79. }
  80. return out
  81. }
  82. // mapKeys returns the keys of input in sorted order
  83. func mapKeys(input map[string]struct{}) []string {
  84. var keys []string
  85. for c := range input {
  86. keys = append(keys, c)
  87. }
  88. sort.Strings(keys)
  89. return keys
  90. }
  91. // Caps holds the capabilities for a container.
  92. type Caps struct {
  93. pid capability.Capabilities
  94. caps map[capability.CapType][]capability.Cap
  95. }
  96. // ApplyBoundingSet sets the capability bounding set to those specified in the whitelist.
  97. func (c *Caps) ApplyBoundingSet() error {
  98. c.pid.Clear(capability.BOUNDING)
  99. c.pid.Set(capability.BOUNDING, c.caps[capability.BOUNDING]...)
  100. return c.pid.Apply(capability.BOUNDING)
  101. }
  102. // Apply sets all the capabilities for the current process in the config.
  103. func (c *Caps) ApplyCaps() error {
  104. c.pid.Clear(allCapabilityTypes)
  105. for _, g := range capTypes {
  106. c.pid.Set(g, c.caps[g]...)
  107. }
  108. return c.pid.Apply(allCapabilityTypes)
  109. }