Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at for-next 528 lines 13 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* Converted from tools/testing/selftests/bpf/verifier/array_access.c */ 3 4#include <linux/bpf.h> 5#include <bpf/bpf_helpers.h> 6#include "bpf_misc.h" 7 8#define MAX_ENTRIES 11 9 10struct test_val { 11 unsigned int index; 12 int foo[MAX_ENTRIES]; 13}; 14 15struct { 16 __uint(type, BPF_MAP_TYPE_ARRAY); 17 __uint(max_entries, 1); 18 __type(key, int); 19 __type(value, struct test_val); 20 __uint(map_flags, BPF_F_RDONLY_PROG); 21} map_array_ro SEC(".maps"); 22 23struct { 24 __uint(type, BPF_MAP_TYPE_ARRAY); 25 __uint(max_entries, 1); 26 __type(key, int); 27 __type(value, struct test_val); 28 __uint(map_flags, BPF_F_WRONLY_PROG); 29} map_array_wo SEC(".maps"); 30 31struct { 32 __uint(type, BPF_MAP_TYPE_HASH); 33 __uint(max_entries, 1); 34 __type(key, long long); 35 __type(value, struct test_val); 36} map_hash_48b SEC(".maps"); 37 38SEC("socket") 39__description("valid map access into an array with a constant") 40__success __failure_unpriv __msg_unpriv("R0 leaks addr") 41__retval(0) 42__naked void an_array_with_a_constant_1(void) 43{ 44 asm volatile (" \ 45 r1 = 0; \ 46 *(u64*)(r10 - 8) = r1; \ 47 r2 = r10; \ 48 r2 += -8; \ 49 r1 = %[map_hash_48b] ll; \ 50 call %[bpf_map_lookup_elem]; \ 51 if r0 == 0 goto l0_%=; \ 52 r1 = %[test_val_foo]; \ 53 *(u64*)(r0 + 0) = r1; \ 54l0_%=: exit; \ 55" : 56 : __imm(bpf_map_lookup_elem), 57 __imm_addr(map_hash_48b), 58 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 59 : __clobber_all); 60} 61 62SEC("socket") 63__description("valid map access into an array with a register") 64__success __failure_unpriv __msg_unpriv("R0 leaks addr") 65__retval(0) __flag(BPF_F_ANY_ALIGNMENT) 66__naked void an_array_with_a_register_1(void) 67{ 68 asm volatile (" \ 69 r1 = 0; \ 70 *(u64*)(r10 - 8) = r1; \ 71 r2 = r10; \ 72 r2 += -8; \ 73 r1 = %[map_hash_48b] ll; \ 74 call %[bpf_map_lookup_elem]; \ 75 if r0 == 0 goto l0_%=; \ 76 r1 = 4; \ 77 r1 <<= 2; \ 78 r0 += r1; \ 79 r1 = %[test_val_foo]; \ 80 *(u64*)(r0 + 0) = r1; \ 81l0_%=: exit; \ 82" : 83 : __imm(bpf_map_lookup_elem), 84 __imm_addr(map_hash_48b), 85 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 86 : __clobber_all); 87} 88 89SEC("socket") 90__description("valid map access into an array with a variable") 91__success __failure_unpriv __msg_unpriv("R0 leaks addr") 92__retval(0) __flag(BPF_F_ANY_ALIGNMENT) 93__naked void an_array_with_a_variable_1(void) 94{ 95 asm volatile (" \ 96 r1 = 0; \ 97 *(u64*)(r10 - 8) = r1; \ 98 r2 = r10; \ 99 r2 += -8; \ 100 r1 = %[map_hash_48b] ll; \ 101 call %[bpf_map_lookup_elem]; \ 102 if r0 == 0 goto l0_%=; \ 103 r1 = *(u32*)(r0 + 0); \ 104 if r1 >= %[max_entries] goto l0_%=; \ 105 r1 <<= 2; \ 106 r0 += r1; \ 107 r1 = %[test_val_foo]; \ 108 *(u64*)(r0 + 0) = r1; \ 109l0_%=: exit; \ 110" : 111 : __imm(bpf_map_lookup_elem), 112 __imm_addr(map_hash_48b), 113 __imm_const(max_entries, MAX_ENTRIES), 114 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 115 : __clobber_all); 116} 117 118SEC("socket") 119__description("valid map access into an array with a signed variable") 120__success __failure_unpriv __msg_unpriv("R0 leaks addr") 121__retval(0) __flag(BPF_F_ANY_ALIGNMENT) 122__naked void array_with_a_signed_variable(void) 123{ 124 asm volatile (" \ 125 r1 = 0; \ 126 *(u64*)(r10 - 8) = r1; \ 127 r2 = r10; \ 128 r2 += -8; \ 129 r1 = %[map_hash_48b] ll; \ 130 call %[bpf_map_lookup_elem]; \ 131 if r0 == 0 goto l0_%=; \ 132 r1 = *(u32*)(r0 + 0); \ 133 if w1 s> 0xffffffff goto l1_%=; \ 134 w1 = 0; \ 135l1_%=: w2 = %[max_entries]; \ 136 if r2 s> r1 goto l2_%=; \ 137 w1 = 0; \ 138l2_%=: w1 <<= 2; \ 139 r0 += r1; \ 140 r1 = %[test_val_foo]; \ 141 *(u64*)(r0 + 0) = r1; \ 142l0_%=: exit; \ 143" : 144 : __imm(bpf_map_lookup_elem), 145 __imm_addr(map_hash_48b), 146 __imm_const(max_entries, MAX_ENTRIES), 147 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 148 : __clobber_all); 149} 150 151SEC("socket") 152__description("invalid map access into an array with a constant") 153__failure __msg("invalid access to map value, value_size=48 off=48 size=8") 154__failure_unpriv 155__naked void an_array_with_a_constant_2(void) 156{ 157 asm volatile (" \ 158 r1 = 0; \ 159 *(u64*)(r10 - 8) = r1; \ 160 r2 = r10; \ 161 r2 += -8; \ 162 r1 = %[map_hash_48b] ll; \ 163 call %[bpf_map_lookup_elem]; \ 164 if r0 == 0 goto l0_%=; \ 165 r1 = %[test_val_foo]; \ 166 *(u64*)(r0 + %[__imm_0]) = r1; \ 167l0_%=: exit; \ 168" : 169 : __imm(bpf_map_lookup_elem), 170 __imm_addr(map_hash_48b), 171 __imm_const(__imm_0, (MAX_ENTRIES + 1) << 2), 172 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 173 : __clobber_all); 174} 175 176SEC("socket") 177__description("invalid map access into an array with a register") 178__failure __msg("R0 min value is outside of the allowed memory range") 179__failure_unpriv 180__flag(BPF_F_ANY_ALIGNMENT) 181__naked void an_array_with_a_register_2(void) 182{ 183 asm volatile (" \ 184 r1 = 0; \ 185 *(u64*)(r10 - 8) = r1; \ 186 r2 = r10; \ 187 r2 += -8; \ 188 r1 = %[map_hash_48b] ll; \ 189 call %[bpf_map_lookup_elem]; \ 190 if r0 == 0 goto l0_%=; \ 191 r1 = %[__imm_0]; \ 192 r1 <<= 2; \ 193 r0 += r1; \ 194 r1 = %[test_val_foo]; \ 195 *(u64*)(r0 + 0) = r1; \ 196l0_%=: exit; \ 197" : 198 : __imm(bpf_map_lookup_elem), 199 __imm_addr(map_hash_48b), 200 __imm_const(__imm_0, MAX_ENTRIES + 1), 201 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 202 : __clobber_all); 203} 204 205SEC("socket") 206__description("invalid map access into an array with a variable") 207__failure 208__msg("R0 unbounded memory access, make sure to bounds check any such access") 209__failure_unpriv 210__flag(BPF_F_ANY_ALIGNMENT) 211__naked void an_array_with_a_variable_2(void) 212{ 213 asm volatile (" \ 214 r1 = 0; \ 215 *(u64*)(r10 - 8) = r1; \ 216 r2 = r10; \ 217 r2 += -8; \ 218 r1 = %[map_hash_48b] ll; \ 219 call %[bpf_map_lookup_elem]; \ 220 if r0 == 0 goto l0_%=; \ 221 r1 = *(u32*)(r0 + 0); \ 222 r1 <<= 2; \ 223 r0 += r1; \ 224 r1 = %[test_val_foo]; \ 225 *(u64*)(r0 + 0) = r1; \ 226l0_%=: exit; \ 227" : 228 : __imm(bpf_map_lookup_elem), 229 __imm_addr(map_hash_48b), 230 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 231 : __clobber_all); 232} 233 234SEC("socket") 235__description("invalid map access into an array with no floor check") 236__failure __msg("R0 unbounded memory access") 237__failure_unpriv __msg_unpriv("R0 leaks addr") 238__flag(BPF_F_ANY_ALIGNMENT) 239__naked void array_with_no_floor_check(void) 240{ 241 asm volatile (" \ 242 r1 = 0; \ 243 *(u64*)(r10 - 8) = r1; \ 244 r2 = r10; \ 245 r2 += -8; \ 246 r1 = %[map_hash_48b] ll; \ 247 call %[bpf_map_lookup_elem]; \ 248 if r0 == 0 goto l0_%=; \ 249 r1 = *(u64*)(r0 + 0); \ 250 w2 = %[max_entries]; \ 251 if r2 s> r1 goto l1_%=; \ 252 w1 = 0; \ 253l1_%=: w1 <<= 2; \ 254 r0 += r1; \ 255 r1 = %[test_val_foo]; \ 256 *(u64*)(r0 + 0) = r1; \ 257l0_%=: exit; \ 258" : 259 : __imm(bpf_map_lookup_elem), 260 __imm_addr(map_hash_48b), 261 __imm_const(max_entries, MAX_ENTRIES), 262 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 263 : __clobber_all); 264} 265 266SEC("socket") 267__description("invalid map access into an array with a invalid max check") 268__failure __msg("invalid access to map value, value_size=48 off=44 size=8") 269__failure_unpriv __msg_unpriv("R0 leaks addr") 270__flag(BPF_F_ANY_ALIGNMENT) 271__naked void with_a_invalid_max_check_1(void) 272{ 273 asm volatile (" \ 274 r1 = 0; \ 275 *(u64*)(r10 - 8) = r1; \ 276 r2 = r10; \ 277 r2 += -8; \ 278 r1 = %[map_hash_48b] ll; \ 279 call %[bpf_map_lookup_elem]; \ 280 if r0 == 0 goto l0_%=; \ 281 r1 = *(u32*)(r0 + 0); \ 282 w2 = %[__imm_0]; \ 283 if r2 > r1 goto l1_%=; \ 284 w1 = 0; \ 285l1_%=: w1 <<= 2; \ 286 r0 += r1; \ 287 r1 = %[test_val_foo]; \ 288 *(u64*)(r0 + 0) = r1; \ 289l0_%=: exit; \ 290" : 291 : __imm(bpf_map_lookup_elem), 292 __imm_addr(map_hash_48b), 293 __imm_const(__imm_0, MAX_ENTRIES + 1), 294 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 295 : __clobber_all); 296} 297 298SEC("socket") 299__description("invalid map access into an array with a invalid max check") 300__failure __msg("R0 pointer += pointer") 301__failure_unpriv 302__flag(BPF_F_ANY_ALIGNMENT) 303__naked void with_a_invalid_max_check_2(void) 304{ 305 asm volatile (" \ 306 r1 = 0; \ 307 *(u64*)(r10 - 8) = r1; \ 308 r2 = r10; \ 309 r2 += -8; \ 310 r1 = %[map_hash_48b] ll; \ 311 call %[bpf_map_lookup_elem]; \ 312 if r0 == 0 goto l0_%=; \ 313 r8 = r0; \ 314 r1 = 0; \ 315 *(u64*)(r10 - 8) = r1; \ 316 r2 = r10; \ 317 r2 += -8; \ 318 r1 = %[map_hash_48b] ll; \ 319 call %[bpf_map_lookup_elem]; \ 320 if r0 == 0 goto l0_%=; \ 321 r0 += r8; \ 322 r0 = *(u32*)(r0 + %[test_val_foo]); \ 323l0_%=: exit; \ 324" : 325 : __imm(bpf_map_lookup_elem), 326 __imm_addr(map_hash_48b), 327 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 328 : __clobber_all); 329} 330 331SEC("socket") 332__description("valid read map access into a read-only array 1") 333__success __success_unpriv __retval(28) 334__naked void a_read_only_array_1_1(void) 335{ 336 asm volatile (" \ 337 r1 = 0; \ 338 *(u64*)(r10 - 8) = r1; \ 339 r2 = r10; \ 340 r2 += -8; \ 341 r1 = %[map_array_ro] ll; \ 342 call %[bpf_map_lookup_elem]; \ 343 if r0 == 0 goto l0_%=; \ 344 r0 = *(u32*)(r0 + 0); \ 345l0_%=: exit; \ 346" : 347 : __imm(bpf_map_lookup_elem), 348 __imm_addr(map_array_ro) 349 : __clobber_all); 350} 351 352SEC("tc") 353__description("valid read map access into a read-only array 2") 354__success __retval(65507) 355__naked void a_read_only_array_2_1(void) 356{ 357 asm volatile (" \ 358 r1 = 0; \ 359 *(u64*)(r10 - 8) = r1; \ 360 r2 = r10; \ 361 r2 += -8; \ 362 r1 = %[map_array_ro] ll; \ 363 call %[bpf_map_lookup_elem]; \ 364 if r0 == 0 goto l0_%=; \ 365 r1 = r0; \ 366 r2 = 4; \ 367 r3 = 0; \ 368 r4 = 0; \ 369 r5 = 0; \ 370 call %[bpf_csum_diff]; \ 371l0_%=: exit; \ 372" : 373 : __imm(bpf_csum_diff), 374 __imm(bpf_map_lookup_elem), 375 __imm_addr(map_array_ro) 376 : __clobber_all); 377} 378 379SEC("socket") 380__description("invalid write map access into a read-only array 1") 381__failure __msg("write into map forbidden") 382__failure_unpriv 383__naked void a_read_only_array_1_2(void) 384{ 385 asm volatile (" \ 386 r1 = 0; \ 387 *(u64*)(r10 - 8) = r1; \ 388 r2 = r10; \ 389 r2 += -8; \ 390 r1 = %[map_array_ro] ll; \ 391 call %[bpf_map_lookup_elem]; \ 392 if r0 == 0 goto l0_%=; \ 393 r1 = 42; \ 394 *(u64*)(r0 + 0) = r1; \ 395l0_%=: exit; \ 396" : 397 : __imm(bpf_map_lookup_elem), 398 __imm_addr(map_array_ro) 399 : __clobber_all); 400} 401 402SEC("tc") 403__description("invalid write map access into a read-only array 2") 404__failure __msg("write into map forbidden") 405__naked void a_read_only_array_2_2(void) 406{ 407 asm volatile (" \ 408 r6 = r1; \ 409 r1 = 0; \ 410 *(u64*)(r10 - 8) = r1; \ 411 r2 = r10; \ 412 r2 += -8; \ 413 r1 = %[map_array_ro] ll; \ 414 call %[bpf_map_lookup_elem]; \ 415 if r0 == 0 goto l0_%=; \ 416 r1 = r6; \ 417 r2 = 0; \ 418 r3 = r0; \ 419 r4 = 8; \ 420 call %[bpf_skb_load_bytes]; \ 421l0_%=: exit; \ 422" : 423 : __imm(bpf_map_lookup_elem), 424 __imm(bpf_skb_load_bytes), 425 __imm_addr(map_array_ro) 426 : __clobber_all); 427} 428 429SEC("socket") 430__description("valid write map access into a write-only array 1") 431__success __success_unpriv __retval(1) 432__naked void a_write_only_array_1_1(void) 433{ 434 asm volatile (" \ 435 r1 = 0; \ 436 *(u64*)(r10 - 8) = r1; \ 437 r2 = r10; \ 438 r2 += -8; \ 439 r1 = %[map_array_wo] ll; \ 440 call %[bpf_map_lookup_elem]; \ 441 if r0 == 0 goto l0_%=; \ 442 r1 = 42; \ 443 *(u64*)(r0 + 0) = r1; \ 444l0_%=: r0 = 1; \ 445 exit; \ 446" : 447 : __imm(bpf_map_lookup_elem), 448 __imm_addr(map_array_wo) 449 : __clobber_all); 450} 451 452SEC("tc") 453__description("valid write map access into a write-only array 2") 454__success __retval(0) 455__naked void a_write_only_array_2_1(void) 456{ 457 asm volatile (" \ 458 r6 = r1; \ 459 r1 = 0; \ 460 *(u64*)(r10 - 8) = r1; \ 461 r2 = r10; \ 462 r2 += -8; \ 463 r1 = %[map_array_wo] ll; \ 464 call %[bpf_map_lookup_elem]; \ 465 if r0 == 0 goto l0_%=; \ 466 r1 = r6; \ 467 r2 = 0; \ 468 r3 = r0; \ 469 r4 = 8; \ 470 call %[bpf_skb_load_bytes]; \ 471l0_%=: exit; \ 472" : 473 : __imm(bpf_map_lookup_elem), 474 __imm(bpf_skb_load_bytes), 475 __imm_addr(map_array_wo) 476 : __clobber_all); 477} 478 479SEC("socket") 480__description("invalid read map access into a write-only array 1") 481__failure __msg("read from map forbidden") 482__failure_unpriv 483__naked void a_write_only_array_1_2(void) 484{ 485 asm volatile (" \ 486 r1 = 0; \ 487 *(u64*)(r10 - 8) = r1; \ 488 r2 = r10; \ 489 r2 += -8; \ 490 r1 = %[map_array_wo] ll; \ 491 call %[bpf_map_lookup_elem]; \ 492 if r0 == 0 goto l0_%=; \ 493 r0 = *(u64*)(r0 + 0); \ 494l0_%=: exit; \ 495" : 496 : __imm(bpf_map_lookup_elem), 497 __imm_addr(map_array_wo) 498 : __clobber_all); 499} 500 501SEC("tc") 502__description("invalid read map access into a write-only array 2") 503__failure __msg("read from map forbidden") 504__naked void a_write_only_array_2_2(void) 505{ 506 asm volatile (" \ 507 r1 = 0; \ 508 *(u64*)(r10 - 8) = r1; \ 509 r2 = r10; \ 510 r2 += -8; \ 511 r1 = %[map_array_wo] ll; \ 512 call %[bpf_map_lookup_elem]; \ 513 if r0 == 0 goto l0_%=; \ 514 r1 = r0; \ 515 r2 = 4; \ 516 r3 = 0; \ 517 r4 = 0; \ 518 r5 = 0; \ 519 call %[bpf_csum_diff]; \ 520l0_%=: exit; \ 521" : 522 : __imm(bpf_csum_diff), 523 __imm(bpf_map_lookup_elem), 524 __imm_addr(map_array_wo) 525 : __clobber_all); 526} 527 528char _license[] SEC("license") = "GPL";