xref: /linux/tools/testing/selftests/bpf/progs/verifier_loops1.c (revision 45d8b572fac3aa8b49d53c946b3685eaf78a2824)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Converted from tools/testing/selftests/bpf/verifier/loops1.c */
3 
4 #include <linux/bpf.h>
5 #include <bpf/bpf_helpers.h>
6 #include "bpf_misc.h"
7 
8 SEC("xdp")
9 __description("bounded loop, count to 4")
10 __success __retval(4)
11 __naked void bounded_loop_count_to_4(void)
12 {
13 	asm volatile ("					\
14 	r0 = 0;						\
15 l0_%=:	r0 += 1;					\
16 	if r0 < 4 goto l0_%=;				\
17 	exit;						\
18 "	::: __clobber_all);
19 }
20 
21 SEC("tracepoint")
22 __description("bounded loop, count to 20")
23 __success
24 __naked void bounded_loop_count_to_20(void)
25 {
26 	asm volatile ("					\
27 	r0 = 0;						\
28 l0_%=:	r0 += 3;					\
29 	if r0 < 20 goto l0_%=;				\
30 	exit;						\
31 "	::: __clobber_all);
32 }
33 
34 SEC("tracepoint")
35 __description("bounded loop, count from positive unknown to 4")
36 __success
37 __naked void from_positive_unknown_to_4(void)
38 {
39 	asm volatile ("					\
40 	call %[bpf_get_prandom_u32];			\
41 	if r0 s< 0 goto l0_%=;				\
42 l1_%=:	r0 += 1;					\
43 	if r0 < 4 goto l1_%=;				\
44 l0_%=:	exit;						\
45 "	:
46 	: __imm(bpf_get_prandom_u32)
47 	: __clobber_all);
48 }
49 
50 SEC("tracepoint")
51 __description("bounded loop, count from totally unknown to 4")
52 __success
53 __naked void from_totally_unknown_to_4(void)
54 {
55 	asm volatile ("					\
56 	call %[bpf_get_prandom_u32];			\
57 l0_%=:	r0 += 1;					\
58 	if r0 < 4 goto l0_%=;				\
59 	exit;						\
60 "	:
61 	: __imm(bpf_get_prandom_u32)
62 	: __clobber_all);
63 }
64 
65 SEC("tracepoint")
66 __description("bounded loop, count to 4 with equality")
67 __success
68 __naked void count_to_4_with_equality(void)
69 {
70 	asm volatile ("					\
71 	r0 = 0;						\
72 l0_%=:	r0 += 1;					\
73 	if r0 != 4 goto l0_%=;				\
74 	exit;						\
75 "	::: __clobber_all);
76 }
77 
78 SEC("socket")
79 __description("bounded loop, start in the middle")
80 __success
81 __failure_unpriv __msg_unpriv("back-edge")
82 __naked void loop_start_in_the_middle(void)
83 {
84 	asm volatile ("					\
85 	r0 = 0;						\
86 	goto l0_%=;					\
87 l1_%=:	r0 += 1;					\
88 l0_%=:	if r0 < 4 goto l1_%=;				\
89 	exit;						\
90 "	::: __clobber_all);
91 }
92 
93 SEC("xdp")
94 __description("bounded loop containing a forward jump")
95 __success __retval(4)
96 __naked void loop_containing_a_forward_jump(void)
97 {
98 	asm volatile ("					\
99 	r0 = 0;						\
100 l1_%=:	r0 += 1;					\
101 	if r0 == r0 goto l0_%=;				\
102 l0_%=:	if r0 < 4 goto l1_%=;				\
103 	exit;						\
104 "	::: __clobber_all);
105 }
106 
107 SEC("tracepoint")
108 __description("bounded loop that jumps out rather than in")
109 __success
110 __naked void jumps_out_rather_than_in(void)
111 {
112 	asm volatile ("					\
113 	r6 = 0;						\
114 l1_%=:	r6 += 1;					\
115 	if r6 > 10000 goto l0_%=;			\
116 	call %[bpf_get_prandom_u32];			\
117 	goto l1_%=;					\
118 l0_%=:	exit;						\
119 "	:
120 	: __imm(bpf_get_prandom_u32)
121 	: __clobber_all);
122 }
123 
124 SEC("tracepoint")
125 __description("infinite loop after a conditional jump")
126 __failure __msg("program is too large")
127 __naked void loop_after_a_conditional_jump(void)
128 {
129 	asm volatile ("					\
130 	r0 = 5;						\
131 	if r0 < 4 goto l0_%=;				\
132 l1_%=:	r0 += 1;					\
133 	goto l1_%=;					\
134 l0_%=:	exit;						\
135 "	::: __clobber_all);
136 }
137 
138 SEC("tracepoint")
139 __description("bounded recursion")
140 __failure
141 /* verifier limitation in detecting max stack depth */
142 __msg("the call stack of 8 frames is too deep !")
143 __naked void bounded_recursion(void)
144 {
145 	asm volatile ("					\
146 	r1 = 0;						\
147 	call bounded_recursion__1;			\
148 	exit;						\
149 "	::: __clobber_all);
150 }
151 
152 static __naked __noinline __attribute__((used))
153 void bounded_recursion__1(void)
154 {
155 	asm volatile ("					\
156 	r1 += 1;					\
157 	r0 = r1;					\
158 	if r1 < 4 goto l0_%=;				\
159 	exit;						\
160 l0_%=:	call bounded_recursion__1;			\
161 	exit;						\
162 "	::: __clobber_all);
163 }
164 
165 SEC("tracepoint")
166 __description("infinite loop in two jumps")
167 __failure __msg("loop detected")
168 __naked void infinite_loop_in_two_jumps(void)
169 {
170 	asm volatile ("					\
171 	r0 = 0;						\
172 l1_%=:	goto l0_%=;					\
173 l0_%=:	if r0 < 4 goto l1_%=;				\
174 	exit;						\
175 "	::: __clobber_all);
176 }
177 
178 SEC("tracepoint")
179 __description("infinite loop: three-jump trick")
180 __failure __msg("loop detected")
181 __naked void infinite_loop_three_jump_trick(void)
182 {
183 	asm volatile ("					\
184 	r0 = 0;						\
185 l2_%=:	r0 += 1;					\
186 	r0 &= 1;					\
187 	if r0 < 2 goto l0_%=;				\
188 	exit;						\
189 l0_%=:	r0 += 1;					\
190 	r0 &= 1;					\
191 	if r0 < 2 goto l1_%=;				\
192 	exit;						\
193 l1_%=:	r0 += 1;					\
194 	r0 &= 1;					\
195 	if r0 < 2 goto l2_%=;				\
196 	exit;						\
197 "	::: __clobber_all);
198 }
199 
200 SEC("xdp")
201 __description("not-taken loop with back jump to 1st insn")
202 __success __retval(123)
203 __naked void back_jump_to_1st_insn_1(void)
204 {
205 	asm volatile ("					\
206 l0_%=:	r0 = 123;					\
207 	if r0 == 4 goto l0_%=;				\
208 	exit;						\
209 "	::: __clobber_all);
210 }
211 
212 SEC("xdp")
213 __description("taken loop with back jump to 1st insn")
214 __success __retval(55)
215 __naked void back_jump_to_1st_insn_2(void)
216 {
217 	asm volatile ("					\
218 	r1 = 10;					\
219 	r2 = 0;						\
220 	call back_jump_to_1st_insn_2__1;		\
221 	exit;						\
222 "	::: __clobber_all);
223 }
224 
225 static __naked __noinline __attribute__((used))
226 void back_jump_to_1st_insn_2__1(void)
227 {
228 	asm volatile ("					\
229 l0_%=:	r2 += r1;					\
230 	r1 -= 1;					\
231 	if r1 != 0 goto l0_%=;				\
232 	r0 = r2;					\
233 	exit;						\
234 "	::: __clobber_all);
235 }
236 
237 SEC("xdp")
238 __description("taken loop with back jump to 1st insn, 2")
239 __success __retval(55)
240 __naked void jump_to_1st_insn_2(void)
241 {
242 	asm volatile ("					\
243 	r1 = 10;					\
244 	r2 = 0;						\
245 	call jump_to_1st_insn_2__1;			\
246 	exit;						\
247 "	::: __clobber_all);
248 }
249 
250 static __naked __noinline __attribute__((used))
251 void jump_to_1st_insn_2__1(void)
252 {
253 	asm volatile ("					\
254 l0_%=:	r2 += r1;					\
255 	r1 -= 1;					\
256 	if w1 != 0 goto l0_%=;				\
257 	r0 = r2;					\
258 	exit;						\
259 "	::: __clobber_all);
260 }
261 
262 SEC("xdp")
263 __success
264 __naked void not_an_inifinite_loop(void)
265 {
266 	asm volatile ("					\
267 	call %[bpf_get_prandom_u32];			\
268 	r0 &= 0xff;					\
269 	*(u64 *)(r10 - 8) = r0;				\
270 	r0 = 0;						\
271 loop_%=:						\
272 	r0 = *(u64 *)(r10 - 8);				\
273 	if r0 > 10 goto exit_%=;			\
274 	r0 += 1;					\
275 	*(u64 *)(r10 - 8) = r0;				\
276 	r0 = 0;						\
277 	goto loop_%=;					\
278 exit_%=:						\
279 	r0 = 0;						\
280 	exit;						\
281 "	:
282 	: __imm(bpf_get_prandom_u32)
283 	: __clobber_all);
284 }
285 
286 char _license[] SEC("license") = "GPL";
287