1// SPDX-License-Identifier: GPL-2.0 2/* Converted from tools/testing/selftests/bpf/verifier/helper_access_var_len.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_HASH); 17 __uint(max_entries, 1); 18 __type(key, long long); 19 __type(value, struct test_val); 20} map_hash_48b SEC(".maps"); 21 22struct { 23 __uint(type, BPF_MAP_TYPE_HASH); 24 __uint(max_entries, 1); 25 __type(key, long long); 26 __type(value, long long); 27} map_hash_8b SEC(".maps"); 28 29struct { 30 __uint(type, BPF_MAP_TYPE_RINGBUF); 31 __uint(max_entries, 4096); 32} map_ringbuf SEC(".maps"); 33 34SEC("tracepoint") 35__description("helper access to variable memory: stack, bitwise AND + JMP, correct bounds") 36__success 37__naked void bitwise_and_jmp_correct_bounds(void) 38{ 39 asm volatile (" \ 40 r1 = r10; \ 41 r1 += -64; \ 42 r0 = 0; \ 43 *(u64*)(r10 - 64) = r0; \ 44 *(u64*)(r10 - 56) = r0; \ 45 *(u64*)(r10 - 48) = r0; \ 46 *(u64*)(r10 - 40) = r0; \ 47 *(u64*)(r10 - 32) = r0; \ 48 *(u64*)(r10 - 24) = r0; \ 49 *(u64*)(r10 - 16) = r0; \ 50 *(u64*)(r10 - 8) = r0; \ 51 r2 = 16; \ 52 *(u64*)(r1 - 128) = r2; \ 53 r2 = *(u64*)(r1 - 128); \ 54 r2 &= 64; \ 55 r4 = 0; \ 56 if r4 >= r2 goto l0_%=; \ 57 r3 = 0; \ 58 call %[bpf_probe_read_kernel]; \ 59l0_%=: r0 = 0; \ 60 exit; \ 61" : 62 : __imm(bpf_probe_read_kernel) 63 : __clobber_all); 64} 65 66SEC("socket") 67__description("helper access to variable memory: stack, bitwise AND, zero included") 68/* in privileged mode reads from uninitialized stack locations are permitted */ 69__success __failure_unpriv 70__msg_unpriv("invalid indirect read from stack R2 off -64+0 size 64") 71__retval(0) 72__naked void stack_bitwise_and_zero_included(void) 73{ 74 asm volatile (" \ 75 /* set max stack size */ \ 76 r6 = 0; \ 77 *(u64*)(r10 - 128) = r6; \ 78 /* set r3 to a random value */ \ 79 call %[bpf_get_prandom_u32]; \ 80 r3 = r0; \ 81 /* use bitwise AND to limit r3 range to [0, 64] */\ 82 r3 &= 64; \ 83 r1 = %[map_ringbuf] ll; \ 84 r2 = r10; \ 85 r2 += -64; \ 86 r4 = 0; \ 87 /* Call bpf_ringbuf_output(), it is one of a few helper functions with\ 88 * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\ 89 * For unpriv this should signal an error, because memory at &fp[-64] is\ 90 * not initialized. \ 91 */ \ 92 call %[bpf_ringbuf_output]; \ 93 exit; \ 94" : 95 : __imm(bpf_get_prandom_u32), 96 __imm(bpf_ringbuf_output), 97 __imm_addr(map_ringbuf) 98 : __clobber_all); 99} 100 101SEC("tracepoint") 102__description("helper access to variable memory: stack, bitwise AND + JMP, wrong max") 103__failure __msg("invalid indirect access to stack R1 off=-64 size=65") 104__naked void bitwise_and_jmp_wrong_max(void) 105{ 106 asm volatile (" \ 107 r2 = *(u64*)(r1 + 8); \ 108 r1 = r10; \ 109 r1 += -64; \ 110 *(u64*)(r1 - 128) = r2; \ 111 r2 = *(u64*)(r1 - 128); \ 112 r2 &= 65; \ 113 r4 = 0; \ 114 if r4 >= r2 goto l0_%=; \ 115 r3 = 0; \ 116 call %[bpf_probe_read_kernel]; \ 117l0_%=: r0 = 0; \ 118 exit; \ 119" : 120 : __imm(bpf_probe_read_kernel) 121 : __clobber_all); 122} 123 124SEC("tracepoint") 125__description("helper access to variable memory: stack, JMP, correct bounds") 126__success 127__naked void memory_stack_jmp_correct_bounds(void) 128{ 129 asm volatile (" \ 130 r1 = r10; \ 131 r1 += -64; \ 132 r0 = 0; \ 133 *(u64*)(r10 - 64) = r0; \ 134 *(u64*)(r10 - 56) = r0; \ 135 *(u64*)(r10 - 48) = r0; \ 136 *(u64*)(r10 - 40) = r0; \ 137 *(u64*)(r10 - 32) = r0; \ 138 *(u64*)(r10 - 24) = r0; \ 139 *(u64*)(r10 - 16) = r0; \ 140 *(u64*)(r10 - 8) = r0; \ 141 r2 = 16; \ 142 *(u64*)(r1 - 128) = r2; \ 143 r2 = *(u64*)(r1 - 128); \ 144 if r2 > 64 goto l0_%=; \ 145 r4 = 0; \ 146 if r4 >= r2 goto l0_%=; \ 147 r3 = 0; \ 148 call %[bpf_probe_read_kernel]; \ 149l0_%=: r0 = 0; \ 150 exit; \ 151" : 152 : __imm(bpf_probe_read_kernel) 153 : __clobber_all); 154} 155 156SEC("tracepoint") 157__description("helper access to variable memory: stack, JMP (signed), correct bounds") 158__success 159__naked void stack_jmp_signed_correct_bounds(void) 160{ 161 asm volatile (" \ 162 r1 = r10; \ 163 r1 += -64; \ 164 r0 = 0; \ 165 *(u64*)(r10 - 64) = r0; \ 166 *(u64*)(r10 - 56) = r0; \ 167 *(u64*)(r10 - 48) = r0; \ 168 *(u64*)(r10 - 40) = r0; \ 169 *(u64*)(r10 - 32) = r0; \ 170 *(u64*)(r10 - 24) = r0; \ 171 *(u64*)(r10 - 16) = r0; \ 172 *(u64*)(r10 - 8) = r0; \ 173 r2 = 16; \ 174 *(u64*)(r1 - 128) = r2; \ 175 r2 = *(u64*)(r1 - 128); \ 176 if r2 s> 64 goto l0_%=; \ 177 r4 = 0; \ 178 if r4 s>= r2 goto l0_%=; \ 179 r3 = 0; \ 180 call %[bpf_probe_read_kernel]; \ 181l0_%=: r0 = 0; \ 182 exit; \ 183" : 184 : __imm(bpf_probe_read_kernel) 185 : __clobber_all); 186} 187 188SEC("tracepoint") 189__description("helper access to variable memory: stack, JMP, bounds + offset") 190__failure __msg("invalid indirect access to stack R1 off=-64 size=65") 191__naked void memory_stack_jmp_bounds_offset(void) 192{ 193 asm volatile (" \ 194 r2 = *(u64*)(r1 + 8); \ 195 r1 = r10; \ 196 r1 += -64; \ 197 *(u64*)(r1 - 128) = r2; \ 198 r2 = *(u64*)(r1 - 128); \ 199 if r2 > 64 goto l0_%=; \ 200 r4 = 0; \ 201 if r4 >= r2 goto l0_%=; \ 202 r2 += 1; \ 203 r3 = 0; \ 204 call %[bpf_probe_read_kernel]; \ 205l0_%=: r0 = 0; \ 206 exit; \ 207" : 208 : __imm(bpf_probe_read_kernel) 209 : __clobber_all); 210} 211 212SEC("tracepoint") 213__description("helper access to variable memory: stack, JMP, wrong max") 214__failure __msg("invalid indirect access to stack R1 off=-64 size=65") 215__naked void memory_stack_jmp_wrong_max(void) 216{ 217 asm volatile (" \ 218 r2 = *(u64*)(r1 + 8); \ 219 r1 = r10; \ 220 r1 += -64; \ 221 *(u64*)(r1 - 128) = r2; \ 222 r2 = *(u64*)(r1 - 128); \ 223 if r2 > 65 goto l0_%=; \ 224 r4 = 0; \ 225 if r4 >= r2 goto l0_%=; \ 226 r3 = 0; \ 227 call %[bpf_probe_read_kernel]; \ 228l0_%=: r0 = 0; \ 229 exit; \ 230" : 231 : __imm(bpf_probe_read_kernel) 232 : __clobber_all); 233} 234 235SEC("tracepoint") 236__description("helper access to variable memory: stack, JMP, no max check") 237__failure 238/* because max wasn't checked, signed min is negative */ 239__msg("R2 min value is negative, either use unsigned or 'var &= const'") 240__naked void stack_jmp_no_max_check(void) 241{ 242 asm volatile (" \ 243 r2 = *(u64*)(r1 + 8); \ 244 r1 = r10; \ 245 r1 += -64; \ 246 *(u64*)(r1 - 128) = r2; \ 247 r2 = *(u64*)(r1 - 128); \ 248 r4 = 0; \ 249 if r4 >= r2 goto l0_%=; \ 250 r3 = 0; \ 251 call %[bpf_probe_read_kernel]; \ 252l0_%=: r0 = 0; \ 253 exit; \ 254" : 255 : __imm(bpf_probe_read_kernel) 256 : __clobber_all); 257} 258 259SEC("socket") 260__description("helper access to variable memory: stack, JMP, no min check") 261/* in privileged mode reads from uninitialized stack locations are permitted */ 262__success __failure_unpriv 263__msg_unpriv("invalid indirect read from stack R2 off -64+0 size 64") 264__retval(0) 265__naked void stack_jmp_no_min_check(void) 266{ 267 asm volatile (" \ 268 /* set max stack size */ \ 269 r6 = 0; \ 270 *(u64*)(r10 - 128) = r6; \ 271 /* set r3 to a random value */ \ 272 call %[bpf_get_prandom_u32]; \ 273 r3 = r0; \ 274 /* use JMP to limit r3 range to [0, 64] */ \ 275 if r3 > 64 goto l0_%=; \ 276 r1 = %[map_ringbuf] ll; \ 277 r2 = r10; \ 278 r2 += -64; \ 279 r4 = 0; \ 280 /* Call bpf_ringbuf_output(), it is one of a few helper functions with\ 281 * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\ 282 * For unpriv this should signal an error, because memory at &fp[-64] is\ 283 * not initialized. \ 284 */ \ 285 call %[bpf_ringbuf_output]; \ 286l0_%=: r0 = 0; \ 287 exit; \ 288" : 289 : __imm(bpf_get_prandom_u32), 290 __imm(bpf_ringbuf_output), 291 __imm_addr(map_ringbuf) 292 : __clobber_all); 293} 294 295SEC("tracepoint") 296__description("helper access to variable memory: stack, JMP (signed), no min check") 297__failure __msg("R2 min value is negative") 298__naked void jmp_signed_no_min_check(void) 299{ 300 asm volatile (" \ 301 r2 = *(u64*)(r1 + 8); \ 302 r1 = r10; \ 303 r1 += -64; \ 304 *(u64*)(r1 - 128) = r2; \ 305 r2 = *(u64*)(r1 - 128); \ 306 if r2 s> 64 goto l0_%=; \ 307 r3 = 0; \ 308 call %[bpf_probe_read_kernel]; \ 309 r0 = 0; \ 310l0_%=: exit; \ 311" : 312 : __imm(bpf_probe_read_kernel) 313 : __clobber_all); 314} 315 316SEC("tracepoint") 317__description("helper access to variable memory: map, JMP, correct bounds") 318__success 319__naked void memory_map_jmp_correct_bounds(void) 320{ 321 asm volatile (" \ 322 r2 = r10; \ 323 r2 += -8; \ 324 r1 = 0; \ 325 *(u64*)(r2 + 0) = r1; \ 326 r1 = %[map_hash_48b] ll; \ 327 call %[bpf_map_lookup_elem]; \ 328 if r0 == 0 goto l0_%=; \ 329 r1 = r0; \ 330 r2 = %[sizeof_test_val]; \ 331 *(u64*)(r10 - 128) = r2; \ 332 r2 = *(u64*)(r10 - 128); \ 333 if r2 s> %[sizeof_test_val] goto l1_%=; \ 334 r4 = 0; \ 335 if r4 s>= r2 goto l1_%=; \ 336 r3 = 0; \ 337 call %[bpf_probe_read_kernel]; \ 338l1_%=: r0 = 0; \ 339l0_%=: exit; \ 340" : 341 : __imm(bpf_map_lookup_elem), 342 __imm(bpf_probe_read_kernel), 343 __imm_addr(map_hash_48b), 344 __imm_const(sizeof_test_val, sizeof(struct test_val)) 345 : __clobber_all); 346} 347 348SEC("tracepoint") 349__description("helper access to variable memory: map, JMP, wrong max") 350__failure __msg("invalid access to map value, value_size=48 off=0 size=49") 351__naked void memory_map_jmp_wrong_max(void) 352{ 353 asm volatile (" \ 354 r6 = *(u64*)(r1 + 8); \ 355 r2 = r10; \ 356 r2 += -8; \ 357 r1 = 0; \ 358 *(u64*)(r2 + 0) = r1; \ 359 r1 = %[map_hash_48b] ll; \ 360 call %[bpf_map_lookup_elem]; \ 361 if r0 == 0 goto l0_%=; \ 362 r1 = r0; \ 363 r2 = r6; \ 364 *(u64*)(r10 - 128) = r2; \ 365 r2 = *(u64*)(r10 - 128); \ 366 if r2 s> %[__imm_0] goto l1_%=; \ 367 r4 = 0; \ 368 if r4 s>= r2 goto l1_%=; \ 369 r3 = 0; \ 370 call %[bpf_probe_read_kernel]; \ 371l1_%=: r0 = 0; \ 372l0_%=: exit; \ 373" : 374 : __imm(bpf_map_lookup_elem), 375 __imm(bpf_probe_read_kernel), 376 __imm_addr(map_hash_48b), 377 __imm_const(__imm_0, sizeof(struct test_val) + 1) 378 : __clobber_all); 379} 380 381SEC("tracepoint") 382__description("helper access to variable memory: map adjusted, JMP, correct bounds") 383__success 384__naked void map_adjusted_jmp_correct_bounds(void) 385{ 386 asm volatile (" \ 387 r2 = r10; \ 388 r2 += -8; \ 389 r1 = 0; \ 390 *(u64*)(r2 + 0) = r1; \ 391 r1 = %[map_hash_48b] ll; \ 392 call %[bpf_map_lookup_elem]; \ 393 if r0 == 0 goto l0_%=; \ 394 r1 = r0; \ 395 r1 += 20; \ 396 r2 = %[sizeof_test_val]; \ 397 *(u64*)(r10 - 128) = r2; \ 398 r2 = *(u64*)(r10 - 128); \ 399 if r2 s> %[__imm_0] goto l1_%=; \ 400 r4 = 0; \ 401 if r4 s>= r2 goto l1_%=; \ 402 r3 = 0; \ 403 call %[bpf_probe_read_kernel]; \ 404l1_%=: r0 = 0; \ 405l0_%=: exit; \ 406" : 407 : __imm(bpf_map_lookup_elem), 408 __imm(bpf_probe_read_kernel), 409 __imm_addr(map_hash_48b), 410 __imm_const(__imm_0, sizeof(struct test_val) - 20), 411 __imm_const(sizeof_test_val, sizeof(struct test_val)) 412 : __clobber_all); 413} 414 415SEC("tracepoint") 416__description("helper access to variable memory: map adjusted, JMP, wrong max") 417__failure __msg("R1 min value is outside of the allowed memory range") 418__naked void map_adjusted_jmp_wrong_max(void) 419{ 420 asm volatile (" \ 421 r6 = *(u64*)(r1 + 8); \ 422 r2 = r10; \ 423 r2 += -8; \ 424 r1 = 0; \ 425 *(u64*)(r2 + 0) = r1; \ 426 r1 = %[map_hash_48b] ll; \ 427 call %[bpf_map_lookup_elem]; \ 428 if r0 == 0 goto l0_%=; \ 429 r1 = r0; \ 430 r1 += 20; \ 431 r2 = r6; \ 432 *(u64*)(r10 - 128) = r2; \ 433 r2 = *(u64*)(r10 - 128); \ 434 if r2 s> %[__imm_0] goto l1_%=; \ 435 r4 = 0; \ 436 if r4 s>= r2 goto l1_%=; \ 437 r3 = 0; \ 438 call %[bpf_probe_read_kernel]; \ 439l1_%=: r0 = 0; \ 440l0_%=: exit; \ 441" : 442 : __imm(bpf_map_lookup_elem), 443 __imm(bpf_probe_read_kernel), 444 __imm_addr(map_hash_48b), 445 __imm_const(__imm_0, sizeof(struct test_val) - 19) 446 : __clobber_all); 447} 448 449SEC("tc") 450__description("helper access to variable memory: size = 0 allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)") 451__success __retval(0) 452__naked void ptr_to_mem_or_null_1(void) 453{ 454 asm volatile (" \ 455 r1 = 0; \ 456 r2 = 0; \ 457 r3 = 0; \ 458 r4 = 0; \ 459 r5 = 0; \ 460 call %[bpf_csum_diff]; \ 461 exit; \ 462" : 463 : __imm(bpf_csum_diff) 464 : __clobber_all); 465} 466 467SEC("tc") 468__description("helper access to variable memory: size > 0 not allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)") 469__failure __msg("R1 type=scalar expected=fp") 470__naked void ptr_to_mem_or_null_2(void) 471{ 472 asm volatile (" \ 473 r2 = *(u32*)(r1 + 0); \ 474 r1 = 0; \ 475 *(u64*)(r10 - 128) = r2; \ 476 r2 = *(u64*)(r10 - 128); \ 477 r2 &= 64; \ 478 r3 = 0; \ 479 r4 = 0; \ 480 r5 = 0; \ 481 call %[bpf_csum_diff]; \ 482 exit; \ 483" : 484 : __imm(bpf_csum_diff) 485 : __clobber_all); 486} 487 488SEC("tc") 489__description("helper access to variable memory: size = 0 allowed on != NULL stack pointer (ARG_PTR_TO_MEM_OR_NULL)") 490__success __retval(0) 491__naked void ptr_to_mem_or_null_3(void) 492{ 493 asm volatile (" \ 494 r1 = r10; \ 495 r1 += -8; \ 496 r2 = 0; \ 497 *(u64*)(r1 + 0) = r2; \ 498 r2 &= 8; \ 499 r3 = 0; \ 500 r4 = 0; \ 501 r5 = 0; \ 502 call %[bpf_csum_diff]; \ 503 exit; \ 504" : 505 : __imm(bpf_csum_diff) 506 : __clobber_all); 507} 508 509SEC("tc") 510__description("helper access to variable memory: size = 0 allowed on != NULL map pointer (ARG_PTR_TO_MEM_OR_NULL)") 511__success __retval(0) 512__naked void ptr_to_mem_or_null_4(void) 513{ 514 asm volatile (" \ 515 r1 = 0; \ 516 *(u64*)(r10 - 8) = r1; \ 517 r2 = r10; \ 518 r2 += -8; \ 519 r1 = %[map_hash_8b] ll; \ 520 call %[bpf_map_lookup_elem]; \ 521 if r0 == 0 goto l0_%=; \ 522 r1 = r0; \ 523 r2 = 0; \ 524 r3 = 0; \ 525 r4 = 0; \ 526 r5 = 0; \ 527 call %[bpf_csum_diff]; \ 528l0_%=: exit; \ 529" : 530 : __imm(bpf_csum_diff), 531 __imm(bpf_map_lookup_elem), 532 __imm_addr(map_hash_8b) 533 : __clobber_all); 534} 535 536SEC("tc") 537__description("helper access to variable memory: size possible = 0 allowed on != NULL stack pointer (ARG_PTR_TO_MEM_OR_NULL)") 538__success __retval(0) 539__naked void ptr_to_mem_or_null_5(void) 540{ 541 asm volatile (" \ 542 r1 = 0; \ 543 *(u64*)(r10 - 8) = r1; \ 544 r2 = r10; \ 545 r2 += -8; \ 546 r1 = %[map_hash_8b] ll; \ 547 call %[bpf_map_lookup_elem]; \ 548 if r0 == 0 goto l0_%=; \ 549 r2 = *(u64*)(r0 + 0); \ 550 if r2 > 8 goto l0_%=; \ 551 r1 = r10; \ 552 r1 += -8; \ 553 *(u64*)(r1 + 0) = r2; \ 554 r3 = 0; \ 555 r4 = 0; \ 556 r5 = 0; \ 557 call %[bpf_csum_diff]; \ 558l0_%=: exit; \ 559" : 560 : __imm(bpf_csum_diff), 561 __imm(bpf_map_lookup_elem), 562 __imm_addr(map_hash_8b) 563 : __clobber_all); 564} 565 566SEC("tc") 567__description("helper access to variable memory: size possible = 0 allowed on != NULL map pointer (ARG_PTR_TO_MEM_OR_NULL)") 568__success __retval(0) 569__naked void ptr_to_mem_or_null_6(void) 570{ 571 asm volatile (" \ 572 r1 = 0; \ 573 *(u64*)(r10 - 8) = r1; \ 574 r2 = r10; \ 575 r2 += -8; \ 576 r1 = %[map_hash_8b] ll; \ 577 call %[bpf_map_lookup_elem]; \ 578 if r0 == 0 goto l0_%=; \ 579 r1 = r0; \ 580 r2 = *(u64*)(r0 + 0); \ 581 if r2 > 8 goto l0_%=; \ 582 r3 = 0; \ 583 r4 = 0; \ 584 r5 = 0; \ 585 call %[bpf_csum_diff]; \ 586l0_%=: exit; \ 587" : 588 : __imm(bpf_csum_diff), 589 __imm(bpf_map_lookup_elem), 590 __imm_addr(map_hash_8b) 591 : __clobber_all); 592} 593 594SEC("tc") 595__description("helper access to variable memory: size possible = 0 allowed on != NULL packet pointer (ARG_PTR_TO_MEM_OR_NULL)") 596__success __retval(0) 597/* csum_diff of 64-byte packet */ 598__flag(BPF_F_ANY_ALIGNMENT) 599__naked void ptr_to_mem_or_null_7(void) 600{ 601 asm volatile (" \ 602 r6 = *(u32*)(r1 + %[__sk_buff_data]); \ 603 r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ 604 r0 = r6; \ 605 r0 += 8; \ 606 if r0 > r3 goto l0_%=; \ 607 r1 = r6; \ 608 r2 = *(u64*)(r6 + 0); \ 609 if r2 > 8 goto l0_%=; \ 610 r3 = 0; \ 611 r4 = 0; \ 612 r5 = 0; \ 613 call %[bpf_csum_diff]; \ 614l0_%=: exit; \ 615" : 616 : __imm(bpf_csum_diff), 617 __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), 618 __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) 619 : __clobber_all); 620} 621 622SEC("tracepoint") 623__description("helper access to variable memory: size = 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)") 624__failure __msg("R1 type=scalar expected=fp") 625__naked void ptr_to_mem_or_null_8(void) 626{ 627 asm volatile (" \ 628 r1 = 0; \ 629 r2 = 0; \ 630 r3 = 0; \ 631 call %[bpf_probe_read_kernel]; \ 632 exit; \ 633" : 634 : __imm(bpf_probe_read_kernel) 635 : __clobber_all); 636} 637 638SEC("tracepoint") 639__description("helper access to variable memory: size > 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)") 640__failure __msg("R1 type=scalar expected=fp") 641__naked void ptr_to_mem_or_null_9(void) 642{ 643 asm volatile (" \ 644 r1 = 0; \ 645 r2 = 1; \ 646 r3 = 0; \ 647 call %[bpf_probe_read_kernel]; \ 648 exit; \ 649" : 650 : __imm(bpf_probe_read_kernel) 651 : __clobber_all); 652} 653 654SEC("tracepoint") 655__description("helper access to variable memory: size = 0 allowed on != NULL stack pointer (!ARG_PTR_TO_MEM_OR_NULL)") 656__success 657__naked void ptr_to_mem_or_null_10(void) 658{ 659 asm volatile (" \ 660 r1 = r10; \ 661 r1 += -8; \ 662 r2 = 0; \ 663 r3 = 0; \ 664 call %[bpf_probe_read_kernel]; \ 665 exit; \ 666" : 667 : __imm(bpf_probe_read_kernel) 668 : __clobber_all); 669} 670 671SEC("tracepoint") 672__description("helper access to variable memory: size = 0 allowed on != NULL map pointer (!ARG_PTR_TO_MEM_OR_NULL)") 673__success 674__naked void ptr_to_mem_or_null_11(void) 675{ 676 asm volatile (" \ 677 r1 = 0; \ 678 *(u64*)(r10 - 8) = r1; \ 679 r2 = r10; \ 680 r2 += -8; \ 681 r1 = %[map_hash_8b] ll; \ 682 call %[bpf_map_lookup_elem]; \ 683 if r0 == 0 goto l0_%=; \ 684 r1 = r0; \ 685 r2 = 0; \ 686 r3 = 0; \ 687 call %[bpf_probe_read_kernel]; \ 688l0_%=: exit; \ 689" : 690 : __imm(bpf_map_lookup_elem), 691 __imm(bpf_probe_read_kernel), 692 __imm_addr(map_hash_8b) 693 : __clobber_all); 694} 695 696SEC("tracepoint") 697__description("helper access to variable memory: size possible = 0 allowed on != NULL stack pointer (!ARG_PTR_TO_MEM_OR_NULL)") 698__success 699__naked void ptr_to_mem_or_null_12(void) 700{ 701 asm volatile (" \ 702 r1 = 0; \ 703 *(u64*)(r10 - 8) = r1; \ 704 r2 = r10; \ 705 r2 += -8; \ 706 r1 = %[map_hash_8b] ll; \ 707 call %[bpf_map_lookup_elem]; \ 708 if r0 == 0 goto l0_%=; \ 709 r2 = *(u64*)(r0 + 0); \ 710 if r2 > 8 goto l0_%=; \ 711 r1 = r10; \ 712 r1 += -8; \ 713 r3 = 0; \ 714 call %[bpf_probe_read_kernel]; \ 715l0_%=: exit; \ 716" : 717 : __imm(bpf_map_lookup_elem), 718 __imm(bpf_probe_read_kernel), 719 __imm_addr(map_hash_8b) 720 : __clobber_all); 721} 722 723SEC("tracepoint") 724__description("helper access to variable memory: size possible = 0 allowed on != NULL map pointer (!ARG_PTR_TO_MEM_OR_NULL)") 725__success 726__naked void ptr_to_mem_or_null_13(void) 727{ 728 asm volatile (" \ 729 r1 = 0; \ 730 *(u64*)(r10 - 8) = r1; \ 731 r2 = r10; \ 732 r2 += -8; \ 733 r1 = %[map_hash_8b] ll; \ 734 call %[bpf_map_lookup_elem]; \ 735 if r0 == 0 goto l0_%=; \ 736 r1 = r0; \ 737 r2 = *(u64*)(r0 + 0); \ 738 if r2 > 8 goto l0_%=; \ 739 r3 = 0; \ 740 call %[bpf_probe_read_kernel]; \ 741l0_%=: exit; \ 742" : 743 : __imm(bpf_map_lookup_elem), 744 __imm(bpf_probe_read_kernel), 745 __imm_addr(map_hash_8b) 746 : __clobber_all); 747} 748 749SEC("socket") 750__description("helper access to variable memory: 8 bytes leak") 751/* in privileged mode reads from uninitialized stack locations are permitted */ 752__success __failure_unpriv 753__msg_unpriv("invalid indirect read from stack R2 off -64+32 size 64") 754__retval(0) 755__naked void variable_memory_8_bytes_leak(void) 756{ 757 asm volatile (" \ 758 /* set max stack size */ \ 759 r6 = 0; \ 760 *(u64*)(r10 - 128) = r6; \ 761 /* set r3 to a random value */ \ 762 call %[bpf_get_prandom_u32]; \ 763 r3 = r0; \ 764 r1 = %[map_ringbuf] ll; \ 765 r2 = r10; \ 766 r2 += -64; \ 767 r0 = 0; \ 768 *(u64*)(r10 - 64) = r0; \ 769 *(u64*)(r10 - 56) = r0; \ 770 *(u64*)(r10 - 48) = r0; \ 771 *(u64*)(r10 - 40) = r0; \ 772 /* Note: fp[-32] left uninitialized */ \ 773 *(u64*)(r10 - 24) = r0; \ 774 *(u64*)(r10 - 16) = r0; \ 775 *(u64*)(r10 - 8) = r0; \ 776 /* Limit r3 range to [1, 64] */ \ 777 r3 &= 63; \ 778 r3 += 1; \ 779 r4 = 0; \ 780 /* Call bpf_ringbuf_output(), it is one of a few helper functions with\ 781 * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\ 782 * For unpriv this should signal an error, because memory region [1, 64]\ 783 * at &fp[-64] is not fully initialized. \ 784 */ \ 785 call %[bpf_ringbuf_output]; \ 786 r0 = 0; \ 787 exit; \ 788" : 789 : __imm(bpf_get_prandom_u32), 790 __imm(bpf_ringbuf_output), 791 __imm_addr(map_ringbuf) 792 : __clobber_all); 793} 794 795SEC("tracepoint") 796__description("helper access to variable memory: 8 bytes no leak (init memory)") 797__success 798__naked void bytes_no_leak_init_memory(void) 799{ 800 asm volatile (" \ 801 r1 = r10; \ 802 r0 = 0; \ 803 r0 = 0; \ 804 *(u64*)(r10 - 64) = r0; \ 805 *(u64*)(r10 - 56) = r0; \ 806 *(u64*)(r10 - 48) = r0; \ 807 *(u64*)(r10 - 40) = r0; \ 808 *(u64*)(r10 - 32) = r0; \ 809 *(u64*)(r10 - 24) = r0; \ 810 *(u64*)(r10 - 16) = r0; \ 811 *(u64*)(r10 - 8) = r0; \ 812 r1 += -64; \ 813 r2 = 0; \ 814 r2 &= 32; \ 815 r2 += 32; \ 816 r3 = 0; \ 817 call %[bpf_probe_read_kernel]; \ 818 r1 = *(u64*)(r10 - 16); \ 819 exit; \ 820" : 821 : __imm(bpf_probe_read_kernel) 822 : __clobber_all); 823} 824 825char _license[] SEC("license") = "GPL"; 826