github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/cgroups/devices/devicefilter_test.go (about) 1 package devices 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/opencontainers/runc/libcontainer/devices" 8 "github.com/opencontainers/runc/libcontainer/specconv" 9 ) 10 11 func hash(s, comm string) string { 12 var res []string 13 for _, l := range strings.Split(s, "\n") { 14 trimmed := strings.TrimSpace(l) 15 if trimmed == "" || strings.HasPrefix(trimmed, comm) { 16 continue 17 } 18 res = append(res, trimmed) 19 } 20 return strings.Join(res, "\n") 21 } 22 23 func testDeviceFilter(t testing.TB, devices []*devices.Rule, expectedStr string) { 24 insts, _, err := deviceFilter(devices) 25 if err != nil { 26 t.Fatalf("%s: %v (devices: %+v)", t.Name(), err, devices) 27 } 28 s := insts.String() 29 if expectedStr != "" { 30 hashed := hash(s, "//") 31 expectedHashed := hash(expectedStr, "//") 32 if expectedHashed != hashed { 33 t.Fatalf("expected:\n%q\ngot\n%q", expectedHashed, hashed) 34 } 35 } 36 } 37 38 func TestDeviceFilter_Nil(t *testing.T) { 39 expected := ` 40 // load parameters into registers 41 0: LdXMemW dst: r2 src: r1 off: 0 imm: 0 42 1: AndImm32 dst: r2 imm: 65535 43 2: LdXMemW dst: r3 src: r1 off: 0 imm: 0 44 3: RShImm32 dst: r3 imm: 16 45 4: LdXMemW dst: r4 src: r1 off: 4 imm: 0 46 5: LdXMemW dst: r5 src: r1 off: 8 imm: 0 47 block-0: 48 // return 0 (reject) 49 6: MovImm32 dst: r0 imm: 0 50 7: Exit 51 ` 52 testDeviceFilter(t, nil, expected) 53 } 54 55 func TestDeviceFilter_BuiltInAllowList(t *testing.T) { 56 expected := ` 57 // load parameters into registers 58 0: LdXMemW dst: r2 src: r1 off: 0 imm: 0 59 1: AndImm32 dst: r2 imm: 65535 60 2: LdXMemW dst: r3 src: r1 off: 0 imm: 0 61 3: RShImm32 dst: r3 imm: 16 62 4: LdXMemW dst: r4 src: r1 off: 4 imm: 0 63 5: LdXMemW dst: r5 src: r1 off: 8 imm: 0 64 block-0: 65 // (b, wildcard, wildcard, m, true) 66 6: JNEImm dst: r2 off: -1 imm: 1 <block-1> 67 7: MovReg32 dst: r1 src: r3 68 8: AndImm32 dst: r1 imm: 1 69 9: JNEReg dst: r1 off: -1 src: r3 <block-1> 70 10: MovImm32 dst: r0 imm: 1 71 11: Exit 72 block-1: 73 // (c, wildcard, wildcard, m, true) 74 12: JNEImm dst: r2 off: -1 imm: 2 <block-2> 75 13: MovReg32 dst: r1 src: r3 76 14: AndImm32 dst: r1 imm: 1 77 15: JNEReg dst: r1 off: -1 src: r3 <block-2> 78 16: MovImm32 dst: r0 imm: 1 79 17: Exit 80 block-2: 81 18: JNEImm dst: r2 off: -1 imm: 2 <block-3> 82 19: JNEImm dst: r4 off: -1 imm: 1 <block-3> 83 20: JNEImm dst: r5 off: -1 imm: 3 <block-3> 84 21: MovImm32 dst: r0 imm: 1 85 22: Exit 86 block-3: 87 23: JNEImm dst: r2 off: -1 imm: 2 <block-4> 88 24: JNEImm dst: r4 off: -1 imm: 1 <block-4> 89 25: JNEImm dst: r5 off: -1 imm: 5 <block-4> 90 26: MovImm32 dst: r0 imm: 1 91 27: Exit 92 block-4: 93 28: JNEImm dst: r2 off: -1 imm: 2 <block-5> 94 29: JNEImm dst: r4 off: -1 imm: 1 <block-5> 95 30: JNEImm dst: r5 off: -1 imm: 7 <block-5> 96 31: MovImm32 dst: r0 imm: 1 97 32: Exit 98 block-5: 99 33: JNEImm dst: r2 off: -1 imm: 2 <block-6> 100 34: JNEImm dst: r4 off: -1 imm: 1 <block-6> 101 35: JNEImm dst: r5 off: -1 imm: 8 <block-6> 102 36: MovImm32 dst: r0 imm: 1 103 37: Exit 104 block-6: 105 38: JNEImm dst: r2 off: -1 imm: 2 <block-7> 106 39: JNEImm dst: r4 off: -1 imm: 1 <block-7> 107 40: JNEImm dst: r5 off: -1 imm: 9 <block-7> 108 41: MovImm32 dst: r0 imm: 1 109 42: Exit 110 block-7: 111 43: JNEImm dst: r2 off: -1 imm: 2 <block-8> 112 44: JNEImm dst: r4 off: -1 imm: 5 <block-8> 113 45: JNEImm dst: r5 off: -1 imm: 0 <block-8> 114 46: MovImm32 dst: r0 imm: 1 115 47: Exit 116 block-8: 117 48: JNEImm dst: r2 off: -1 imm: 2 <block-9> 118 49: JNEImm dst: r4 off: -1 imm: 5 <block-9> 119 50: JNEImm dst: r5 off: -1 imm: 2 <block-9> 120 51: MovImm32 dst: r0 imm: 1 121 52: Exit 122 block-9: 123 // /dev/pts (c, 136, wildcard, rwm, true) 124 53: JNEImm dst: r2 off: -1 imm: 2 <block-10> 125 54: JNEImm dst: r4 off: -1 imm: 136 <block-10> 126 55: MovImm32 dst: r0 imm: 1 127 56: Exit 128 block-10: 129 57: MovImm32 dst: r0 imm: 0 130 58: Exit 131 ` 132 var devices []*devices.Rule 133 for _, device := range specconv.AllowedDevices { 134 devices = append(devices, &device.Rule) 135 } 136 testDeviceFilter(t, devices, expected) 137 } 138 139 func TestDeviceFilter_Privileged(t *testing.T) { 140 devices := []*devices.Rule{ 141 { 142 Type: 'a', 143 Major: -1, 144 Minor: -1, 145 Permissions: "rwm", 146 Allow: true, 147 }, 148 } 149 expected := ` 150 // load parameters into registers 151 0: LdXMemW dst: r2 src: r1 off: 0 imm: 0 152 1: AndImm32 dst: r2 imm: 65535 153 2: LdXMemW dst: r3 src: r1 off: 0 imm: 0 154 3: RShImm32 dst: r3 imm: 16 155 4: LdXMemW dst: r4 src: r1 off: 4 imm: 0 156 5: LdXMemW dst: r5 src: r1 off: 8 imm: 0 157 block-0: 158 // return 1 (accept) 159 6: MovImm32 dst: r0 imm: 1 160 7: Exit 161 ` 162 testDeviceFilter(t, devices, expected) 163 } 164 165 func TestDeviceFilter_PrivilegedExceptSingleDevice(t *testing.T) { 166 devices := []*devices.Rule{ 167 { 168 Type: 'a', 169 Major: -1, 170 Minor: -1, 171 Permissions: "rwm", 172 Allow: true, 173 }, 174 { 175 Type: 'b', 176 Major: 8, 177 Minor: 0, 178 Permissions: "rwm", 179 Allow: false, 180 }, 181 } 182 expected := ` 183 // load parameters into registers 184 0: LdXMemW dst: r2 src: r1 off: 0 imm: 0 185 1: AndImm32 dst: r2 imm: 65535 186 2: LdXMemW dst: r3 src: r1 off: 0 imm: 0 187 3: RShImm32 dst: r3 imm: 16 188 4: LdXMemW dst: r4 src: r1 off: 4 imm: 0 189 5: LdXMemW dst: r5 src: r1 off: 8 imm: 0 190 block-0: 191 // return 0 (reject) if type==b && major == 8 && minor == 0 192 6: JNEImm dst: r2 off: -1 imm: 1 <block-1> 193 7: JNEImm dst: r4 off: -1 imm: 8 <block-1> 194 8: JNEImm dst: r5 off: -1 imm: 0 <block-1> 195 9: MovImm32 dst: r0 imm: 0 196 10: Exit 197 block-1: 198 // return 1 (accept) 199 11: MovImm32 dst: r0 imm: 1 200 12: Exit 201 ` 202 testDeviceFilter(t, devices, expected) 203 } 204 205 func TestDeviceFilter_Weird(t *testing.T) { 206 devices := []*devices.Rule{ 207 { 208 Type: 'b', 209 Major: 8, 210 Minor: 1, 211 Permissions: "rwm", 212 Allow: false, 213 }, 214 { 215 Type: 'a', 216 Major: -1, 217 Minor: -1, 218 Permissions: "rwm", 219 Allow: true, 220 }, 221 { 222 Type: 'b', 223 Major: 8, 224 Minor: 2, 225 Permissions: "rwm", 226 Allow: false, 227 }, 228 } 229 // 8/1 is allowed, 8/2 is not allowed. 230 // This conforms to runc v1.0.0-rc.9 (cgroup1) behavior. 231 expected := ` 232 // load parameters into registers 233 0: LdXMemW dst: r2 src: r1 off: 0 imm: 0 234 1: AndImm32 dst: r2 imm: 65535 235 2: LdXMemW dst: r3 src: r1 off: 0 imm: 0 236 3: RShImm32 dst: r3 imm: 16 237 4: LdXMemW dst: r4 src: r1 off: 4 imm: 0 238 5: LdXMemW dst: r5 src: r1 off: 8 imm: 0 239 block-0: 240 // return 0 (reject) if type==b && major == 8 && minor == 2 241 6: JNEImm dst: r2 off: -1 imm: 1 <block-1> 242 7: JNEImm dst: r4 off: -1 imm: 8 <block-1> 243 8: JNEImm dst: r5 off: -1 imm: 2 <block-1> 244 9: MovImm32 dst: r0 imm: 0 245 10: Exit 246 block-1: 247 // return 1 (accept) 248 11: MovImm32 dst: r0 imm: 1 249 12: Exit 250 ` 251 testDeviceFilter(t, devices, expected) 252 }