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("tracepoint")
79 __description("bounded loop, start in the middle")
80 __failure __msg("back-edge")
81 __naked void loop_start_in_the_middle(void)
82 {
83 	asm volatile ("					\
84 	r0 = 0;						\
85 	goto l0_%=;					\
86 l1_%=:	r0 += 1;					\
87 l0_%=:	if r0 < 4 goto l1_%=;				\
88 	exit;						\
89 "	::: __clobber_all);
90 }
91 
92 SEC("xdp")
93 __description("bounded loop containing a forward jump")
94 __success __retval(4)
95 __naked void loop_containing_a_forward_jump(void)
96 {
97 	asm volatile ("					\
98 	r0 = 0;						\
99 l1_%=:	r0 += 1;					\
100 	if r0 == r0 goto l0_%=;				\
101 l0_%=:	if r0 < 4 goto l1_%=;				\
102 	exit;						\
103 "	::: __clobber_all);
104 }
105 
106 SEC("tracepoint")
107 __description("bounded loop that jumps out rather than in")
108 __success
109 __naked void jumps_out_rather_than_in(void)
110 {
111 	asm volatile ("					\
112 	r6 = 0;						\
113 l1_%=:	r6 += 1;					\
114 	if r6 > 10000 goto l0_%=;			\
115 	call %[bpf_get_prandom_u32];			\
116 	goto l1_%=;					\
117 l0_%=:	exit;						\
118 "	:
119 	: __imm(bpf_get_prandom_u32)
120 	: __clobber_all);
121 }
122 
123 SEC("tracepoint")
124 __description("infinite loop after a conditional jump")
125 __failure __msg("program is too large")
126 __naked void loop_after_a_conditional_jump(void)
127 {
128 	asm volatile ("					\
129 	r0 = 5;						\
130 	if r0 < 4 goto l0_%=;				\
131 l1_%=:	r0 += 1;					\
132 	goto l1_%=;					\
133 l0_%=:	exit;						\
134 "	::: __clobber_all);
135 }
136 
137 SEC("tracepoint")
138 __description("bounded recursion")
139 __failure __msg("back-edge")
140 __naked void bounded_recursion(void)
141 {
142 	asm volatile ("					\
143 	r1 = 0;						\
144 	call bounded_recursion__1;			\
145 	exit;						\
146 "	::: __clobber_all);
147 }
148 
149 static __naked __noinline __attribute__((used))
150 void bounded_recursion__1(void)
151 {
152 	asm volatile ("					\
153 	r1 += 1;					\
154 	r0 = r1;					\
155 	if r1 < 4 goto l0_%=;				\
156 	exit;						\
157 l0_%=:	call bounded_recursion__1;			\
158 	exit;						\
159 "	::: __clobber_all);
160 }
161 
162 SEC("tracepoint")
163 __description("infinite loop in two jumps")
164 __failure __msg("loop detected")
165 __naked void infinite_loop_in_two_jumps(void)
166 {
167 	asm volatile ("					\
168 	r0 = 0;						\
169 l1_%=:	goto l0_%=;					\
170 l0_%=:	if r0 < 4 goto l1_%=;				\
171 	exit;						\
172 "	::: __clobber_all);
173 }
174 
175 SEC("tracepoint")
176 __description("infinite loop: three-jump trick")
177 __failure __msg("loop detected")
178 __naked void infinite_loop_three_jump_trick(void)
179 {
180 	asm volatile ("					\
181 	r0 = 0;						\
182 l2_%=:	r0 += 1;					\
183 	r0 &= 1;					\
184 	if r0 < 2 goto l0_%=;				\
185 	exit;						\
186 l0_%=:	r0 += 1;					\
187 	r0 &= 1;					\
188 	if r0 < 2 goto l1_%=;				\
189 	exit;						\
190 l1_%=:	r0 += 1;					\
191 	r0 &= 1;					\
192 	if r0 < 2 goto l2_%=;				\
193 	exit;						\
194 "	::: __clobber_all);
195 }
196 
197 SEC("xdp")
198 __description("not-taken loop with back jump to 1st insn")
199 __success __retval(123)
200 __naked void back_jump_to_1st_insn_1(void)
201 {
202 	asm volatile ("					\
203 l0_%=:	r0 = 123;					\
204 	if r0 == 4 goto l0_%=;				\
205 	exit;						\
206 "	::: __clobber_all);
207 }
208 
209 SEC("xdp")
210 __description("taken loop with back jump to 1st insn")
211 __success __retval(55)
212 __naked void back_jump_to_1st_insn_2(void)
213 {
214 	asm volatile ("					\
215 	r1 = 10;					\
216 	r2 = 0;						\
217 	call back_jump_to_1st_insn_2__1;		\
218 	exit;						\
219 "	::: __clobber_all);
220 }
221 
222 static __naked __noinline __attribute__((used))
223 void back_jump_to_1st_insn_2__1(void)
224 {
225 	asm volatile ("					\
226 l0_%=:	r2 += r1;					\
227 	r1 -= 1;					\
228 	if r1 != 0 goto l0_%=;				\
229 	r0 = r2;					\
230 	exit;						\
231 "	::: __clobber_all);
232 }
233 
234 SEC("xdp")
235 __description("taken loop with back jump to 1st insn, 2")
236 __success __retval(55)
237 __naked void jump_to_1st_insn_2(void)
238 {
239 	asm volatile ("					\
240 	r1 = 10;					\
241 	r2 = 0;						\
242 	call jump_to_1st_insn_2__1;			\
243 	exit;						\
244 "	::: __clobber_all);
245 }
246 
247 static __naked __noinline __attribute__((used))
248 void jump_to_1st_insn_2__1(void)
249 {
250 	asm volatile ("					\
251 l0_%=:	r2 += r1;					\
252 	r1 -= 1;					\
253 	if w1 != 0 goto l0_%=;				\
254 	r0 = r2;					\
255 	exit;						\
256 "	::: __clobber_all);
257 }
258 
259 char _license[] SEC("license") = "GPL";
260