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 10 struct test_val { 11 unsigned int index; 12 int foo[MAX_ENTRIES]; 13 }; 14 15 struct { 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 23 struct { 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 31 struct { 32 __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 33 __uint(max_entries, 2); 34 __type(key, __u32); 35 __type(value, struct test_val); 36 } map_array_pcpu SEC(".maps"); 37 38 struct { 39 __uint(type, BPF_MAP_TYPE_ARRAY); 40 __uint(max_entries, 2); 41 __type(key, __u32); 42 __type(value, struct test_val); 43 } map_array SEC(".maps"); 44 45 struct { 46 __uint(type, BPF_MAP_TYPE_HASH); 47 __uint(max_entries, 1); 48 __type(key, long long); 49 __type(value, struct test_val); 50 } map_hash_48b SEC(".maps"); 51 52 SEC("socket") 53 __description("valid map access into an array with a constant") 54 __success __failure_unpriv __msg_unpriv("R0 leaks addr") 55 __retval(0) 56 __naked void an_array_with_a_constant_1(void) 57 { 58 asm volatile (" \ 59 r1 = 0; \ 60 *(u64*)(r10 - 8) = r1; \ 61 r2 = r10; \ 62 r2 += -8; \ 63 r1 = %[map_hash_48b] ll; \ 64 call %[bpf_map_lookup_elem]; \ 65 if r0 == 0 goto l0_%=; \ 66 r1 = %[test_val_foo]; \ 67 *(u64*)(r0 + 0) = r1; \ 68 l0_%=: exit; \ 69 " : 70 : __imm(bpf_map_lookup_elem), 71 __imm_addr(map_hash_48b), 72 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 73 : __clobber_all); 74 } 75 76 SEC("socket") 77 __description("valid map access into an array with a register") 78 __success __failure_unpriv __msg_unpriv("R0 leaks addr") 79 __retval(0) __flag(BPF_F_ANY_ALIGNMENT) 80 __naked void an_array_with_a_register_1(void) 81 { 82 asm volatile (" \ 83 r1 = 0; \ 84 *(u64*)(r10 - 8) = r1; \ 85 r2 = r10; \ 86 r2 += -8; \ 87 r1 = %[map_hash_48b] ll; \ 88 call %[bpf_map_lookup_elem]; \ 89 if r0 == 0 goto l0_%=; \ 90 r1 = 4; \ 91 r1 <<= 2; \ 92 r0 += r1; \ 93 r1 = %[test_val_foo]; \ 94 *(u64*)(r0 + 0) = r1; \ 95 l0_%=: exit; \ 96 " : 97 : __imm(bpf_map_lookup_elem), 98 __imm_addr(map_hash_48b), 99 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 100 : __clobber_all); 101 } 102 103 SEC("socket") 104 __description("valid map access into an array with a variable") 105 __success __failure_unpriv __msg_unpriv("R0 leaks addr") 106 __retval(0) __flag(BPF_F_ANY_ALIGNMENT) 107 __naked void an_array_with_a_variable_1(void) 108 { 109 asm volatile (" \ 110 r1 = 0; \ 111 *(u64*)(r10 - 8) = r1; \ 112 r2 = r10; \ 113 r2 += -8; \ 114 r1 = %[map_hash_48b] ll; \ 115 call %[bpf_map_lookup_elem]; \ 116 if r0 == 0 goto l0_%=; \ 117 r1 = *(u32*)(r0 + 0); \ 118 if r1 >= %[max_entries] goto l0_%=; \ 119 r1 <<= 2; \ 120 r0 += r1; \ 121 r1 = %[test_val_foo]; \ 122 *(u64*)(r0 + 0) = r1; \ 123 l0_%=: exit; \ 124 " : 125 : __imm(bpf_map_lookup_elem), 126 __imm_addr(map_hash_48b), 127 __imm_const(max_entries, MAX_ENTRIES), 128 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 129 : __clobber_all); 130 } 131 132 SEC("socket") 133 __description("valid map access into an array with a signed variable") 134 __success __failure_unpriv __msg_unpriv("R0 leaks addr") 135 __retval(0) __flag(BPF_F_ANY_ALIGNMENT) 136 __naked void array_with_a_signed_variable(void) 137 { 138 asm volatile (" \ 139 r1 = 0; \ 140 *(u64*)(r10 - 8) = r1; \ 141 r2 = r10; \ 142 r2 += -8; \ 143 r1 = %[map_hash_48b] ll; \ 144 call %[bpf_map_lookup_elem]; \ 145 if r0 == 0 goto l0_%=; \ 146 r1 = *(u32*)(r0 + 0); \ 147 if w1 s> 0xffffffff goto l1_%=; \ 148 w1 = 0; \ 149 l1_%=: w2 = %[max_entries]; \ 150 if r2 s> r1 goto l2_%=; \ 151 w1 = 0; \ 152 l2_%=: w1 <<= 2; \ 153 r0 += r1; \ 154 r1 = %[test_val_foo]; \ 155 *(u64*)(r0 + 0) = r1; \ 156 l0_%=: exit; \ 157 " : 158 : __imm(bpf_map_lookup_elem), 159 __imm_addr(map_hash_48b), 160 __imm_const(max_entries, MAX_ENTRIES), 161 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 162 : __clobber_all); 163 } 164 165 SEC("socket") 166 __description("invalid map access into an array with a constant") 167 __failure __msg("invalid access to map value, value_size=48 off=48 size=8") 168 __failure_unpriv 169 __naked void an_array_with_a_constant_2(void) 170 { 171 asm volatile (" \ 172 r1 = 0; \ 173 *(u64*)(r10 - 8) = r1; \ 174 r2 = r10; \ 175 r2 += -8; \ 176 r1 = %[map_hash_48b] ll; \ 177 call %[bpf_map_lookup_elem]; \ 178 if r0 == 0 goto l0_%=; \ 179 r1 = %[test_val_foo]; \ 180 *(u64*)(r0 + %[__imm_0]) = r1; \ 181 l0_%=: exit; \ 182 " : 183 : __imm(bpf_map_lookup_elem), 184 __imm_addr(map_hash_48b), 185 __imm_const(__imm_0, (MAX_ENTRIES + 1) << 2), 186 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 187 : __clobber_all); 188 } 189 190 SEC("socket") 191 __description("invalid map access into an array with a register") 192 __failure __msg("R0 min value is outside of the allowed memory range") 193 __failure_unpriv 194 __flag(BPF_F_ANY_ALIGNMENT) 195 __naked void an_array_with_a_register_2(void) 196 { 197 asm volatile (" \ 198 r1 = 0; \ 199 *(u64*)(r10 - 8) = r1; \ 200 r2 = r10; \ 201 r2 += -8; \ 202 r1 = %[map_hash_48b] ll; \ 203 call %[bpf_map_lookup_elem]; \ 204 if r0 == 0 goto l0_%=; \ 205 r1 = %[__imm_0]; \ 206 r1 <<= 2; \ 207 r0 += r1; \ 208 r1 = %[test_val_foo]; \ 209 *(u64*)(r0 + 0) = r1; \ 210 l0_%=: exit; \ 211 " : 212 : __imm(bpf_map_lookup_elem), 213 __imm_addr(map_hash_48b), 214 __imm_const(__imm_0, MAX_ENTRIES + 1), 215 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 216 : __clobber_all); 217 } 218 219 SEC("socket") 220 __description("invalid map access into an array with a variable") 221 __failure 222 __msg("R0 unbounded memory access, make sure to bounds check any such access") 223 __failure_unpriv 224 __flag(BPF_F_ANY_ALIGNMENT) 225 __naked void an_array_with_a_variable_2(void) 226 { 227 asm volatile (" \ 228 r1 = 0; \ 229 *(u64*)(r10 - 8) = r1; \ 230 r2 = r10; \ 231 r2 += -8; \ 232 r1 = %[map_hash_48b] ll; \ 233 call %[bpf_map_lookup_elem]; \ 234 if r0 == 0 goto l0_%=; \ 235 r1 = *(u32*)(r0 + 0); \ 236 r1 <<= 2; \ 237 r0 += r1; \ 238 r1 = %[test_val_foo]; \ 239 *(u64*)(r0 + 0) = r1; \ 240 l0_%=: exit; \ 241 " : 242 : __imm(bpf_map_lookup_elem), 243 __imm_addr(map_hash_48b), 244 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 245 : __clobber_all); 246 } 247 248 SEC("socket") 249 __description("invalid map access into an array with no floor check") 250 __failure __msg("R0 unbounded memory access") 251 __failure_unpriv __msg_unpriv("R0 leaks addr") 252 __flag(BPF_F_ANY_ALIGNMENT) 253 __naked void array_with_no_floor_check(void) 254 { 255 asm volatile (" \ 256 r1 = 0; \ 257 *(u64*)(r10 - 8) = r1; \ 258 r2 = r10; \ 259 r2 += -8; \ 260 r1 = %[map_hash_48b] ll; \ 261 call %[bpf_map_lookup_elem]; \ 262 if r0 == 0 goto l0_%=; \ 263 r1 = *(u64*)(r0 + 0); \ 264 w2 = %[max_entries]; \ 265 if r2 s> r1 goto l1_%=; \ 266 w1 = 0; \ 267 l1_%=: w1 <<= 2; \ 268 r0 += r1; \ 269 r1 = %[test_val_foo]; \ 270 *(u64*)(r0 + 0) = r1; \ 271 l0_%=: exit; \ 272 " : 273 : __imm(bpf_map_lookup_elem), 274 __imm_addr(map_hash_48b), 275 __imm_const(max_entries, MAX_ENTRIES), 276 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 277 : __clobber_all); 278 } 279 280 SEC("socket") 281 __description("invalid map access into an array with a invalid max check") 282 __failure __msg("invalid access to map value, value_size=48 off=44 size=8") 283 __failure_unpriv __msg_unpriv("R0 leaks addr") 284 __flag(BPF_F_ANY_ALIGNMENT) 285 __naked void with_a_invalid_max_check_1(void) 286 { 287 asm volatile (" \ 288 r1 = 0; \ 289 *(u64*)(r10 - 8) = r1; \ 290 r2 = r10; \ 291 r2 += -8; \ 292 r1 = %[map_hash_48b] ll; \ 293 call %[bpf_map_lookup_elem]; \ 294 if r0 == 0 goto l0_%=; \ 295 r1 = *(u32*)(r0 + 0); \ 296 w2 = %[__imm_0]; \ 297 if r2 > r1 goto l1_%=; \ 298 w1 = 0; \ 299 l1_%=: w1 <<= 2; \ 300 r0 += r1; \ 301 r1 = %[test_val_foo]; \ 302 *(u64*)(r0 + 0) = r1; \ 303 l0_%=: exit; \ 304 " : 305 : __imm(bpf_map_lookup_elem), 306 __imm_addr(map_hash_48b), 307 __imm_const(__imm_0, MAX_ENTRIES + 1), 308 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 309 : __clobber_all); 310 } 311 312 SEC("socket") 313 __description("invalid map access into an array with a invalid max check") 314 __failure __msg("R0 pointer += pointer") 315 __failure_unpriv 316 __flag(BPF_F_ANY_ALIGNMENT) 317 __naked void with_a_invalid_max_check_2(void) 318 { 319 asm volatile (" \ 320 r1 = 0; \ 321 *(u64*)(r10 - 8) = r1; \ 322 r2 = r10; \ 323 r2 += -8; \ 324 r1 = %[map_hash_48b] ll; \ 325 call %[bpf_map_lookup_elem]; \ 326 if r0 == 0 goto l0_%=; \ 327 r8 = r0; \ 328 r1 = 0; \ 329 *(u64*)(r10 - 8) = r1; \ 330 r2 = r10; \ 331 r2 += -8; \ 332 r1 = %[map_hash_48b] ll; \ 333 call %[bpf_map_lookup_elem]; \ 334 if r0 == 0 goto l0_%=; \ 335 r0 += r8; \ 336 r0 = *(u32*)(r0 + %[test_val_foo]); \ 337 l0_%=: exit; \ 338 " : 339 : __imm(bpf_map_lookup_elem), 340 __imm_addr(map_hash_48b), 341 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 342 : __clobber_all); 343 } 344 345 SEC("socket") 346 __description("valid read map access into a read-only array 1") 347 __success __success_unpriv __retval(28) 348 __naked void a_read_only_array_1_1(void) 349 { 350 asm volatile (" \ 351 r1 = 0; \ 352 *(u64*)(r10 - 8) = r1; \ 353 r2 = r10; \ 354 r2 += -8; \ 355 r1 = %[map_array_ro] ll; \ 356 call %[bpf_map_lookup_elem]; \ 357 if r0 == 0 goto l0_%=; \ 358 r0 = *(u32*)(r0 + 0); \ 359 l0_%=: exit; \ 360 " : 361 : __imm(bpf_map_lookup_elem), 362 __imm_addr(map_array_ro) 363 : __clobber_all); 364 } 365 366 SEC("tc") 367 __description("valid read map access into a read-only array 2") 368 __success __retval(65507) 369 __naked void a_read_only_array_2_1(void) 370 { 371 asm volatile (" \ 372 r1 = 0; \ 373 *(u64*)(r10 - 8) = r1; \ 374 r2 = r10; \ 375 r2 += -8; \ 376 r1 = %[map_array_ro] ll; \ 377 call %[bpf_map_lookup_elem]; \ 378 if r0 == 0 goto l0_%=; \ 379 r1 = r0; \ 380 r2 = 4; \ 381 r3 = 0; \ 382 r4 = 0; \ 383 r5 = 0; \ 384 call %[bpf_csum_diff]; \ 385 l0_%=: exit; \ 386 " : 387 : __imm(bpf_csum_diff), 388 __imm(bpf_map_lookup_elem), 389 __imm_addr(map_array_ro) 390 : __clobber_all); 391 } 392 393 SEC("socket") 394 __description("invalid write map access into a read-only array 1") 395 __failure __msg("write into map forbidden") 396 __failure_unpriv 397 __naked void a_read_only_array_1_2(void) 398 { 399 asm volatile (" \ 400 r1 = 0; \ 401 *(u64*)(r10 - 8) = r1; \ 402 r2 = r10; \ 403 r2 += -8; \ 404 r1 = %[map_array_ro] ll; \ 405 call %[bpf_map_lookup_elem]; \ 406 if r0 == 0 goto l0_%=; \ 407 r1 = 42; \ 408 *(u64*)(r0 + 0) = r1; \ 409 l0_%=: exit; \ 410 " : 411 : __imm(bpf_map_lookup_elem), 412 __imm_addr(map_array_ro) 413 : __clobber_all); 414 } 415 416 SEC("tc") 417 __description("invalid write map access into a read-only array 2") 418 __failure __msg("write into map forbidden") 419 __naked void a_read_only_array_2_2(void) 420 { 421 asm volatile (" \ 422 r6 = r1; \ 423 r1 = 0; \ 424 *(u64*)(r10 - 8) = r1; \ 425 r2 = r10; \ 426 r2 += -8; \ 427 r1 = %[map_array_ro] ll; \ 428 call %[bpf_map_lookup_elem]; \ 429 if r0 == 0 goto l0_%=; \ 430 r1 = r6; \ 431 r2 = 0; \ 432 r3 = r0; \ 433 r4 = 8; \ 434 call %[bpf_skb_load_bytes]; \ 435 l0_%=: exit; \ 436 " : 437 : __imm(bpf_map_lookup_elem), 438 __imm(bpf_skb_load_bytes), 439 __imm_addr(map_array_ro) 440 : __clobber_all); 441 } 442 443 SEC("socket") 444 __description("valid write map access into a write-only array 1") 445 __success __success_unpriv __retval(1) 446 __naked void a_write_only_array_1_1(void) 447 { 448 asm volatile (" \ 449 r1 = 0; \ 450 *(u64*)(r10 - 8) = r1; \ 451 r2 = r10; \ 452 r2 += -8; \ 453 r1 = %[map_array_wo] ll; \ 454 call %[bpf_map_lookup_elem]; \ 455 if r0 == 0 goto l0_%=; \ 456 r1 = 42; \ 457 *(u64*)(r0 + 0) = r1; \ 458 l0_%=: r0 = 1; \ 459 exit; \ 460 " : 461 : __imm(bpf_map_lookup_elem), 462 __imm_addr(map_array_wo) 463 : __clobber_all); 464 } 465 466 SEC("tc") 467 __description("valid write map access into a write-only array 2") 468 __success __retval(0) 469 __naked void a_write_only_array_2_1(void) 470 { 471 asm volatile (" \ 472 r6 = r1; \ 473 r1 = 0; \ 474 *(u64*)(r10 - 8) = r1; \ 475 r2 = r10; \ 476 r2 += -8; \ 477 r1 = %[map_array_wo] ll; \ 478 call %[bpf_map_lookup_elem]; \ 479 if r0 == 0 goto l0_%=; \ 480 r1 = r6; \ 481 r2 = 0; \ 482 r3 = r0; \ 483 r4 = 8; \ 484 call %[bpf_skb_load_bytes]; \ 485 l0_%=: exit; \ 486 " : 487 : __imm(bpf_map_lookup_elem), 488 __imm(bpf_skb_load_bytes), 489 __imm_addr(map_array_wo) 490 : __clobber_all); 491 } 492 493 SEC("socket") 494 __description("invalid read map access into a write-only array 1") 495 __failure __msg("read from map forbidden") 496 __failure_unpriv 497 __naked void a_write_only_array_1_2(void) 498 { 499 asm volatile (" \ 500 r1 = 0; \ 501 *(u64*)(r10 - 8) = r1; \ 502 r2 = r10; \ 503 r2 += -8; \ 504 r1 = %[map_array_wo] ll; \ 505 call %[bpf_map_lookup_elem]; \ 506 if r0 == 0 goto l0_%=; \ 507 r0 = *(u64*)(r0 + 0); \ 508 l0_%=: exit; \ 509 " : 510 : __imm(bpf_map_lookup_elem), 511 __imm_addr(map_array_wo) 512 : __clobber_all); 513 } 514 515 SEC("tc") 516 __description("invalid read map access into a write-only array 2") 517 __failure __msg("read from map forbidden") 518 __naked void a_write_only_array_2_2(void) 519 { 520 asm volatile (" \ 521 r1 = 0; \ 522 *(u64*)(r10 - 8) = r1; \ 523 r2 = r10; \ 524 r2 += -8; \ 525 r1 = %[map_array_wo] ll; \ 526 call %[bpf_map_lookup_elem]; \ 527 if r0 == 0 goto l0_%=; \ 528 r1 = r0; \ 529 r2 = 4; \ 530 r3 = 0; \ 531 r4 = 0; \ 532 r5 = 0; \ 533 call %[bpf_csum_diff]; \ 534 l0_%=: exit; \ 535 " : 536 : __imm(bpf_csum_diff), 537 __imm(bpf_map_lookup_elem), 538 __imm_addr(map_array_wo) 539 : __clobber_all); 540 } 541 542 SEC("socket") 543 __description("valid map access into an array using constant without nullness") 544 __success __retval(4) __log_level(2) 545 __msg("mark_precise: frame0: regs= stack=-8 before {{[0-9]}}: ({{[a-f0-9]+}}) *(u32 *)(r10 -8) = {{(1|r[0-9])}}") 546 unsigned int an_array_with_a_constant_no_nullness(void) 547 { 548 /* Need 8-byte alignment for spill tracking */ 549 __u32 __attribute__((aligned(8))) key = 1; 550 struct test_val *val; 551 552 val = bpf_map_lookup_elem(&map_array, &key); 553 val->index = offsetof(struct test_val, foo); 554 555 return val->index; 556 } 557 558 SEC("socket") 559 __description("valid multiple map access into an array using constant without nullness") 560 __success __retval(8) __log_level(2) 561 __msg("mark_precise: frame0: regs= stack=-8 before {{[0-9]}}: ({{[a-f0-9]+}}) *(u32 *)(r10 -16) = {{(0|r[0-9])}}") 562 __msg("mark_precise: frame0: regs= stack=-8 before {{[0-9]}}: ({{[a-f0-9]+}}) *(u32 *)(r10 -8) = {{(1|r[0-9])}}") 563 unsigned int multiple_array_with_a_constant_no_nullness(void) 564 { 565 __u32 __attribute__((aligned(8))) key = 1; 566 __u32 __attribute__((aligned(8))) key2 = 0; 567 struct test_val *val, *val2; 568 569 val = bpf_map_lookup_elem(&map_array, &key); 570 val->index = offsetof(struct test_val, foo); 571 572 val2 = bpf_map_lookup_elem(&map_array, &key2); 573 val2->index = offsetof(struct test_val, foo); 574 575 return val->index + val2->index; 576 } 577 578 SEC("socket") 579 __description("valid map access into an array using natural aligned 32-bit constant 0 without nullness") 580 __success __retval(4) 581 unsigned int an_array_with_a_32bit_constant_0_no_nullness(void) 582 { 583 /* Unlike the above tests, 32-bit zeroing is precisely tracked even 584 * if writes are not aligned to BPF_REG_SIZE. This tests that our 585 * STACK_ZERO handling functions. 586 */ 587 struct test_val *val; 588 __u32 key = 0; 589 590 val = bpf_map_lookup_elem(&map_array, &key); 591 val->index = offsetof(struct test_val, foo); 592 593 return val->index; 594 } 595 596 SEC("socket") 597 __description("valid map access into a pcpu array using constant without nullness") 598 __success __retval(4) __log_level(2) 599 __msg("mark_precise: frame0: regs= stack=-8 before {{[0-9]}}: ({{[a-f0-9]+}}) *(u32 *)(r10 -8) = {{(1|r[0-9])}}") 600 unsigned int a_pcpu_array_with_a_constant_no_nullness(void) 601 { 602 __u32 __attribute__((aligned(8))) key = 1; 603 struct test_val *val; 604 605 val = bpf_map_lookup_elem(&map_array_pcpu, &key); 606 val->index = offsetof(struct test_val, foo); 607 608 return val->index; 609 } 610 611 SEC("socket") 612 __description("invalid map access into an array using constant without nullness") 613 __failure __msg("R0 invalid mem access 'map_value_or_null'") 614 unsigned int an_array_with_a_constant_no_nullness_out_of_bounds(void) 615 { 616 /* Out of bounds */ 617 __u32 __attribute__((aligned(8))) key = 3; 618 struct test_val *val; 619 620 val = bpf_map_lookup_elem(&map_array, &key); 621 val->index = offsetof(struct test_val, foo); 622 623 return val->index; 624 } 625 626 SEC("socket") 627 __description("invalid map access into an array using constant smaller than key_size") 628 __failure __msg("R0 invalid mem access 'map_value_or_null'") 629 unsigned int an_array_with_a_constant_too_small(void) 630 { 631 __u32 __attribute__((aligned(8))) key; 632 struct test_val *val; 633 634 /* Mark entire key as STACK_MISC */ 635 bpf_probe_read_user(&key, sizeof(key), NULL); 636 637 /* Spilling only the bottom byte results in a tnum const of 1. 638 * We want to check that the verifier rejects it, as the spill is < 4B. 639 */ 640 *(__u8 *)&key = 1; 641 val = bpf_map_lookup_elem(&map_array, &key); 642 643 /* Should fail, as verifier cannot prove in-bound lookup */ 644 val->index = offsetof(struct test_val, foo); 645 646 return val->index; 647 } 648 649 SEC("socket") 650 __description("invalid map access into an array using constant larger than key_size") 651 __failure __msg("R0 invalid mem access 'map_value_or_null'") 652 unsigned int an_array_with_a_constant_too_big(void) 653 { 654 struct test_val *val; 655 __u64 key = 1; 656 657 /* Even if the constant value is < max_entries, if the spill size is 658 * larger than the key size, the set bits may not be where we expect them 659 * to be on different endian architectures. 660 */ 661 val = bpf_map_lookup_elem(&map_array, &key); 662 val->index = offsetof(struct test_val, foo); 663 664 return val->index; 665 } 666 667 SEC("socket") 668 __description("invalid elided lookup using const and non-const key") 669 __failure __msg("R0 invalid mem access 'map_value_or_null'") 670 unsigned int mixed_const_and_non_const_key_lookup(void) 671 { 672 __u32 __attribute__((aligned(8))) key; 673 struct test_val *val; 674 __u32 rand; 675 676 rand = bpf_get_prandom_u32(); 677 key = rand > 42 ? 1 : rand; 678 val = bpf_map_lookup_elem(&map_array, &key); 679 680 return val->index; 681 } 682 683 SEC("socket") 684 __failure __msg("invalid read from stack R2 off=4096 size=4") 685 __naked void key_lookup_at_invalid_fp(void) 686 { 687 asm volatile (" \ 688 r1 = %[map_array] ll; \ 689 r2 = r10; \ 690 r2 += 4096; \ 691 call %[bpf_map_lookup_elem]; \ 692 r0 = *(u64*)(r0 + 0); \ 693 exit; \ 694 " : 695 : __imm(bpf_map_lookup_elem), 696 __imm_addr(map_array) 697 : __clobber_all); 698 } 699 700 volatile __u32 __attribute__((aligned(8))) global_key; 701 702 SEC("socket") 703 __description("invalid elided lookup using non-stack key") 704 __failure __msg("R0 invalid mem access 'map_value_or_null'") 705 unsigned int non_stack_key_lookup(void) 706 { 707 struct test_val *val; 708 709 global_key = 1; 710 val = bpf_map_lookup_elem(&map_array, (void *)&global_key); 711 val->index = offsetof(struct test_val, foo); 712 713 return val->index; 714 } 715 716 char _license[] SEC("license") = "GPL"; 717