1*57400dccSAndrii Nakryiko // SPDX-License-Identifier: GPL-2.0
2*57400dccSAndrii Nakryiko /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3*57400dccSAndrii Nakryiko 
4*57400dccSAndrii Nakryiko #include <errno.h>
5*57400dccSAndrii Nakryiko #include <string.h>
6*57400dccSAndrii Nakryiko #include <linux/bpf.h>
7*57400dccSAndrii Nakryiko #include <bpf/bpf_helpers.h>
8*57400dccSAndrii Nakryiko #include "bpf_misc.h"
9*57400dccSAndrii Nakryiko 
10*57400dccSAndrii Nakryiko char _license[] SEC("license") = "GPL";
11*57400dccSAndrii Nakryiko 
12*57400dccSAndrii Nakryiko #define ITER_HELPERS						\
13*57400dccSAndrii Nakryiko 	  __imm(bpf_iter_num_new),				\
14*57400dccSAndrii Nakryiko 	  __imm(bpf_iter_num_next),				\
15*57400dccSAndrii Nakryiko 	  __imm(bpf_iter_num_destroy)
16*57400dccSAndrii Nakryiko 
17*57400dccSAndrii Nakryiko SEC("?raw_tp")
18*57400dccSAndrii Nakryiko __success
force_clang_to_emit_btf_for_externs(void * ctx)19*57400dccSAndrii Nakryiko int force_clang_to_emit_btf_for_externs(void *ctx)
20*57400dccSAndrii Nakryiko {
21*57400dccSAndrii Nakryiko 	/* we need this as a workaround to enforce compiler emitting BTF
22*57400dccSAndrii Nakryiko 	 * information for bpf_iter_num_{new,next,destroy}() kfuncs,
23*57400dccSAndrii Nakryiko 	 * as, apparently, it doesn't emit it for symbols only referenced from
24*57400dccSAndrii Nakryiko 	 * assembly (or cleanup attribute, for that matter, as well)
25*57400dccSAndrii Nakryiko 	 */
26*57400dccSAndrii Nakryiko 	bpf_repeat(0);
27*57400dccSAndrii Nakryiko 
28*57400dccSAndrii Nakryiko 	return 0;
29*57400dccSAndrii Nakryiko }
30*57400dccSAndrii Nakryiko 
31*57400dccSAndrii Nakryiko SEC("?raw_tp")
32*57400dccSAndrii Nakryiko __success
consume_first_item_only(void * ctx)33*57400dccSAndrii Nakryiko int consume_first_item_only(void *ctx)
34*57400dccSAndrii Nakryiko {
35*57400dccSAndrii Nakryiko 	struct bpf_iter_num iter;
36*57400dccSAndrii Nakryiko 
37*57400dccSAndrii Nakryiko 	asm volatile (
38*57400dccSAndrii Nakryiko 		/* create iterator */
39*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
40*57400dccSAndrii Nakryiko 		"r2 = 0;"
41*57400dccSAndrii Nakryiko 		"r3 = 1000;"
42*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_new];"
43*57400dccSAndrii Nakryiko 
44*57400dccSAndrii Nakryiko 		/* consume first item */
45*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
46*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_next];"
47*57400dccSAndrii Nakryiko 
48*57400dccSAndrii Nakryiko 		"if r0 == 0 goto +1;"
49*57400dccSAndrii Nakryiko 		"r0 = *(u32 *)(r0 + 0);"
50*57400dccSAndrii Nakryiko 
51*57400dccSAndrii Nakryiko 		/* destroy iterator */
52*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
53*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_destroy];"
54*57400dccSAndrii Nakryiko 		:
55*57400dccSAndrii Nakryiko 		: __imm_ptr(iter), ITER_HELPERS
56*57400dccSAndrii Nakryiko 		: __clobber_common
57*57400dccSAndrii Nakryiko 	);
58*57400dccSAndrii Nakryiko 
59*57400dccSAndrii Nakryiko 	return 0;
60*57400dccSAndrii Nakryiko }
61*57400dccSAndrii Nakryiko 
62*57400dccSAndrii Nakryiko SEC("?raw_tp")
63*57400dccSAndrii Nakryiko __failure __msg("R0 invalid mem access 'scalar'")
missing_null_check_fail(void * ctx)64*57400dccSAndrii Nakryiko int missing_null_check_fail(void *ctx)
65*57400dccSAndrii Nakryiko {
66*57400dccSAndrii Nakryiko 	struct bpf_iter_num iter;
67*57400dccSAndrii Nakryiko 
68*57400dccSAndrii Nakryiko 	asm volatile (
69*57400dccSAndrii Nakryiko 		/* create iterator */
70*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
71*57400dccSAndrii Nakryiko 		"r2 = 0;"
72*57400dccSAndrii Nakryiko 		"r3 = 1000;"
73*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_new];"
74*57400dccSAndrii Nakryiko 
75*57400dccSAndrii Nakryiko 		/* consume first element */
76*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
77*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_next];"
78*57400dccSAndrii Nakryiko 
79*57400dccSAndrii Nakryiko 		/* FAIL: deref with no NULL check */
80*57400dccSAndrii Nakryiko 		"r1 = *(u32 *)(r0 + 0);"
81*57400dccSAndrii Nakryiko 
82*57400dccSAndrii Nakryiko 		/* destroy iterator */
83*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
84*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_destroy];"
85*57400dccSAndrii Nakryiko 		:
86*57400dccSAndrii Nakryiko 		: __imm_ptr(iter), ITER_HELPERS
87*57400dccSAndrii Nakryiko 		: __clobber_common
88*57400dccSAndrii Nakryiko 	);
89*57400dccSAndrii Nakryiko 
90*57400dccSAndrii Nakryiko 	return 0;
91*57400dccSAndrii Nakryiko }
92*57400dccSAndrii Nakryiko 
93*57400dccSAndrii Nakryiko SEC("?raw_tp")
94*57400dccSAndrii Nakryiko __failure
95*57400dccSAndrii Nakryiko __msg("invalid access to memory, mem_size=4 off=0 size=8")
96*57400dccSAndrii Nakryiko __msg("R0 min value is outside of the allowed memory range")
wrong_sized_read_fail(void * ctx)97*57400dccSAndrii Nakryiko int wrong_sized_read_fail(void *ctx)
98*57400dccSAndrii Nakryiko {
99*57400dccSAndrii Nakryiko 	struct bpf_iter_num iter;
100*57400dccSAndrii Nakryiko 
101*57400dccSAndrii Nakryiko 	asm volatile (
102*57400dccSAndrii Nakryiko 		/* create iterator */
103*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
104*57400dccSAndrii Nakryiko 		"r2 = 0;"
105*57400dccSAndrii Nakryiko 		"r3 = 1000;"
106*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_new];"
107*57400dccSAndrii Nakryiko 
108*57400dccSAndrii Nakryiko 		/* consume first element */
109*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
110*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_next];"
111*57400dccSAndrii Nakryiko 
112*57400dccSAndrii Nakryiko 		"if r0 == 0 goto +1;"
113*57400dccSAndrii Nakryiko 		/* FAIL: deref more than available 4 bytes */
114*57400dccSAndrii Nakryiko 		"r0 = *(u64 *)(r0 + 0);"
115*57400dccSAndrii Nakryiko 
116*57400dccSAndrii Nakryiko 		/* destroy iterator */
117*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
118*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_destroy];"
119*57400dccSAndrii Nakryiko 		:
120*57400dccSAndrii Nakryiko 		: __imm_ptr(iter), ITER_HELPERS
121*57400dccSAndrii Nakryiko 		: __clobber_common
122*57400dccSAndrii Nakryiko 	);
123*57400dccSAndrii Nakryiko 
124*57400dccSAndrii Nakryiko 	return 0;
125*57400dccSAndrii Nakryiko }
126*57400dccSAndrii Nakryiko 
127*57400dccSAndrii Nakryiko SEC("?raw_tp")
128*57400dccSAndrii Nakryiko __success __log_level(2)
__flag(BPF_F_TEST_STATE_FREQ)129*57400dccSAndrii Nakryiko __flag(BPF_F_TEST_STATE_FREQ)
130*57400dccSAndrii Nakryiko int simplest_loop(void *ctx)
131*57400dccSAndrii Nakryiko {
132*57400dccSAndrii Nakryiko 	struct bpf_iter_num iter;
133*57400dccSAndrii Nakryiko 
134*57400dccSAndrii Nakryiko 	asm volatile (
135*57400dccSAndrii Nakryiko 		"r6 = 0;" /* init sum */
136*57400dccSAndrii Nakryiko 
137*57400dccSAndrii Nakryiko 		/* create iterator */
138*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
139*57400dccSAndrii Nakryiko 		"r2 = 0;"
140*57400dccSAndrii Nakryiko 		"r3 = 10;"
141*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_new];"
142*57400dccSAndrii Nakryiko 
143*57400dccSAndrii Nakryiko 	"1:"
144*57400dccSAndrii Nakryiko 		/* consume next item */
145*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
146*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_next];"
147*57400dccSAndrii Nakryiko 
148*57400dccSAndrii Nakryiko 		"if r0 == 0 goto 2f;"
149*57400dccSAndrii Nakryiko 		"r0 = *(u32 *)(r0 + 0);"
150*57400dccSAndrii Nakryiko 		"r6 += r0;" /* accumulate sum */
151*57400dccSAndrii Nakryiko 		"goto 1b;"
152*57400dccSAndrii Nakryiko 
153*57400dccSAndrii Nakryiko 	"2:"
154*57400dccSAndrii Nakryiko 		/* destroy iterator */
155*57400dccSAndrii Nakryiko 		"r1 = %[iter];"
156*57400dccSAndrii Nakryiko 		"call %[bpf_iter_num_destroy];"
157*57400dccSAndrii Nakryiko 		:
158*57400dccSAndrii Nakryiko 		: __imm_ptr(iter), ITER_HELPERS
159*57400dccSAndrii Nakryiko 		: __clobber_common, "r6"
160*57400dccSAndrii Nakryiko 	);
161*57400dccSAndrii Nakryiko 
162*57400dccSAndrii Nakryiko 	return 0;
163*57400dccSAndrii Nakryiko }
164