1 // SPDX-License-Identifier: GPL-2.0 2 /* Converted from tools/testing/selftests/bpf/verifier/ctx.c */ 3 4 #include "vmlinux.h" 5 #include <bpf/bpf_helpers.h> 6 #include "bpf_misc.h" 7 #include "../test_kmods/bpf_testmod_kfunc.h" 8 9 static const char ctx_strncmp_target[] = "ctx"; 10 static const char ctx_snprintf_fmt[] = ""; 11 12 SEC("tc") 13 __description("context stores via BPF_ATOMIC") 14 __failure __msg("BPF_ATOMIC stores into R1 ctx is not allowed") 15 __naked void context_stores_via_bpf_atomic(void) 16 { 17 asm volatile (" \ 18 r0 = 0; \ 19 lock *(u32 *)(r1 + %[__sk_buff_mark]) += w0; \ 20 exit; \ 21 " : 22 : __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) 23 : __clobber_all); 24 } 25 26 SEC("tc") 27 __description("arithmetic ops make PTR_TO_CTX unusable") 28 __failure __msg("dereference of modified ctx ptr") 29 __naked void make_ptr_to_ctx_unusable(void) 30 { 31 asm volatile (" \ 32 r1 += %[__imm_0]; \ 33 r0 = *(u32*)(r1 + %[__sk_buff_mark]); \ 34 exit; \ 35 " : 36 : __imm_const(__imm_0, 37 offsetof(struct __sk_buff, data) - offsetof(struct __sk_buff, mark)), 38 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) 39 : __clobber_all); 40 } 41 42 SEC("tc") 43 __description("pass unmodified ctx pointer to helper") 44 __success __retval(0) 45 __naked void unmodified_ctx_pointer_to_helper(void) 46 { 47 asm volatile (" \ 48 r2 = 0; \ 49 call %[bpf_csum_update]; \ 50 r0 = 0; \ 51 exit; \ 52 " : 53 : __imm(bpf_csum_update) 54 : __clobber_all); 55 } 56 57 SEC("tc") 58 __description("pass modified ctx pointer to helper, 1") 59 __failure __msg("negative offset ctx ptr R1 off=-612 disallowed") 60 __naked void ctx_pointer_to_helper_1(void) 61 { 62 asm volatile (" \ 63 r1 += -612; \ 64 r2 = 0; \ 65 call %[bpf_csum_update]; \ 66 r0 = 0; \ 67 exit; \ 68 " : 69 : __imm(bpf_csum_update) 70 : __clobber_all); 71 } 72 73 SEC("socket") 74 __description("pass modified ctx pointer to helper, 2") 75 __failure __msg("negative offset ctx ptr R1 off=-612 disallowed") 76 __naked void ctx_pointer_to_helper_2(void) 77 { 78 asm volatile (" \ 79 r1 += -612; \ 80 call %[bpf_get_socket_cookie]; \ 81 r0 = 0; \ 82 exit; \ 83 " : 84 : __imm(bpf_get_socket_cookie) 85 : __clobber_all); 86 } 87 88 SEC("tc") 89 __description("pass modified ctx pointer to helper, 3") 90 __failure __msg("variable ctx access var_off=(0x0; 0x4)") 91 __naked void ctx_pointer_to_helper_3(void) 92 { 93 asm volatile (" \ 94 r3 = *(u32*)(r1 + 0); \ 95 r3 &= 4; \ 96 r1 += r3; \ 97 r2 = 0; \ 98 call %[bpf_csum_update]; \ 99 r0 = 0; \ 100 exit; \ 101 " : 102 : __imm(bpf_csum_update) 103 : __clobber_all); 104 } 105 106 SEC("cgroup/sendmsg6") 107 __description("pass ctx or null check, 1: ctx") 108 __success 109 __naked void or_null_check_1_ctx(void) 110 { 111 asm volatile (" \ 112 call %[bpf_get_netns_cookie]; \ 113 r0 = 0; \ 114 exit; \ 115 " : 116 : __imm(bpf_get_netns_cookie) 117 : __clobber_all); 118 } 119 120 SEC("cgroup/sendmsg6") 121 __description("pass ctx or null check, 2: null") 122 __success 123 __naked void or_null_check_2_null(void) 124 { 125 asm volatile (" \ 126 r1 = 0; \ 127 call %[bpf_get_netns_cookie]; \ 128 r0 = 0; \ 129 exit; \ 130 " : 131 : __imm(bpf_get_netns_cookie) 132 : __clobber_all); 133 } 134 135 SEC("cgroup/sendmsg6") 136 __description("pass ctx or null check, 3: 1") 137 __failure __msg("R1 type=scalar expected=ctx") 138 __naked void or_null_check_3_1(void) 139 { 140 asm volatile (" \ 141 r1 = 1; \ 142 call %[bpf_get_netns_cookie]; \ 143 r0 = 0; \ 144 exit; \ 145 " : 146 : __imm(bpf_get_netns_cookie) 147 : __clobber_all); 148 } 149 150 SEC("cgroup/sendmsg6") 151 __description("pass ctx or null check, 4: ctx - const") 152 __failure __msg("negative offset ctx ptr R1 off=-612 disallowed") 153 __naked void null_check_4_ctx_const(void) 154 { 155 asm volatile (" \ 156 r1 += -612; \ 157 call %[bpf_get_netns_cookie]; \ 158 r0 = 0; \ 159 exit; \ 160 " : 161 : __imm(bpf_get_netns_cookie) 162 : __clobber_all); 163 } 164 165 SEC("cgroup/connect4") 166 __description("pass ctx or null check, 5: null (connect)") 167 __success 168 __naked void null_check_5_null_connect(void) 169 { 170 asm volatile (" \ 171 r1 = 0; \ 172 call %[bpf_get_netns_cookie]; \ 173 r0 = 0; \ 174 exit; \ 175 " : 176 : __imm(bpf_get_netns_cookie) 177 : __clobber_all); 178 } 179 180 SEC("cgroup/post_bind4") 181 __description("pass ctx or null check, 6: null (bind)") 182 __success 183 __naked void null_check_6_null_bind(void) 184 { 185 asm volatile (" \ 186 r1 = 0; \ 187 call %[bpf_get_netns_cookie]; \ 188 r0 = 0; \ 189 exit; \ 190 " : 191 : __imm(bpf_get_netns_cookie) 192 : __clobber_all); 193 } 194 195 SEC("cgroup/post_bind4") 196 __description("pass ctx or null check, 7: ctx (bind)") 197 __success 198 __naked void null_check_7_ctx_bind(void) 199 { 200 asm volatile (" \ 201 call %[bpf_get_socket_cookie]; \ 202 r0 = 0; \ 203 exit; \ 204 " : 205 : __imm(bpf_get_socket_cookie) 206 : __clobber_all); 207 } 208 209 SEC("cgroup/post_bind4") 210 __description("pass ctx or null check, 8: null (bind)") 211 __failure __msg("R1 type=scalar expected=ctx") 212 __naked void null_check_8_null_bind(void) 213 { 214 asm volatile (" \ 215 r1 = 0; \ 216 call %[bpf_get_socket_cookie]; \ 217 r0 = 0; \ 218 exit; \ 219 " : 220 : __imm(bpf_get_socket_cookie) 221 : __clobber_all); 222 } 223 224 #define narrow_load(type, ctx, field) \ 225 SEC(type) \ 226 __description("narrow load on field " #field " of " #ctx) \ 227 __failure __msg("invalid bpf_context access") \ 228 __naked void invalid_narrow_load##ctx##field(void) \ 229 { \ 230 asm volatile (" \ 231 r1 = *(u32 *)(r1 + %[off]); \ 232 r0 = 0; \ 233 exit;" \ 234 : \ 235 : __imm_const(off, offsetof(struct ctx, field) + 4) \ 236 : __clobber_all); \ 237 } 238 239 narrow_load("cgroup/getsockopt", bpf_sockopt, sk); 240 narrow_load("cgroup/getsockopt", bpf_sockopt, optval); 241 narrow_load("cgroup/getsockopt", bpf_sockopt, optval_end); 242 narrow_load("tc", __sk_buff, sk); 243 narrow_load("cgroup/bind4", bpf_sock_addr, sk); 244 narrow_load("sockops", bpf_sock_ops, sk); 245 narrow_load("sockops", bpf_sock_ops, skb_data); 246 narrow_load("sockops", bpf_sock_ops, skb_data_end); 247 narrow_load("sockops", bpf_sock_ops, skb_hwtstamp); 248 249 #define unaligned_access(type, ctx, field) \ 250 SEC(type) \ 251 __description("unaligned access on field " #field " of " #ctx) \ 252 __failure __msg("invalid bpf_context access") \ 253 __naked void unaligned_ctx_access_##ctx##field(void) \ 254 { \ 255 asm volatile (" \ 256 r1 = *(u%[size] *)(r1 + %[off]); \ 257 r0 = 0; \ 258 exit;" \ 259 : \ 260 : __imm_const(size, sizeof_field(struct ctx, field) * 8), \ 261 __imm_const(off, offsetof(struct ctx, field) + 1) \ 262 : __clobber_all); \ 263 } 264 265 unaligned_access("flow_dissector", __sk_buff, data); 266 unaligned_access("netfilter", bpf_nf_ctx, skb); 267 268 #define padding_access(type, ctx, prev_field, sz) \ 269 SEC(type) \ 270 __description("access on " #ctx " padding after " #prev_field) \ 271 __naked void padding_ctx_access_##ctx(void) \ 272 { \ 273 asm volatile (" \ 274 r1 = *(u%[size] *)(r1 + %[off]); \ 275 r0 = 0; \ 276 exit;" \ 277 : \ 278 : __imm_const(size, sz * 8), \ 279 __imm_const(off, offsetofend(struct ctx, prev_field)) \ 280 : __clobber_all); \ 281 } 282 283 __failure __msg("invalid bpf_context access") 284 padding_access("cgroup/bind4", bpf_sock_addr, msg_src_ip6[3], 4); 285 286 __success 287 padding_access("sk_lookup", bpf_sk_lookup, remote_port, 2); 288 289 __failure __msg("invalid bpf_context access") 290 padding_access("tc", __sk_buff, tstamp_type, 2); 291 292 __failure __msg("invalid bpf_context access") 293 padding_access("cgroup/post_bind4", bpf_sock, dst_port, 2); 294 295 __failure __msg("invalid bpf_context access") 296 padding_access("sk_reuseport", sk_reuseport_md, hash, 4); 297 298 SEC("?syscall") 299 __description("syscall: write to ctx with fixed offset") 300 __success 301 int syscall_ctx_fixed_off_write(void *ctx) 302 { 303 char *p = ctx; 304 305 *(__u32 *)p = 0; 306 *(__u32 *)(p + 4) = 0; 307 return 0; 308 } 309 310 SEC("?syscall") 311 __description("syscall: read ctx with fixed offset") 312 __success 313 int syscall_ctx_fixed_off_read(void *ctx) 314 { 315 char *p = ctx; 316 volatile __u32 val; 317 318 val = *(__u32 *)(p + 4); 319 (void)val; 320 return 0; 321 } 322 323 SEC("?syscall") 324 __description("syscall: unaligned read ctx with fixed offset") 325 __success 326 int syscall_ctx_unaligned_fixed_off_read(void *ctx) 327 { 328 char *p = ctx; 329 volatile __u32 val; 330 331 val = *(__u32 *)(p + 2); 332 (void)val; 333 return 0; 334 } 335 336 SEC("?syscall") 337 __description("syscall: unaligned write ctx with fixed offset") 338 __success 339 int syscall_ctx_unaligned_fixed_off_write(void *ctx) 340 { 341 char *p = ctx; 342 343 *(__u32 *)(p + 2) = 0; 344 return 0; 345 } 346 347 SEC("?syscall") 348 __description("syscall: read ctx with variable offset") 349 __success 350 int syscall_ctx_var_off_read(void *ctx) 351 { 352 __u64 off = bpf_get_prandom_u32(); 353 char *p = ctx; 354 volatile __u32 val; 355 356 off &= 0xfc; 357 p += off; 358 val = *(__u32 *)p; 359 (void)val; 360 return 0; 361 } 362 363 SEC("?syscall") 364 __description("syscall: write ctx with variable offset") 365 __success 366 int syscall_ctx_var_off_write(void *ctx) 367 { 368 __u64 off = bpf_get_prandom_u32(); 369 char *p = ctx; 370 371 off &= 0xfc; 372 p += off; 373 *(__u32 *)p = 0; 374 return 0; 375 } 376 377 SEC("?syscall") 378 __description("syscall: unaligned read ctx with variable offset") 379 __success 380 int syscall_ctx_unaligned_var_off_read(void *ctx) 381 { 382 __u64 off = bpf_get_prandom_u32(); 383 char *p = ctx; 384 volatile __u32 val; 385 386 off &= 0xfc; 387 off += 2; 388 p += off; 389 val = *(__u32 *)p; 390 (void)val; 391 return 0; 392 } 393 394 SEC("?syscall") 395 __description("syscall: unaligned write ctx with variable offset") 396 __success 397 int syscall_ctx_unaligned_var_off_write(void *ctx) 398 { 399 __u64 off = bpf_get_prandom_u32(); 400 char *p = ctx; 401 402 off &= 0xfc; 403 off += 2; 404 p += off; 405 *(__u32 *)p = 0; 406 return 0; 407 } 408 409 SEC("?syscall") 410 __description("syscall: reject ctx access past U16_MAX with fixed offset") 411 __failure __msg("outside of the allowed memory range") 412 int syscall_ctx_u16_max_fixed_off(void *ctx) 413 { 414 char *p = ctx; 415 volatile __u32 val; 416 417 p += 65535; 418 val = *(__u32 *)p; 419 (void)val; 420 return 0; 421 } 422 423 SEC("?syscall") 424 __description("syscall: reject ctx access past U16_MAX with variable offset") 425 __failure __msg("outside of the allowed memory range") 426 int syscall_ctx_u16_max_var_off(void *ctx) 427 { 428 __u64 off = bpf_get_prandom_u32(); 429 char *p = ctx; 430 volatile __u32 val; 431 432 off &= 0xffff; 433 off += 1; 434 p += off; 435 val = *(__u32 *)p; 436 (void)val; 437 return 0; 438 } 439 440 SEC("?syscall") 441 __description("syscall: reject negative variable offset ctx access") 442 __failure __msg("min value is negative") 443 int syscall_ctx_neg_var_off(void *ctx) 444 { 445 __u64 off = bpf_get_prandom_u32(); 446 char *p = ctx; 447 448 off &= 4; 449 p -= off; 450 return *(__u32 *)p; 451 } 452 453 SEC("?syscall") 454 __description("syscall: reject unbounded variable offset ctx access") 455 __failure __msg("unbounded memory access") 456 int syscall_ctx_unbounded_var_off(void *ctx) 457 { 458 __u64 off = (__u32)bpf_get_prandom_u32(); 459 char *p = ctx; 460 461 off <<= 2; 462 p += off; 463 return *(__u32 *)p; 464 } 465 466 SEC("?syscall") 467 __description("syscall: helper read ctx with fixed offset") 468 __success 469 int syscall_ctx_helper_fixed_off_read(void *ctx) 470 { 471 char *p = ctx; 472 473 p += 4; 474 return bpf_strncmp(p, 4, ctx_strncmp_target); 475 } 476 477 SEC("?syscall") 478 __description("syscall: helper write ctx with fixed offset") 479 __success 480 int syscall_ctx_helper_fixed_off_write(void *ctx) 481 { 482 char *p = ctx; 483 484 p += 4; 485 return bpf_probe_read_kernel(p, 4, 0); 486 } 487 488 SEC("?syscall") 489 __description("syscall: helper unaligned read ctx with fixed offset") 490 __success 491 int syscall_ctx_helper_unaligned_fixed_off_read(void *ctx) 492 { 493 char *p = ctx; 494 495 p += 2; 496 return bpf_strncmp(p, 4, ctx_strncmp_target); 497 } 498 499 SEC("?syscall") 500 __description("syscall: helper unaligned write ctx with fixed offset") 501 __success 502 int syscall_ctx_helper_unaligned_fixed_off_write(void *ctx) 503 { 504 char *p = ctx; 505 506 p += 2; 507 return bpf_probe_read_kernel(p, 4, 0); 508 } 509 510 SEC("?syscall") 511 __description("syscall: helper read ctx with variable offset") 512 __success 513 int syscall_ctx_helper_var_off_read(void *ctx) 514 { 515 __u64 off = bpf_get_prandom_u32(); 516 char *p = ctx; 517 518 off &= 0xfc; 519 p += off; 520 return bpf_strncmp(p, 4, ctx_strncmp_target); 521 } 522 523 SEC("?syscall") 524 __description("syscall: helper write ctx with variable offset") 525 __success 526 int syscall_ctx_helper_var_off_write(void *ctx) 527 { 528 __u64 off = bpf_get_prandom_u32(); 529 char *p = ctx; 530 531 off &= 0xfc; 532 p += off; 533 return bpf_probe_read_kernel(p, 4, 0); 534 } 535 536 SEC("?syscall") 537 __description("syscall: helper unaligned read ctx with variable offset") 538 __success 539 int syscall_ctx_helper_unaligned_var_off_read(void *ctx) 540 { 541 __u64 off = bpf_get_prandom_u32(); 542 char *p = ctx; 543 544 off &= 0xfc; 545 off += 2; 546 p += off; 547 return bpf_strncmp(p, 4, ctx_strncmp_target); 548 } 549 550 SEC("?syscall") 551 __description("syscall: helper unaligned write ctx with variable offset") 552 __success 553 int syscall_ctx_helper_unaligned_var_off_write(void *ctx) 554 { 555 __u64 off = bpf_get_prandom_u32(); 556 char *p = ctx; 557 558 off &= 0xfc; 559 off += 2; 560 p += off; 561 return bpf_probe_read_kernel(p, 4, 0); 562 } 563 564 SEC("?syscall") 565 __description("syscall: reject helper read ctx past U16_MAX with fixed offset") 566 __failure __msg("outside of the allowed memory range") 567 int syscall_ctx_helper_u16_max_fixed_off_read(void *ctx) 568 { 569 char *p = ctx; 570 571 p += 65535; 572 return bpf_strncmp(p, 4, ctx_strncmp_target); 573 } 574 575 SEC("?syscall") 576 __description("syscall: reject helper write ctx past U16_MAX with fixed offset") 577 __failure __msg("outside of the allowed memory range") 578 int syscall_ctx_helper_u16_max_fixed_off_write(void *ctx) 579 { 580 char *p = ctx; 581 582 p += 65535; 583 return bpf_probe_read_kernel(p, 4, 0); 584 } 585 586 SEC("?syscall") 587 __description("syscall: reject helper read ctx past U16_MAX with variable offset") 588 __failure __msg("outside of the allowed memory range") 589 int syscall_ctx_helper_u16_max_var_off_read(void *ctx) 590 { 591 __u64 off = bpf_get_prandom_u32(); 592 char *p = ctx; 593 594 off &= 0xffff; 595 off += 1; 596 p += off; 597 return bpf_strncmp(p, 4, ctx_strncmp_target); 598 } 599 600 SEC("?syscall") 601 __description("syscall: reject helper write ctx past U16_MAX with variable offset") 602 __failure __msg("outside of the allowed memory range") 603 int syscall_ctx_helper_u16_max_var_off_write(void *ctx) 604 { 605 __u64 off = bpf_get_prandom_u32(); 606 char *p = ctx; 607 608 off &= 0xffff; 609 off += 1; 610 p += off; 611 return bpf_probe_read_kernel(p, 4, 0); 612 } 613 614 SEC("?syscall") 615 __description("syscall: helper read zero-sized ctx access") 616 __success 617 int syscall_ctx_helper_zero_sized_read(void *ctx) 618 { 619 return bpf_snprintf(0, 0, ctx_snprintf_fmt, ctx, 0); 620 } 621 622 SEC("?syscall") 623 __description("syscall: helper write zero-sized ctx access") 624 __success 625 int syscall_ctx_helper_zero_sized_write(void *ctx) 626 { 627 return bpf_probe_read_kernel(ctx, 0, 0); 628 } 629 630 SEC("?syscall") 631 __description("syscall: kfunc access ctx with fixed offset") 632 __success 633 int syscall_ctx_kfunc_fixed_off(void *ctx) 634 { 635 char *p = ctx; 636 637 p += 4; 638 bpf_kfunc_call_test_mem_len_pass1(p, 4); 639 return 0; 640 } 641 642 SEC("?syscall") 643 __description("syscall: kfunc access ctx with variable offset") 644 __success 645 int syscall_ctx_kfunc_var_off(void *ctx) 646 { 647 __u64 off = bpf_get_prandom_u32(); 648 char *p = ctx; 649 650 off &= 0xfc; 651 p += off; 652 bpf_kfunc_call_test_mem_len_pass1(p, 4); 653 return 0; 654 } 655 656 SEC("?syscall") 657 __description("syscall: kfunc unaligned access ctx with fixed offset") 658 __success 659 int syscall_ctx_kfunc_unaligned_fixed_off(void *ctx) 660 { 661 char *p = ctx; 662 663 p += 2; 664 bpf_kfunc_call_test_mem_len_pass1(p, 4); 665 return 0; 666 } 667 668 SEC("?syscall") 669 __description("syscall: kfunc unaligned access ctx with variable offset") 670 __success 671 int syscall_ctx_kfunc_unaligned_var_off(void *ctx) 672 { 673 __u64 off = bpf_get_prandom_u32(); 674 char *p = ctx; 675 676 off &= 0xfc; 677 off += 2; 678 p += off; 679 bpf_kfunc_call_test_mem_len_pass1(p, 4); 680 return 0; 681 } 682 683 SEC("?syscall") 684 __description("syscall: reject kfunc ctx access past U16_MAX with fixed offset") 685 __failure __msg("outside of the allowed memory range") 686 int syscall_ctx_kfunc_u16_max_fixed_off(void *ctx) 687 { 688 char *p = ctx; 689 690 p += 65535; 691 bpf_kfunc_call_test_mem_len_pass1(p, 4); 692 return 0; 693 } 694 695 SEC("?syscall") 696 __description("syscall: reject kfunc ctx access past U16_MAX with variable offset") 697 __failure __msg("outside of the allowed memory range") 698 int syscall_ctx_kfunc_u16_max_var_off(void *ctx) 699 { 700 __u64 off = bpf_get_prandom_u32(); 701 char *p = ctx; 702 703 off &= 0xffff; 704 off += 1; 705 p += off; 706 bpf_kfunc_call_test_mem_len_pass1(p, 4); 707 return 0; 708 } 709 710 SEC("?syscall") 711 __description("syscall: kfunc access zero-sized ctx") 712 __success 713 int syscall_ctx_kfunc_zero_sized(void *ctx) 714 { 715 bpf_kfunc_call_test_mem_len_pass1(ctx, 0); 716 return 0; 717 } 718 719 /* 720 * For non-syscall program types without convert_ctx_access, direct ctx 721 * dereference is still allowed after adding a fixed offset, while variable 722 * and negative direct accesses reject. 723 * 724 * Passing ctx as a helper or kfunc memory argument is only permitted for 725 * syscall programs, so the helper and kfunc cases below validate rejection 726 * for non-syscall ctx pointers at fixed, variable, and zero-sized accesses. 727 */ 728 #define no_rewrite_ctx_access(type, name, off, load_t) \ 729 SEC("?" type) \ 730 __description(type ": read ctx at fixed offset") \ 731 __success \ 732 int no_rewrite_##name##_fixed(void *ctx) \ 733 { \ 734 char *p = ctx; \ 735 volatile load_t val; \ 736 \ 737 val = *(load_t *)(p + off); \ 738 (void)val; \ 739 return 0; \ 740 } \ 741 SEC("?" type) \ 742 __description(type ": reject variable offset ctx access") \ 743 __failure __msg("variable ctx access var_off=") \ 744 int no_rewrite_##name##_var(void *ctx) \ 745 { \ 746 __u64 off_var = bpf_get_prandom_u32(); \ 747 char *p = ctx; \ 748 \ 749 off_var &= 4; \ 750 p += off_var; \ 751 return *(load_t *)p; \ 752 } \ 753 SEC("?" type) \ 754 __description(type ": reject negative offset ctx access") \ 755 __failure __msg("invalid bpf_context access") \ 756 int no_rewrite_##name##_neg(void *ctx) \ 757 { \ 758 char *p = ctx; \ 759 \ 760 p -= 612; \ 761 return *(load_t *)p; \ 762 } \ 763 SEC("?" type) \ 764 __description(type ": reject helper read ctx at fixed offset") \ 765 __failure __msg("dereference of modified ctx ptr") \ 766 int no_rewrite_##name##_helper_read_fixed(void *ctx) \ 767 { \ 768 char *p = ctx; \ 769 \ 770 p += off; \ 771 return bpf_strncmp(p, 4, ctx_strncmp_target); \ 772 } \ 773 SEC("?" type) \ 774 __description(type ": reject helper write ctx at fixed offset") \ 775 __failure __msg("dereference of modified ctx ptr") \ 776 int no_rewrite_##name##_helper_write_fixed(void *ctx) \ 777 { \ 778 char *p = ctx; \ 779 \ 780 p += off; \ 781 return bpf_probe_read_kernel(p, 4, 0); \ 782 } \ 783 SEC("?" type) \ 784 __description(type ": reject helper read ctx with variable offset") \ 785 __failure __msg("variable ctx access var_off=") \ 786 int no_rewrite_##name##_helper_read_var(void *ctx) \ 787 { \ 788 __u64 off_var = bpf_get_prandom_u32(); \ 789 char *p = ctx; \ 790 \ 791 off_var &= 4; \ 792 p += off_var; \ 793 return bpf_strncmp(p, 4, ctx_strncmp_target); \ 794 } \ 795 SEC("?" type) \ 796 __description(type ": reject helper write ctx with variable offset") \ 797 __failure __msg("variable ctx access var_off=") \ 798 int no_rewrite_##name##_helper_write_var(void *ctx) \ 799 { \ 800 __u64 off_var = bpf_get_prandom_u32(); \ 801 char *p = ctx; \ 802 \ 803 off_var &= 4; \ 804 p += off_var; \ 805 return bpf_probe_read_kernel(p, 4, 0); \ 806 } \ 807 SEC("?" type) \ 808 __description(type ": reject helper read zero-sized ctx access") \ 809 __failure __msg("R4 type=ctx expected=fp") \ 810 int no_rewrite_##name##_helper_read_zero(void *ctx) \ 811 { \ 812 return bpf_snprintf(0, 0, ctx_snprintf_fmt, ctx, 0); \ 813 } \ 814 SEC("?" type) \ 815 __description(type ": reject helper write zero-sized ctx access") \ 816 __failure __msg("R1 type=ctx expected=fp") \ 817 int no_rewrite_##name##_helper_write_zero(void *ctx) \ 818 { \ 819 return bpf_probe_read_kernel(ctx, 0, 0); \ 820 } \ 821 SEC("?" type) \ 822 __description(type ": reject kfunc ctx at fixed offset") \ 823 __failure __msg("dereference of modified ctx ptr") \ 824 int no_rewrite_##name##_kfunc_fixed(void *ctx) \ 825 { \ 826 char *p = ctx; \ 827 \ 828 p += off; \ 829 bpf_kfunc_call_test_mem_len_pass1(p, 4); \ 830 return 0; \ 831 } \ 832 SEC("?" type) \ 833 __description(type ": reject kfunc ctx with variable offset") \ 834 __failure __msg("variable ctx access var_off=") \ 835 int no_rewrite_##name##_kfunc_var(void *ctx) \ 836 { \ 837 __u64 off_var = bpf_get_prandom_u32(); \ 838 char *p = ctx; \ 839 \ 840 off_var &= 4; \ 841 p += off_var; \ 842 bpf_kfunc_call_test_mem_len_pass1(p, 4); \ 843 return 0; \ 844 } \ 845 SEC("?" type) \ 846 __description(type ": reject kfunc zero-sized ctx access") \ 847 __failure __msg("R1 type=ctx expected=fp") \ 848 int no_rewrite_##name##_kfunc_zero(void *ctx) \ 849 { \ 850 bpf_kfunc_call_test_mem_len_pass1(ctx, 0); \ 851 return 0; \ 852 } 853 854 no_rewrite_ctx_access("kprobe", kprobe, 8, u64); 855 no_rewrite_ctx_access("tracepoint", tp, 8, u64); 856 no_rewrite_ctx_access("raw_tp", raw_tp, 8, u64); 857 no_rewrite_ctx_access("raw_tracepoint.w", raw_tp_w, 8, u64); 858 no_rewrite_ctx_access("fentry/bpf_modify_return_test", fentry, 8, u64); 859 no_rewrite_ctx_access("cgroup/dev", cgroup_dev, 4, u32); 860 no_rewrite_ctx_access("netfilter", netfilter, offsetof(struct bpf_nf_ctx, skb), u64); 861 862 char _license[] SEC("license") = "GPL"; 863