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