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