xref: /linux/tools/testing/selftests/bpf/progs/verifier_ctx.c (revision 171580e432727a9e729f286075ee86070424f490)
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