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 | |