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