Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
9static const char ctx_strncmp_target[] = "ctx";
10static const char ctx_snprintf_fmt[] = "";
11
12SEC("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
26SEC("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
42SEC("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
57SEC("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
73SEC("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
88SEC("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
106SEC("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
120SEC("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
135SEC("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
150SEC("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
165SEC("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
180SEC("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
195SEC("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
209SEC("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
239narrow_load("cgroup/getsockopt", bpf_sockopt, sk);
240narrow_load("cgroup/getsockopt", bpf_sockopt, optval);
241narrow_load("cgroup/getsockopt", bpf_sockopt, optval_end);
242narrow_load("tc", __sk_buff, sk);
243narrow_load("cgroup/bind4", bpf_sock_addr, sk);
244narrow_load("sockops", bpf_sock_ops, sk);
245narrow_load("sockops", bpf_sock_ops, skb_data);
246narrow_load("sockops", bpf_sock_ops, skb_data_end);
247narrow_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
265unaligned_access("flow_dissector", __sk_buff, data);
266unaligned_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")
284padding_access("cgroup/bind4", bpf_sock_addr, msg_src_ip6[3], 4);
285
286__success
287padding_access("sk_lookup", bpf_sk_lookup, remote_port, 2);
288
289__failure __msg("invalid bpf_context access")
290padding_access("tc", __sk_buff, tstamp_type, 2);
291
292__failure __msg("invalid bpf_context access")
293padding_access("cgroup/post_bind4", bpf_sock, dst_port, 2);
294
295__failure __msg("invalid bpf_context access")
296padding_access("sk_reuseport", sk_reuseport_md, hash, 4);
297
298SEC("?syscall")
299__description("syscall: write to ctx with fixed offset")
300__success
301int 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
310SEC("?syscall")
311__description("syscall: read ctx with fixed offset")
312__success
313int 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
323SEC("?syscall")
324__description("syscall: unaligned read ctx with fixed offset")
325__success
326int 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
336SEC("?syscall")
337__description("syscall: unaligned write ctx with fixed offset")
338__success
339int syscall_ctx_unaligned_fixed_off_write(void *ctx)
340{
341 char *p = ctx;
342
343 *(__u32 *)(p + 2) = 0;
344 return 0;
345}
346
347SEC("?syscall")
348__description("syscall: read ctx with variable offset")
349__success
350int 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
363SEC("?syscall")
364__description("syscall: write ctx with variable offset")
365__success
366int 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
377SEC("?syscall")
378__description("syscall: unaligned read ctx with variable offset")
379__success
380int 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
394SEC("?syscall")
395__description("syscall: unaligned write ctx with variable offset")
396__success
397int 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
409SEC("?syscall")
410__description("syscall: reject ctx access past U16_MAX with fixed offset")
411__failure __msg("outside of the allowed memory range")
412int 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
423SEC("?syscall")
424__description("syscall: reject ctx access past U16_MAX with variable offset")
425__failure __msg("outside of the allowed memory range")
426int 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
440SEC("?syscall")
441__description("syscall: reject negative variable offset ctx access")
442__failure __msg("min value is negative")
443int 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
453SEC("?syscall")
454__description("syscall: reject unbounded variable offset ctx access")
455__failure __msg("unbounded memory access")
456int 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
466SEC("?syscall")
467__description("syscall: helper read ctx with fixed offset")
468__success
469int 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
477SEC("?syscall")
478__description("syscall: helper write ctx with fixed offset")
479__success
480int 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
488SEC("?syscall")
489__description("syscall: helper unaligned read ctx with fixed offset")
490__success
491int 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
499SEC("?syscall")
500__description("syscall: helper unaligned write ctx with fixed offset")
501__success
502int 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
510SEC("?syscall")
511__description("syscall: helper read ctx with variable offset")
512__success
513int 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
523SEC("?syscall")
524__description("syscall: helper write ctx with variable offset")
525__success
526int 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
536SEC("?syscall")
537__description("syscall: helper unaligned read ctx with variable offset")
538__success
539int 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
550SEC("?syscall")
551__description("syscall: helper unaligned write ctx with variable offset")
552__success
553int 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
564SEC("?syscall")
565__description("syscall: reject helper read ctx past U16_MAX with fixed offset")
566__failure __msg("outside of the allowed memory range")
567int 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
575SEC("?syscall")
576__description("syscall: reject helper write ctx past U16_MAX with fixed offset")
577__failure __msg("outside of the allowed memory range")
578int 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
586SEC("?syscall")
587__description("syscall: reject helper read ctx past U16_MAX with variable offset")
588__failure __msg("outside of the allowed memory range")
589int 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
600SEC("?syscall")
601__description("syscall: reject helper write ctx past U16_MAX with variable offset")
602__failure __msg("outside of the allowed memory range")
603int 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
614SEC("?syscall")
615__description("syscall: helper read zero-sized ctx access")
616__success
617int syscall_ctx_helper_zero_sized_read(void *ctx)
618{
619 return bpf_snprintf(0, 0, ctx_snprintf_fmt, ctx, 0);
620}
621
622SEC("?syscall")
623__description("syscall: helper write zero-sized ctx access")
624__success
625int syscall_ctx_helper_zero_sized_write(void *ctx)
626{
627 return bpf_probe_read_kernel(ctx, 0, 0);
628}
629
630SEC("?syscall")
631__description("syscall: kfunc access ctx with fixed offset")
632__success
633int 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
642SEC("?syscall")
643__description("syscall: kfunc access ctx with variable offset")
644__success
645int 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
656SEC("?syscall")
657__description("syscall: kfunc unaligned access ctx with fixed offset")
658__success
659int 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
668SEC("?syscall")
669__description("syscall: kfunc unaligned access ctx with variable offset")
670__success
671int 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
683SEC("?syscall")
684__description("syscall: reject kfunc ctx access past U16_MAX with fixed offset")
685__failure __msg("outside of the allowed memory range")
686int 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
695SEC("?syscall")
696__description("syscall: reject kfunc ctx access past U16_MAX with variable offset")
697__failure __msg("outside of the allowed memory range")
698int 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
710SEC("?syscall")
711__description("syscall: kfunc access zero-sized ctx")
712__success
713int 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
854no_rewrite_ctx_access("kprobe", kprobe, 8, u64);
855no_rewrite_ctx_access("tracepoint", tp, 8, u64);
856no_rewrite_ctx_access("raw_tp", raw_tp, 8, u64);
857no_rewrite_ctx_access("raw_tracepoint.w", raw_tp_w, 8, u64);
858no_rewrite_ctx_access("fentry/bpf_modify_return_test", fentry, 8, u64);
859no_rewrite_ctx_access("cgroup/dev", cgroup_dev, 4, u32);
860no_rewrite_ctx_access("netfilter", netfilter, offsetof(struct bpf_nf_ctx, skb), u64);
861
862char _license[] SEC("license") = "GPL";