device.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package devices
  2. import (
  3. "fmt"
  4. "os"
  5. "strconv"
  6. )
  7. const (
  8. Wildcard = -1
  9. )
  10. type Device struct {
  11. Rule
  12. // Path to the device.
  13. Path string `json:"path"`
  14. // FileMode permission bits for the device.
  15. FileMode os.FileMode `json:"file_mode"`
  16. // Uid of the device.
  17. Uid uint32 `json:"uid"`
  18. // Gid of the device.
  19. Gid uint32 `json:"gid"`
  20. }
  21. // Permissions is a cgroupv1-style string to represent device access. It
  22. // has to be a string for backward compatibility reasons, hence why it has
  23. // methods to do set operations.
  24. type Permissions string
  25. const (
  26. deviceRead uint = (1 << iota)
  27. deviceWrite
  28. deviceMknod
  29. )
  30. func (p Permissions) toSet() uint {
  31. var set uint
  32. for _, perm := range p {
  33. switch perm {
  34. case 'r':
  35. set |= deviceRead
  36. case 'w':
  37. set |= deviceWrite
  38. case 'm':
  39. set |= deviceMknod
  40. }
  41. }
  42. return set
  43. }
  44. func fromSet(set uint) Permissions {
  45. var perm string
  46. if set&deviceRead == deviceRead {
  47. perm += "r"
  48. }
  49. if set&deviceWrite == deviceWrite {
  50. perm += "w"
  51. }
  52. if set&deviceMknod == deviceMknod {
  53. perm += "m"
  54. }
  55. return Permissions(perm)
  56. }
  57. // Union returns the union of the two sets of Permissions.
  58. func (p Permissions) Union(o Permissions) Permissions {
  59. lhs := p.toSet()
  60. rhs := o.toSet()
  61. return fromSet(lhs | rhs)
  62. }
  63. // Difference returns the set difference of the two sets of Permissions.
  64. // In set notation, A.Difference(B) gives you A\B.
  65. func (p Permissions) Difference(o Permissions) Permissions {
  66. lhs := p.toSet()
  67. rhs := o.toSet()
  68. return fromSet(lhs &^ rhs)
  69. }
  70. // Intersection computes the intersection of the two sets of Permissions.
  71. func (p Permissions) Intersection(o Permissions) Permissions {
  72. lhs := p.toSet()
  73. rhs := o.toSet()
  74. return fromSet(lhs & rhs)
  75. }
  76. // IsEmpty returns whether the set of permissions in a Permissions is
  77. // empty.
  78. func (p Permissions) IsEmpty() bool {
  79. return p == Permissions("")
  80. }
  81. // IsValid returns whether the set of permissions is a subset of valid
  82. // permissions (namely, {r,w,m}).
  83. func (p Permissions) IsValid() bool {
  84. return p == fromSet(p.toSet())
  85. }
  86. type Type rune
  87. const (
  88. WildcardDevice Type = 'a'
  89. BlockDevice Type = 'b'
  90. CharDevice Type = 'c' // or 'u'
  91. FifoDevice Type = 'p'
  92. )
  93. func (t Type) IsValid() bool {
  94. switch t {
  95. case WildcardDevice, BlockDevice, CharDevice, FifoDevice:
  96. return true
  97. default:
  98. return false
  99. }
  100. }
  101. func (t Type) CanMknod() bool {
  102. switch t {
  103. case BlockDevice, CharDevice, FifoDevice:
  104. return true
  105. default:
  106. return false
  107. }
  108. }
  109. func (t Type) CanCgroup() bool {
  110. switch t {
  111. case WildcardDevice, BlockDevice, CharDevice:
  112. return true
  113. default:
  114. return false
  115. }
  116. }
  117. type Rule struct {
  118. // Type of device ('c' for char, 'b' for block). If set to 'a', this rule
  119. // acts as a wildcard and all fields other than Allow are ignored.
  120. Type Type `json:"type"`
  121. // Major is the device's major number.
  122. Major int64 `json:"major"`
  123. // Minor is the device's minor number.
  124. Minor int64 `json:"minor"`
  125. // Permissions is the set of permissions that this rule applies to (in the
  126. // cgroupv1 format -- any combination of "rwm").
  127. Permissions Permissions `json:"permissions"`
  128. // Allow specifies whether this rule is allowed.
  129. Allow bool `json:"allow"`
  130. }
  131. func (d *Rule) CgroupString() string {
  132. var (
  133. major = strconv.FormatInt(d.Major, 10)
  134. minor = strconv.FormatInt(d.Minor, 10)
  135. )
  136. if d.Major == Wildcard {
  137. major = "*"
  138. }
  139. if d.Minor == Wildcard {
  140. minor = "*"
  141. }
  142. return fmt.Sprintf("%c %s:%s %s", d.Type, major, minor, d.Permissions)
  143. }
  144. func (d *Rule) Mkdev() (uint64, error) {
  145. return mkDev(d)
  146. }