1 // SPDX-License-Identifier: GPL-2.0 2 /* Converted from tools/testing/selftests/bpf/verifier/helper_value_access.c */ 3 4 #include <linux/bpf.h> 5 #include <bpf/bpf_helpers.h> 6 #include "bpf_misc.h" 7 8 struct other_val { 9 long long foo; 10 long long bar; 11 }; 12 13 struct { 14 __uint(type, BPF_MAP_TYPE_HASH); 15 __uint(max_entries, 1); 16 __type(key, long long); 17 __type(value, struct other_val); 18 } map_hash_16b SEC(".maps"); 19 20 #define MAX_ENTRIES 11 21 22 struct test_val { 23 unsigned int index; 24 int foo[MAX_ENTRIES]; 25 }; 26 27 struct { 28 __uint(type, BPF_MAP_TYPE_HASH); 29 __uint(max_entries, 1); 30 __type(key, long long); 31 __type(value, struct test_val); 32 } map_hash_48b SEC(".maps"); 33 34 struct { 35 __uint(type, BPF_MAP_TYPE_HASH); 36 __uint(max_entries, 1); 37 __type(key, long long); 38 __type(value, long long); 39 } map_hash_8b SEC(".maps"); 40 41 SEC("tracepoint") 42 __description("helper access to map: full range") 43 __success 44 __naked void access_to_map_full_range(void) 45 { 46 asm volatile (" \ 47 r2 = r10; \ 48 r2 += -8; \ 49 r1 = 0; \ 50 *(u64*)(r2 + 0) = r1; \ 51 r1 = %[map_hash_48b] ll; \ 52 call %[bpf_map_lookup_elem]; \ 53 if r0 == 0 goto l0_%=; \ 54 r1 = r0; \ 55 r2 = %[sizeof_test_val]; \ 56 r3 = 0; \ 57 call %[bpf_probe_read_kernel]; \ 58 l0_%=: exit; \ 59 " : 60 : __imm(bpf_map_lookup_elem), 61 __imm(bpf_probe_read_kernel), 62 __imm_addr(map_hash_48b), 63 __imm_const(sizeof_test_val, sizeof(struct test_val)) 64 : __clobber_all); 65 } 66 67 SEC("tracepoint") 68 __description("helper access to map: partial range") 69 __success 70 __naked void access_to_map_partial_range(void) 71 { 72 asm volatile (" \ 73 r2 = r10; \ 74 r2 += -8; \ 75 r1 = 0; \ 76 *(u64*)(r2 + 0) = r1; \ 77 r1 = %[map_hash_48b] ll; \ 78 call %[bpf_map_lookup_elem]; \ 79 if r0 == 0 goto l0_%=; \ 80 r1 = r0; \ 81 r2 = 8; \ 82 r3 = 0; \ 83 call %[bpf_probe_read_kernel]; \ 84 l0_%=: exit; \ 85 " : 86 : __imm(bpf_map_lookup_elem), 87 __imm(bpf_probe_read_kernel), 88 __imm_addr(map_hash_48b) 89 : __clobber_all); 90 } 91 92 /* Call a function taking a pointer and a size which doesn't allow the size to 93 * be zero (i.e. bpf_trace_printk() declares the second argument to be 94 * ARG_CONST_SIZE, not ARG_CONST_SIZE_OR_ZERO). We attempt to pass zero for the 95 * size and expect to fail. 96 */ 97 SEC("tracepoint") 98 __description("helper access to map: empty range") 99 __failure __msg("R2 invalid zero-sized read: u64=[0,0]") 100 __naked void access_to_map_empty_range(void) 101 { 102 asm volatile (" \ 103 r2 = r10; \ 104 r2 += -8; \ 105 r1 = 0; \ 106 *(u64*)(r2 + 0) = r1; \ 107 r1 = %[map_hash_48b] ll; \ 108 call %[bpf_map_lookup_elem]; \ 109 if r0 == 0 goto l0_%=; \ 110 r1 = r0; \ 111 r2 = 0; \ 112 call %[bpf_trace_printk]; \ 113 l0_%=: exit; \ 114 " : 115 : __imm(bpf_map_lookup_elem), 116 __imm(bpf_trace_printk), 117 __imm_addr(map_hash_48b) 118 : __clobber_all); 119 } 120 121 /* Like the test above, but this time the size register is not known to be zero; 122 * its lower-bound is zero though, which is still unacceptable. 123 */ 124 SEC("tracepoint") 125 __description("helper access to map: possibly-empty ange") 126 __failure __msg("R2 invalid zero-sized read: u64=[0,4]") 127 __naked void access_to_map_possibly_empty_range(void) 128 { 129 asm volatile (" \ 130 r2 = r10; \ 131 r2 += -8; \ 132 r1 = 0; \ 133 *(u64*)(r2 + 0) = r1; \ 134 r1 = %[map_hash_48b] ll; \ 135 call %[bpf_map_lookup_elem]; \ 136 if r0 == 0 goto l0_%=; \ 137 r1 = r0; \ 138 /* Read an unknown value */ \ 139 r7 = *(u64*)(r0 + 0); \ 140 /* Make it small and positive, to avoid other errors */ \ 141 r7 &= 4; \ 142 r2 = 0; \ 143 r2 += r7; \ 144 call %[bpf_trace_printk]; \ 145 l0_%=: exit; \ 146 " : 147 : __imm(bpf_map_lookup_elem), 148 __imm(bpf_trace_printk), 149 __imm_addr(map_hash_48b) 150 : __clobber_all); 151 } 152 153 SEC("tracepoint") 154 __description("helper access to map: out-of-bound range") 155 __failure __msg("invalid access to map value, value_size=48 off=0 size=56") 156 __naked void map_out_of_bound_range(void) 157 { 158 asm volatile (" \ 159 r2 = r10; \ 160 r2 += -8; \ 161 r1 = 0; \ 162 *(u64*)(r2 + 0) = r1; \ 163 r1 = %[map_hash_48b] ll; \ 164 call %[bpf_map_lookup_elem]; \ 165 if r0 == 0 goto l0_%=; \ 166 r1 = r0; \ 167 r2 = %[__imm_0]; \ 168 r3 = 0; \ 169 call %[bpf_probe_read_kernel]; \ 170 l0_%=: exit; \ 171 " : 172 : __imm(bpf_map_lookup_elem), 173 __imm(bpf_probe_read_kernel), 174 __imm_addr(map_hash_48b), 175 __imm_const(__imm_0, sizeof(struct test_val) + 8) 176 : __clobber_all); 177 } 178 179 SEC("tracepoint") 180 __description("helper access to map: negative range") 181 __failure __msg("R2 min value is negative") 182 __naked void access_to_map_negative_range(void) 183 { 184 asm volatile (" \ 185 r2 = r10; \ 186 r2 += -8; \ 187 r1 = 0; \ 188 *(u64*)(r2 + 0) = r1; \ 189 r1 = %[map_hash_48b] ll; \ 190 call %[bpf_map_lookup_elem]; \ 191 if r0 == 0 goto l0_%=; \ 192 r1 = r0; \ 193 r2 = -8; \ 194 r3 = 0; \ 195 call %[bpf_probe_read_kernel]; \ 196 l0_%=: exit; \ 197 " : 198 : __imm(bpf_map_lookup_elem), 199 __imm(bpf_probe_read_kernel), 200 __imm_addr(map_hash_48b) 201 : __clobber_all); 202 } 203 204 SEC("tracepoint") 205 __description("helper access to adjusted map (via const imm): full range") 206 __success 207 __naked void via_const_imm_full_range(void) 208 { 209 asm volatile (" \ 210 r2 = r10; \ 211 r2 += -8; \ 212 r1 = 0; \ 213 *(u64*)(r2 + 0) = r1; \ 214 r1 = %[map_hash_48b] ll; \ 215 call %[bpf_map_lookup_elem]; \ 216 if r0 == 0 goto l0_%=; \ 217 r1 = r0; \ 218 r1 += %[test_val_foo]; \ 219 r2 = %[__imm_0]; \ 220 r3 = 0; \ 221 call %[bpf_probe_read_kernel]; \ 222 l0_%=: exit; \ 223 " : 224 : __imm(bpf_map_lookup_elem), 225 __imm(bpf_probe_read_kernel), 226 __imm_addr(map_hash_48b), 227 __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo)), 228 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 229 : __clobber_all); 230 } 231 232 SEC("tracepoint") 233 __description("helper access to adjusted map (via const imm): partial range") 234 __success 235 __naked void via_const_imm_partial_range(void) 236 { 237 asm volatile (" \ 238 r2 = r10; \ 239 r2 += -8; \ 240 r1 = 0; \ 241 *(u64*)(r2 + 0) = r1; \ 242 r1 = %[map_hash_48b] ll; \ 243 call %[bpf_map_lookup_elem]; \ 244 if r0 == 0 goto l0_%=; \ 245 r1 = r0; \ 246 r1 += %[test_val_foo]; \ 247 r2 = 8; \ 248 r3 = 0; \ 249 call %[bpf_probe_read_kernel]; \ 250 l0_%=: exit; \ 251 " : 252 : __imm(bpf_map_lookup_elem), 253 __imm(bpf_probe_read_kernel), 254 __imm_addr(map_hash_48b), 255 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 256 : __clobber_all); 257 } 258 259 SEC("tracepoint") 260 __description("helper access to adjusted map (via const imm): empty range") 261 __failure __msg("R2 invalid zero-sized read") 262 __naked void via_const_imm_empty_range(void) 263 { 264 asm volatile (" \ 265 r2 = r10; \ 266 r2 += -8; \ 267 r1 = 0; \ 268 *(u64*)(r2 + 0) = r1; \ 269 r1 = %[map_hash_48b] ll; \ 270 call %[bpf_map_lookup_elem]; \ 271 if r0 == 0 goto l0_%=; \ 272 r1 = r0; \ 273 r1 += %[test_val_foo]; \ 274 r2 = 0; \ 275 call %[bpf_trace_printk]; \ 276 l0_%=: exit; \ 277 " : 278 : __imm(bpf_map_lookup_elem), 279 __imm(bpf_trace_printk), 280 __imm_addr(map_hash_48b), 281 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 282 : __clobber_all); 283 } 284 285 SEC("tracepoint") 286 __description("helper access to adjusted map (via const imm): out-of-bound range") 287 __failure __msg("invalid access to map value, value_size=48 off=4 size=52") 288 __naked void imm_out_of_bound_range(void) 289 { 290 asm volatile (" \ 291 r2 = r10; \ 292 r2 += -8; \ 293 r1 = 0; \ 294 *(u64*)(r2 + 0) = r1; \ 295 r1 = %[map_hash_48b] ll; \ 296 call %[bpf_map_lookup_elem]; \ 297 if r0 == 0 goto l0_%=; \ 298 r1 = r0; \ 299 r1 += %[test_val_foo]; \ 300 r2 = %[__imm_0]; \ 301 r3 = 0; \ 302 call %[bpf_probe_read_kernel]; \ 303 l0_%=: exit; \ 304 " : 305 : __imm(bpf_map_lookup_elem), 306 __imm(bpf_probe_read_kernel), 307 __imm_addr(map_hash_48b), 308 __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo) + 8), 309 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 310 : __clobber_all); 311 } 312 313 SEC("tracepoint") 314 __description("helper access to adjusted map (via const imm): negative range (> adjustment)") 315 __failure __msg("R2 min value is negative") 316 __naked void const_imm_negative_range_adjustment_1(void) 317 { 318 asm volatile (" \ 319 r2 = r10; \ 320 r2 += -8; \ 321 r1 = 0; \ 322 *(u64*)(r2 + 0) = r1; \ 323 r1 = %[map_hash_48b] ll; \ 324 call %[bpf_map_lookup_elem]; \ 325 if r0 == 0 goto l0_%=; \ 326 r1 = r0; \ 327 r1 += %[test_val_foo]; \ 328 r2 = -8; \ 329 r3 = 0; \ 330 call %[bpf_probe_read_kernel]; \ 331 l0_%=: exit; \ 332 " : 333 : __imm(bpf_map_lookup_elem), 334 __imm(bpf_probe_read_kernel), 335 __imm_addr(map_hash_48b), 336 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 337 : __clobber_all); 338 } 339 340 SEC("tracepoint") 341 __description("helper access to adjusted map (via const imm): negative range (< adjustment)") 342 __failure __msg("R2 min value is negative") 343 __naked void const_imm_negative_range_adjustment_2(void) 344 { 345 asm volatile (" \ 346 r2 = r10; \ 347 r2 += -8; \ 348 r1 = 0; \ 349 *(u64*)(r2 + 0) = r1; \ 350 r1 = %[map_hash_48b] ll; \ 351 call %[bpf_map_lookup_elem]; \ 352 if r0 == 0 goto l0_%=; \ 353 r1 = r0; \ 354 r1 += %[test_val_foo]; \ 355 r2 = -1; \ 356 r3 = 0; \ 357 call %[bpf_probe_read_kernel]; \ 358 l0_%=: exit; \ 359 " : 360 : __imm(bpf_map_lookup_elem), 361 __imm(bpf_probe_read_kernel), 362 __imm_addr(map_hash_48b), 363 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 364 : __clobber_all); 365 } 366 367 SEC("tracepoint") 368 __description("helper access to adjusted map (via const reg): full range") 369 __success 370 __naked void via_const_reg_full_range(void) 371 { 372 asm volatile (" \ 373 r2 = r10; \ 374 r2 += -8; \ 375 r1 = 0; \ 376 *(u64*)(r2 + 0) = r1; \ 377 r1 = %[map_hash_48b] ll; \ 378 call %[bpf_map_lookup_elem]; \ 379 if r0 == 0 goto l0_%=; \ 380 r1 = r0; \ 381 r3 = %[test_val_foo]; \ 382 r1 += r3; \ 383 r2 = %[__imm_0]; \ 384 r3 = 0; \ 385 call %[bpf_probe_read_kernel]; \ 386 l0_%=: exit; \ 387 " : 388 : __imm(bpf_map_lookup_elem), 389 __imm(bpf_probe_read_kernel), 390 __imm_addr(map_hash_48b), 391 __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo)), 392 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 393 : __clobber_all); 394 } 395 396 SEC("tracepoint") 397 __description("helper access to adjusted map (via const reg): partial range") 398 __success 399 __naked void via_const_reg_partial_range(void) 400 { 401 asm volatile (" \ 402 r2 = r10; \ 403 r2 += -8; \ 404 r1 = 0; \ 405 *(u64*)(r2 + 0) = r1; \ 406 r1 = %[map_hash_48b] ll; \ 407 call %[bpf_map_lookup_elem]; \ 408 if r0 == 0 goto l0_%=; \ 409 r1 = r0; \ 410 r3 = %[test_val_foo]; \ 411 r1 += r3; \ 412 r2 = 8; \ 413 r3 = 0; \ 414 call %[bpf_probe_read_kernel]; \ 415 l0_%=: exit; \ 416 " : 417 : __imm(bpf_map_lookup_elem), 418 __imm(bpf_probe_read_kernel), 419 __imm_addr(map_hash_48b), 420 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 421 : __clobber_all); 422 } 423 424 SEC("tracepoint") 425 __description("helper access to adjusted map (via const reg): empty range") 426 __failure __msg("R2 invalid zero-sized read") 427 __naked void via_const_reg_empty_range(void) 428 { 429 asm volatile (" \ 430 r2 = r10; \ 431 r2 += -8; \ 432 r1 = 0; \ 433 *(u64*)(r2 + 0) = r1; \ 434 r1 = %[map_hash_48b] ll; \ 435 call %[bpf_map_lookup_elem]; \ 436 if r0 == 0 goto l0_%=; \ 437 r1 = r0; \ 438 r3 = 0; \ 439 r1 += r3; \ 440 r2 = 0; \ 441 call %[bpf_trace_printk]; \ 442 l0_%=: exit; \ 443 " : 444 : __imm(bpf_map_lookup_elem), 445 __imm(bpf_trace_printk), 446 __imm_addr(map_hash_48b) 447 : __clobber_all); 448 } 449 450 SEC("tracepoint") 451 __description("helper access to adjusted map (via const reg): out-of-bound range") 452 __failure __msg("invalid access to map value, value_size=48 off=4 size=52") 453 __naked void reg_out_of_bound_range(void) 454 { 455 asm volatile (" \ 456 r2 = r10; \ 457 r2 += -8; \ 458 r1 = 0; \ 459 *(u64*)(r2 + 0) = r1; \ 460 r1 = %[map_hash_48b] ll; \ 461 call %[bpf_map_lookup_elem]; \ 462 if r0 == 0 goto l0_%=; \ 463 r1 = r0; \ 464 r3 = %[test_val_foo]; \ 465 r1 += r3; \ 466 r2 = %[__imm_0]; \ 467 r3 = 0; \ 468 call %[bpf_probe_read_kernel]; \ 469 l0_%=: exit; \ 470 " : 471 : __imm(bpf_map_lookup_elem), 472 __imm(bpf_probe_read_kernel), 473 __imm_addr(map_hash_48b), 474 __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo) + 8), 475 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 476 : __clobber_all); 477 } 478 479 SEC("tracepoint") 480 __description("helper access to adjusted map (via const reg): negative range (> adjustment)") 481 __failure __msg("R2 min value is negative") 482 __naked void const_reg_negative_range_adjustment_1(void) 483 { 484 asm volatile (" \ 485 r2 = r10; \ 486 r2 += -8; \ 487 r1 = 0; \ 488 *(u64*)(r2 + 0) = r1; \ 489 r1 = %[map_hash_48b] ll; \ 490 call %[bpf_map_lookup_elem]; \ 491 if r0 == 0 goto l0_%=; \ 492 r1 = r0; \ 493 r3 = %[test_val_foo]; \ 494 r1 += r3; \ 495 r2 = -8; \ 496 r3 = 0; \ 497 call %[bpf_probe_read_kernel]; \ 498 l0_%=: exit; \ 499 " : 500 : __imm(bpf_map_lookup_elem), 501 __imm(bpf_probe_read_kernel), 502 __imm_addr(map_hash_48b), 503 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 504 : __clobber_all); 505 } 506 507 SEC("tracepoint") 508 __description("helper access to adjusted map (via const reg): negative range (< adjustment)") 509 __failure __msg("R2 min value is negative") 510 __naked void const_reg_negative_range_adjustment_2(void) 511 { 512 asm volatile (" \ 513 r2 = r10; \ 514 r2 += -8; \ 515 r1 = 0; \ 516 *(u64*)(r2 + 0) = r1; \ 517 r1 = %[map_hash_48b] ll; \ 518 call %[bpf_map_lookup_elem]; \ 519 if r0 == 0 goto l0_%=; \ 520 r1 = r0; \ 521 r3 = %[test_val_foo]; \ 522 r1 += r3; \ 523 r2 = -1; \ 524 r3 = 0; \ 525 call %[bpf_probe_read_kernel]; \ 526 l0_%=: exit; \ 527 " : 528 : __imm(bpf_map_lookup_elem), 529 __imm(bpf_probe_read_kernel), 530 __imm_addr(map_hash_48b), 531 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 532 : __clobber_all); 533 } 534 535 SEC("tracepoint") 536 __description("helper access to adjusted map (via variable): full range") 537 __success 538 __naked void map_via_variable_full_range(void) 539 { 540 asm volatile (" \ 541 r2 = r10; \ 542 r2 += -8; \ 543 r1 = 0; \ 544 *(u64*)(r2 + 0) = r1; \ 545 r1 = %[map_hash_48b] ll; \ 546 call %[bpf_map_lookup_elem]; \ 547 if r0 == 0 goto l0_%=; \ 548 r1 = r0; \ 549 r3 = *(u32*)(r0 + 0); \ 550 if r3 > %[test_val_foo] goto l0_%=; \ 551 r1 += r3; \ 552 r2 = %[__imm_0]; \ 553 r3 = 0; \ 554 call %[bpf_probe_read_kernel]; \ 555 l0_%=: exit; \ 556 " : 557 : __imm(bpf_map_lookup_elem), 558 __imm(bpf_probe_read_kernel), 559 __imm_addr(map_hash_48b), 560 __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo)), 561 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 562 : __clobber_all); 563 } 564 565 SEC("tracepoint") 566 __description("helper access to adjusted map (via variable): partial range") 567 __success 568 __naked void map_via_variable_partial_range(void) 569 { 570 asm volatile (" \ 571 r2 = r10; \ 572 r2 += -8; \ 573 r1 = 0; \ 574 *(u64*)(r2 + 0) = r1; \ 575 r1 = %[map_hash_48b] ll; \ 576 call %[bpf_map_lookup_elem]; \ 577 if r0 == 0 goto l0_%=; \ 578 r1 = r0; \ 579 r3 = *(u32*)(r0 + 0); \ 580 if r3 > %[test_val_foo] goto l0_%=; \ 581 r1 += r3; \ 582 r2 = 8; \ 583 r3 = 0; \ 584 call %[bpf_probe_read_kernel]; \ 585 l0_%=: exit; \ 586 " : 587 : __imm(bpf_map_lookup_elem), 588 __imm(bpf_probe_read_kernel), 589 __imm_addr(map_hash_48b), 590 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 591 : __clobber_all); 592 } 593 594 SEC("tracepoint") 595 __description("helper access to adjusted map (via variable): empty range") 596 __failure __msg("R2 invalid zero-sized read") 597 __naked void map_via_variable_empty_range(void) 598 { 599 asm volatile (" \ 600 r2 = r10; \ 601 r2 += -8; \ 602 r1 = 0; \ 603 *(u64*)(r2 + 0) = r1; \ 604 r1 = %[map_hash_48b] ll; \ 605 call %[bpf_map_lookup_elem]; \ 606 if r0 == 0 goto l0_%=; \ 607 r1 = r0; \ 608 r3 = *(u32*)(r0 + 0); \ 609 if r3 > %[test_val_foo] goto l0_%=; \ 610 r1 += r3; \ 611 r2 = 0; \ 612 call %[bpf_trace_printk]; \ 613 l0_%=: exit; \ 614 " : 615 : __imm(bpf_map_lookup_elem), 616 __imm(bpf_trace_printk), 617 __imm_addr(map_hash_48b), 618 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 619 : __clobber_all); 620 } 621 622 SEC("tracepoint") 623 __description("helper access to adjusted map (via variable): no max check") 624 __failure __msg("R1 unbounded memory access") 625 __naked void via_variable_no_max_check_1(void) 626 { 627 asm volatile (" \ 628 r2 = r10; \ 629 r2 += -8; \ 630 r1 = 0; \ 631 *(u64*)(r2 + 0) = r1; \ 632 r1 = %[map_hash_48b] ll; \ 633 call %[bpf_map_lookup_elem]; \ 634 if r0 == 0 goto l0_%=; \ 635 r1 = r0; \ 636 r3 = *(u32*)(r0 + 0); \ 637 r1 += r3; \ 638 r2 = 1; \ 639 r3 = 0; \ 640 call %[bpf_probe_read_kernel]; \ 641 l0_%=: exit; \ 642 " : 643 : __imm(bpf_map_lookup_elem), 644 __imm(bpf_probe_read_kernel), 645 __imm_addr(map_hash_48b) 646 : __clobber_all); 647 } 648 649 SEC("tracepoint") 650 __description("helper access to adjusted map (via variable): wrong max check") 651 __failure __msg("invalid access to map value, value_size=48 off=4 size=45") 652 __naked void via_variable_wrong_max_check_1(void) 653 { 654 asm volatile (" \ 655 r2 = r10; \ 656 r2 += -8; \ 657 r1 = 0; \ 658 *(u64*)(r2 + 0) = r1; \ 659 r1 = %[map_hash_48b] ll; \ 660 call %[bpf_map_lookup_elem]; \ 661 if r0 == 0 goto l0_%=; \ 662 r1 = r0; \ 663 r3 = *(u32*)(r0 + 0); \ 664 if r3 > %[test_val_foo] goto l0_%=; \ 665 r1 += r3; \ 666 r2 = %[__imm_0]; \ 667 r3 = 0; \ 668 call %[bpf_probe_read_kernel]; \ 669 l0_%=: exit; \ 670 " : 671 : __imm(bpf_map_lookup_elem), 672 __imm(bpf_probe_read_kernel), 673 __imm_addr(map_hash_48b), 674 __imm_const(__imm_0, sizeof(struct test_val) - offsetof(struct test_val, foo) + 1), 675 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 676 : __clobber_all); 677 } 678 679 SEC("tracepoint") 680 __description("helper access to map: bounds check using <, good access") 681 __success 682 __naked void bounds_check_using_good_access_1(void) 683 { 684 asm volatile (" \ 685 r2 = r10; \ 686 r2 += -8; \ 687 r1 = 0; \ 688 *(u64*)(r2 + 0) = r1; \ 689 r1 = %[map_hash_48b] ll; \ 690 call %[bpf_map_lookup_elem]; \ 691 if r0 == 0 goto l0_%=; \ 692 r1 = r0; \ 693 r3 = *(u32*)(r0 + 0); \ 694 if r3 < 32 goto l1_%=; \ 695 r0 = 0; \ 696 l0_%=: exit; \ 697 l1_%=: r1 += r3; \ 698 r0 = 0; \ 699 *(u8*)(r1 + 0) = r0; \ 700 r0 = 0; \ 701 exit; \ 702 " : 703 : __imm(bpf_map_lookup_elem), 704 __imm_addr(map_hash_48b) 705 : __clobber_all); 706 } 707 708 SEC("tracepoint") 709 __description("helper access to map: bounds check using <, bad access") 710 __failure __msg("R1 unbounded memory access") 711 __naked void bounds_check_using_bad_access_1(void) 712 { 713 asm volatile (" \ 714 r2 = r10; \ 715 r2 += -8; \ 716 r1 = 0; \ 717 *(u64*)(r2 + 0) = r1; \ 718 r1 = %[map_hash_48b] ll; \ 719 call %[bpf_map_lookup_elem]; \ 720 if r0 == 0 goto l0_%=; \ 721 r1 = r0; \ 722 r3 = *(u32*)(r0 + 0); \ 723 if r3 < 32 goto l1_%=; \ 724 r1 += r3; \ 725 l0_%=: r0 = 0; \ 726 *(u8*)(r1 + 0) = r0; \ 727 r0 = 0; \ 728 exit; \ 729 l1_%=: r0 = 0; \ 730 exit; \ 731 " : 732 : __imm(bpf_map_lookup_elem), 733 __imm_addr(map_hash_48b) 734 : __clobber_all); 735 } 736 737 SEC("tracepoint") 738 __description("helper access to map: bounds check using <=, good access") 739 __success 740 __naked void bounds_check_using_good_access_2(void) 741 { 742 asm volatile (" \ 743 r2 = r10; \ 744 r2 += -8; \ 745 r1 = 0; \ 746 *(u64*)(r2 + 0) = r1; \ 747 r1 = %[map_hash_48b] ll; \ 748 call %[bpf_map_lookup_elem]; \ 749 if r0 == 0 goto l0_%=; \ 750 r1 = r0; \ 751 r3 = *(u32*)(r0 + 0); \ 752 if r3 <= 32 goto l1_%=; \ 753 r0 = 0; \ 754 l0_%=: exit; \ 755 l1_%=: r1 += r3; \ 756 r0 = 0; \ 757 *(u8*)(r1 + 0) = r0; \ 758 r0 = 0; \ 759 exit; \ 760 " : 761 : __imm(bpf_map_lookup_elem), 762 __imm_addr(map_hash_48b) 763 : __clobber_all); 764 } 765 766 SEC("tracepoint") 767 __description("helper access to map: bounds check using <=, bad access") 768 __failure __msg("R1 unbounded memory access") 769 __naked void bounds_check_using_bad_access_2(void) 770 { 771 asm volatile (" \ 772 r2 = r10; \ 773 r2 += -8; \ 774 r1 = 0; \ 775 *(u64*)(r2 + 0) = r1; \ 776 r1 = %[map_hash_48b] ll; \ 777 call %[bpf_map_lookup_elem]; \ 778 if r0 == 0 goto l0_%=; \ 779 r1 = r0; \ 780 r3 = *(u32*)(r0 + 0); \ 781 if r3 <= 32 goto l1_%=; \ 782 r1 += r3; \ 783 l0_%=: r0 = 0; \ 784 *(u8*)(r1 + 0) = r0; \ 785 r0 = 0; \ 786 exit; \ 787 l1_%=: r0 = 0; \ 788 exit; \ 789 " : 790 : __imm(bpf_map_lookup_elem), 791 __imm_addr(map_hash_48b) 792 : __clobber_all); 793 } 794 795 SEC("tracepoint") 796 __description("helper access to map: bounds check using s<, good access") 797 __success 798 __naked void check_using_s_good_access_1(void) 799 { 800 asm volatile (" \ 801 r2 = r10; \ 802 r2 += -8; \ 803 r1 = 0; \ 804 *(u64*)(r2 + 0) = r1; \ 805 r1 = %[map_hash_48b] ll; \ 806 call %[bpf_map_lookup_elem]; \ 807 if r0 == 0 goto l0_%=; \ 808 r1 = r0; \ 809 r3 = *(u32*)(r0 + 0); \ 810 if r3 s< 32 goto l1_%=; \ 811 l2_%=: r0 = 0; \ 812 l0_%=: exit; \ 813 l1_%=: if r3 s< 0 goto l2_%=; \ 814 r1 += r3; \ 815 r0 = 0; \ 816 *(u8*)(r1 + 0) = r0; \ 817 r0 = 0; \ 818 exit; \ 819 " : 820 : __imm(bpf_map_lookup_elem), 821 __imm_addr(map_hash_48b) 822 : __clobber_all); 823 } 824 825 SEC("tracepoint") 826 __description("helper access to map: bounds check using s<, good access 2") 827 __success 828 __naked void using_s_good_access_2_1(void) 829 { 830 asm volatile (" \ 831 r2 = r10; \ 832 r2 += -8; \ 833 r1 = 0; \ 834 *(u64*)(r2 + 0) = r1; \ 835 r1 = %[map_hash_48b] ll; \ 836 call %[bpf_map_lookup_elem]; \ 837 if r0 == 0 goto l0_%=; \ 838 r1 = r0; \ 839 r3 = *(u32*)(r0 + 0); \ 840 if r3 s< 32 goto l1_%=; \ 841 l2_%=: r0 = 0; \ 842 l0_%=: exit; \ 843 l1_%=: if r3 s< -3 goto l2_%=; \ 844 r1 += r3; \ 845 r0 = 0; \ 846 *(u8*)(r1 + 0) = r0; \ 847 r0 = 0; \ 848 exit; \ 849 " : 850 : __imm(bpf_map_lookup_elem), 851 __imm_addr(map_hash_48b) 852 : __clobber_all); 853 } 854 855 SEC("tracepoint") 856 __description("helper access to map: bounds check using s<, bad access") 857 __failure __msg("R1 min value is negative") 858 __naked void check_using_s_bad_access_1(void) 859 { 860 asm volatile (" \ 861 r2 = r10; \ 862 r2 += -8; \ 863 r1 = 0; \ 864 *(u64*)(r2 + 0) = r1; \ 865 r1 = %[map_hash_48b] ll; \ 866 call %[bpf_map_lookup_elem]; \ 867 if r0 == 0 goto l0_%=; \ 868 r1 = r0; \ 869 r3 = *(u64*)(r0 + 0); \ 870 if r3 s< 32 goto l1_%=; \ 871 l2_%=: r0 = 0; \ 872 l0_%=: exit; \ 873 l1_%=: if r3 s< -3 goto l2_%=; \ 874 r1 += r3; \ 875 r0 = 0; \ 876 *(u8*)(r1 + 0) = r0; \ 877 r0 = 0; \ 878 exit; \ 879 " : 880 : __imm(bpf_map_lookup_elem), 881 __imm_addr(map_hash_48b) 882 : __clobber_all); 883 } 884 885 SEC("tracepoint") 886 __description("helper access to map: bounds check using s<=, good access") 887 __success 888 __naked void check_using_s_good_access_2(void) 889 { 890 asm volatile (" \ 891 r2 = r10; \ 892 r2 += -8; \ 893 r1 = 0; \ 894 *(u64*)(r2 + 0) = r1; \ 895 r1 = %[map_hash_48b] ll; \ 896 call %[bpf_map_lookup_elem]; \ 897 if r0 == 0 goto l0_%=; \ 898 r1 = r0; \ 899 r3 = *(u32*)(r0 + 0); \ 900 if r3 s<= 32 goto l1_%=; \ 901 l2_%=: r0 = 0; \ 902 l0_%=: exit; \ 903 l1_%=: if r3 s<= 0 goto l2_%=; \ 904 r1 += r3; \ 905 r0 = 0; \ 906 *(u8*)(r1 + 0) = r0; \ 907 r0 = 0; \ 908 exit; \ 909 " : 910 : __imm(bpf_map_lookup_elem), 911 __imm_addr(map_hash_48b) 912 : __clobber_all); 913 } 914 915 SEC("tracepoint") 916 __description("helper access to map: bounds check using s<=, good access 2") 917 __success 918 __naked void using_s_good_access_2_2(void) 919 { 920 asm volatile (" \ 921 r2 = r10; \ 922 r2 += -8; \ 923 r1 = 0; \ 924 *(u64*)(r2 + 0) = r1; \ 925 r1 = %[map_hash_48b] ll; \ 926 call %[bpf_map_lookup_elem]; \ 927 if r0 == 0 goto l0_%=; \ 928 r1 = r0; \ 929 r3 = *(u32*)(r0 + 0); \ 930 if r3 s<= 32 goto l1_%=; \ 931 l2_%=: r0 = 0; \ 932 l0_%=: exit; \ 933 l1_%=: if r3 s<= -3 goto l2_%=; \ 934 r1 += r3; \ 935 r0 = 0; \ 936 *(u8*)(r1 + 0) = r0; \ 937 r0 = 0; \ 938 exit; \ 939 " : 940 : __imm(bpf_map_lookup_elem), 941 __imm_addr(map_hash_48b) 942 : __clobber_all); 943 } 944 945 SEC("tracepoint") 946 __description("helper access to map: bounds check using s<=, bad access") 947 __failure __msg("R1 min value is negative") 948 __naked void check_using_s_bad_access_2(void) 949 { 950 asm volatile (" \ 951 r2 = r10; \ 952 r2 += -8; \ 953 r1 = 0; \ 954 *(u64*)(r2 + 0) = r1; \ 955 r1 = %[map_hash_48b] ll; \ 956 call %[bpf_map_lookup_elem]; \ 957 if r0 == 0 goto l0_%=; \ 958 r1 = r0; \ 959 r3 = *(u64*)(r0 + 0); \ 960 if r3 s<= 32 goto l1_%=; \ 961 l2_%=: r0 = 0; \ 962 l0_%=: exit; \ 963 l1_%=: if r3 s<= -3 goto l2_%=; \ 964 r1 += r3; \ 965 r0 = 0; \ 966 *(u8*)(r1 + 0) = r0; \ 967 r0 = 0; \ 968 exit; \ 969 " : 970 : __imm(bpf_map_lookup_elem), 971 __imm_addr(map_hash_48b) 972 : __clobber_all); 973 } 974 975 SEC("tracepoint") 976 __description("map lookup helper access to map") 977 __success 978 __naked void lookup_helper_access_to_map(void) 979 { 980 asm volatile (" \ 981 r2 = r10; \ 982 r2 += -8; \ 983 r1 = 0; \ 984 *(u64*)(r2 + 0) = r1; \ 985 r1 = %[map_hash_16b] ll; \ 986 call %[bpf_map_lookup_elem]; \ 987 if r0 == 0 goto l0_%=; \ 988 r2 = r0; \ 989 r1 = %[map_hash_16b] ll; \ 990 call %[bpf_map_lookup_elem]; \ 991 l0_%=: exit; \ 992 " : 993 : __imm(bpf_map_lookup_elem), 994 __imm_addr(map_hash_16b) 995 : __clobber_all); 996 } 997 998 SEC("tracepoint") 999 __description("map update helper access to map") 1000 __success 1001 __naked void update_helper_access_to_map(void) 1002 { 1003 asm volatile (" \ 1004 r2 = r10; \ 1005 r2 += -8; \ 1006 r1 = 0; \ 1007 *(u64*)(r2 + 0) = r1; \ 1008 r1 = %[map_hash_16b] ll; \ 1009 call %[bpf_map_lookup_elem]; \ 1010 if r0 == 0 goto l0_%=; \ 1011 r4 = 0; \ 1012 r3 = r0; \ 1013 r2 = r0; \ 1014 r1 = %[map_hash_16b] ll; \ 1015 call %[bpf_map_update_elem]; \ 1016 l0_%=: exit; \ 1017 " : 1018 : __imm(bpf_map_lookup_elem), 1019 __imm(bpf_map_update_elem), 1020 __imm_addr(map_hash_16b) 1021 : __clobber_all); 1022 } 1023 1024 SEC("tracepoint") 1025 __description("map update helper access to map: wrong size") 1026 __failure __msg("invalid access to map value, value_size=8 off=0 size=16") 1027 __naked void access_to_map_wrong_size(void) 1028 { 1029 asm volatile (" \ 1030 r2 = r10; \ 1031 r2 += -8; \ 1032 r1 = 0; \ 1033 *(u64*)(r2 + 0) = r1; \ 1034 r1 = %[map_hash_8b] ll; \ 1035 call %[bpf_map_lookup_elem]; \ 1036 if r0 == 0 goto l0_%=; \ 1037 r4 = 0; \ 1038 r3 = r0; \ 1039 r2 = r0; \ 1040 r1 = %[map_hash_16b] ll; \ 1041 call %[bpf_map_update_elem]; \ 1042 l0_%=: exit; \ 1043 " : 1044 : __imm(bpf_map_lookup_elem), 1045 __imm(bpf_map_update_elem), 1046 __imm_addr(map_hash_16b), 1047 __imm_addr(map_hash_8b) 1048 : __clobber_all); 1049 } 1050 1051 SEC("tracepoint") 1052 __description("map helper access to adjusted map (via const imm)") 1053 __success 1054 __naked void adjusted_map_via_const_imm(void) 1055 { 1056 asm volatile (" \ 1057 r2 = r10; \ 1058 r2 += -8; \ 1059 r1 = 0; \ 1060 *(u64*)(r2 + 0) = r1; \ 1061 r1 = %[map_hash_16b] ll; \ 1062 call %[bpf_map_lookup_elem]; \ 1063 if r0 == 0 goto l0_%=; \ 1064 r2 = r0; \ 1065 r2 += %[other_val_bar]; \ 1066 r1 = %[map_hash_16b] ll; \ 1067 call %[bpf_map_lookup_elem]; \ 1068 l0_%=: exit; \ 1069 " : 1070 : __imm(bpf_map_lookup_elem), 1071 __imm_addr(map_hash_16b), 1072 __imm_const(other_val_bar, offsetof(struct other_val, bar)) 1073 : __clobber_all); 1074 } 1075 1076 SEC("tracepoint") 1077 __description("map helper access to adjusted map (via const imm): out-of-bound 1") 1078 __failure __msg("invalid access to map value, value_size=16 off=12 size=8") 1079 __naked void imm_out_of_bound_1(void) 1080 { 1081 asm volatile (" \ 1082 r2 = r10; \ 1083 r2 += -8; \ 1084 r1 = 0; \ 1085 *(u64*)(r2 + 0) = r1; \ 1086 r1 = %[map_hash_16b] ll; \ 1087 call %[bpf_map_lookup_elem]; \ 1088 if r0 == 0 goto l0_%=; \ 1089 r2 = r0; \ 1090 r2 += %[__imm_0]; \ 1091 r1 = %[map_hash_16b] ll; \ 1092 call %[bpf_map_lookup_elem]; \ 1093 l0_%=: exit; \ 1094 " : 1095 : __imm(bpf_map_lookup_elem), 1096 __imm_addr(map_hash_16b), 1097 __imm_const(__imm_0, sizeof(struct other_val) - 4) 1098 : __clobber_all); 1099 } 1100 1101 SEC("tracepoint") 1102 __description("map helper access to adjusted map (via const imm): out-of-bound 2") 1103 __failure __msg("invalid access to map value, value_size=16 off=-4 size=8") 1104 __naked void imm_out_of_bound_2(void) 1105 { 1106 asm volatile (" \ 1107 r2 = r10; \ 1108 r2 += -8; \ 1109 r1 = 0; \ 1110 *(u64*)(r2 + 0) = r1; \ 1111 r1 = %[map_hash_16b] ll; \ 1112 call %[bpf_map_lookup_elem]; \ 1113 if r0 == 0 goto l0_%=; \ 1114 r2 = r0; \ 1115 r2 += -4; \ 1116 r1 = %[map_hash_16b] ll; \ 1117 call %[bpf_map_lookup_elem]; \ 1118 l0_%=: exit; \ 1119 " : 1120 : __imm(bpf_map_lookup_elem), 1121 __imm_addr(map_hash_16b) 1122 : __clobber_all); 1123 } 1124 1125 SEC("tracepoint") 1126 __description("map helper access to adjusted map (via const reg)") 1127 __success 1128 __naked void adjusted_map_via_const_reg(void) 1129 { 1130 asm volatile (" \ 1131 r2 = r10; \ 1132 r2 += -8; \ 1133 r1 = 0; \ 1134 *(u64*)(r2 + 0) = r1; \ 1135 r1 = %[map_hash_16b] ll; \ 1136 call %[bpf_map_lookup_elem]; \ 1137 if r0 == 0 goto l0_%=; \ 1138 r2 = r0; \ 1139 r3 = %[other_val_bar]; \ 1140 r2 += r3; \ 1141 r1 = %[map_hash_16b] ll; \ 1142 call %[bpf_map_lookup_elem]; \ 1143 l0_%=: exit; \ 1144 " : 1145 : __imm(bpf_map_lookup_elem), 1146 __imm_addr(map_hash_16b), 1147 __imm_const(other_val_bar, offsetof(struct other_val, bar)) 1148 : __clobber_all); 1149 } 1150 1151 SEC("tracepoint") 1152 __description("map helper access to adjusted map (via const reg): out-of-bound 1") 1153 __failure __msg("invalid access to map value, value_size=16 off=12 size=8") 1154 __naked void reg_out_of_bound_1(void) 1155 { 1156 asm volatile (" \ 1157 r2 = r10; \ 1158 r2 += -8; \ 1159 r1 = 0; \ 1160 *(u64*)(r2 + 0) = r1; \ 1161 r1 = %[map_hash_16b] ll; \ 1162 call %[bpf_map_lookup_elem]; \ 1163 if r0 == 0 goto l0_%=; \ 1164 r2 = r0; \ 1165 r3 = %[__imm_0]; \ 1166 r2 += r3; \ 1167 r1 = %[map_hash_16b] ll; \ 1168 call %[bpf_map_lookup_elem]; \ 1169 l0_%=: exit; \ 1170 " : 1171 : __imm(bpf_map_lookup_elem), 1172 __imm_addr(map_hash_16b), 1173 __imm_const(__imm_0, sizeof(struct other_val) - 4) 1174 : __clobber_all); 1175 } 1176 1177 SEC("tracepoint") 1178 __description("map helper access to adjusted map (via const reg): out-of-bound 2") 1179 __failure __msg("invalid access to map value, value_size=16 off=-4 size=8") 1180 __naked void reg_out_of_bound_2(void) 1181 { 1182 asm volatile (" \ 1183 r2 = r10; \ 1184 r2 += -8; \ 1185 r1 = 0; \ 1186 *(u64*)(r2 + 0) = r1; \ 1187 r1 = %[map_hash_16b] ll; \ 1188 call %[bpf_map_lookup_elem]; \ 1189 if r0 == 0 goto l0_%=; \ 1190 r2 = r0; \ 1191 r3 = -4; \ 1192 r2 += r3; \ 1193 r1 = %[map_hash_16b] ll; \ 1194 call %[bpf_map_lookup_elem]; \ 1195 l0_%=: exit; \ 1196 " : 1197 : __imm(bpf_map_lookup_elem), 1198 __imm_addr(map_hash_16b) 1199 : __clobber_all); 1200 } 1201 1202 SEC("tracepoint") 1203 __description("map helper access to adjusted map (via variable)") 1204 __success 1205 __naked void to_adjusted_map_via_variable(void) 1206 { 1207 asm volatile (" \ 1208 r2 = r10; \ 1209 r2 += -8; \ 1210 r1 = 0; \ 1211 *(u64*)(r2 + 0) = r1; \ 1212 r1 = %[map_hash_16b] ll; \ 1213 call %[bpf_map_lookup_elem]; \ 1214 if r0 == 0 goto l0_%=; \ 1215 r2 = r0; \ 1216 r3 = *(u32*)(r0 + 0); \ 1217 if r3 > %[other_val_bar] goto l0_%=; \ 1218 r2 += r3; \ 1219 r1 = %[map_hash_16b] ll; \ 1220 call %[bpf_map_lookup_elem]; \ 1221 l0_%=: exit; \ 1222 " : 1223 : __imm(bpf_map_lookup_elem), 1224 __imm_addr(map_hash_16b), 1225 __imm_const(other_val_bar, offsetof(struct other_val, bar)) 1226 : __clobber_all); 1227 } 1228 1229 SEC("tracepoint") 1230 __description("map helper access to adjusted map (via variable): no max check") 1231 __failure 1232 __msg("R2 unbounded memory access, make sure to bounds check any such access") 1233 __naked void via_variable_no_max_check_2(void) 1234 { 1235 asm volatile (" \ 1236 r2 = r10; \ 1237 r2 += -8; \ 1238 r1 = 0; \ 1239 *(u64*)(r2 + 0) = r1; \ 1240 r1 = %[map_hash_16b] ll; \ 1241 call %[bpf_map_lookup_elem]; \ 1242 if r0 == 0 goto l0_%=; \ 1243 r2 = r0; \ 1244 r3 = *(u32*)(r0 + 0); \ 1245 r2 += r3; \ 1246 r1 = %[map_hash_16b] ll; \ 1247 call %[bpf_map_lookup_elem]; \ 1248 l0_%=: exit; \ 1249 " : 1250 : __imm(bpf_map_lookup_elem), 1251 __imm_addr(map_hash_16b) 1252 : __clobber_all); 1253 } 1254 1255 SEC("tracepoint") 1256 __description("map helper access to adjusted map (via variable): wrong max check") 1257 __failure __msg("invalid access to map value, value_size=16 off=9 size=8") 1258 __naked void via_variable_wrong_max_check_2(void) 1259 { 1260 asm volatile (" \ 1261 r2 = r10; \ 1262 r2 += -8; \ 1263 r1 = 0; \ 1264 *(u64*)(r2 + 0) = r1; \ 1265 r1 = %[map_hash_16b] ll; \ 1266 call %[bpf_map_lookup_elem]; \ 1267 if r0 == 0 goto l0_%=; \ 1268 r2 = r0; \ 1269 r3 = *(u32*)(r0 + 0); \ 1270 if r3 > %[__imm_0] goto l0_%=; \ 1271 r2 += r3; \ 1272 r1 = %[map_hash_16b] ll; \ 1273 call %[bpf_map_lookup_elem]; \ 1274 l0_%=: exit; \ 1275 " : 1276 : __imm(bpf_map_lookup_elem), 1277 __imm_addr(map_hash_16b), 1278 __imm_const(__imm_0, offsetof(struct other_val, bar) + 1) 1279 : __clobber_all); 1280 } 1281 1282 char _license[] SEC("license") = "GPL"; 1283