1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Converted from tools/testing/selftests/bpf/verifier/regalloc.c */ |
3 | |
4 | #include <linux/bpf.h> |
5 | #include <bpf/bpf_helpers.h> |
6 | #include "bpf_misc.h" |
7 | |
8 | #define MAX_ENTRIES 11 |
9 | |
10 | struct test_val { |
11 | unsigned int index; |
12 | int foo[MAX_ENTRIES]; |
13 | }; |
14 | |
15 | struct { |
16 | __uint(type, BPF_MAP_TYPE_HASH); |
17 | __uint(max_entries, 1); |
18 | __type(key, long long); |
19 | __type(value, struct test_val); |
20 | } map_hash_48b SEC(".maps" ); |
21 | |
22 | SEC("tracepoint" ) |
23 | __description("regalloc basic" ) |
24 | __success __flag(BPF_F_ANY_ALIGNMENT) |
25 | __naked void regalloc_basic(void) |
26 | { |
27 | asm volatile (" \ |
28 | r6 = r1; \ |
29 | r1 = 0; \ |
30 | *(u64*)(r10 - 8) = r1; \ |
31 | r2 = r10; \ |
32 | r2 += -8; \ |
33 | r1 = %[map_hash_48b] ll; \ |
34 | call %[bpf_map_lookup_elem]; \ |
35 | if r0 == 0 goto l0_%=; \ |
36 | r7 = r0; \ |
37 | call %[bpf_get_prandom_u32]; \ |
38 | r2 = r0; \ |
39 | if r0 s> 20 goto l0_%=; \ |
40 | if r2 s< 0 goto l0_%=; \ |
41 | r7 += r0; \ |
42 | r7 += r2; \ |
43 | r0 = *(u64*)(r7 + 0); \ |
44 | l0_%=: exit; \ |
45 | " : |
46 | : __imm(bpf_get_prandom_u32), |
47 | __imm(bpf_map_lookup_elem), |
48 | __imm_addr(map_hash_48b) |
49 | : __clobber_all); |
50 | } |
51 | |
52 | SEC("tracepoint" ) |
53 | __description("regalloc negative" ) |
54 | __failure __msg("invalid access to map value, value_size=48 off=48 size=1" ) |
55 | __naked void regalloc_negative(void) |
56 | { |
57 | asm volatile (" \ |
58 | r6 = r1; \ |
59 | r1 = 0; \ |
60 | *(u64*)(r10 - 8) = r1; \ |
61 | r2 = r10; \ |
62 | r2 += -8; \ |
63 | r1 = %[map_hash_48b] ll; \ |
64 | call %[bpf_map_lookup_elem]; \ |
65 | if r0 == 0 goto l0_%=; \ |
66 | r7 = r0; \ |
67 | call %[bpf_get_prandom_u32]; \ |
68 | r2 = r0; \ |
69 | if r0 s> 24 goto l0_%=; \ |
70 | if r2 s< 0 goto l0_%=; \ |
71 | r7 += r0; \ |
72 | r7 += r2; \ |
73 | r0 = *(u8*)(r7 + 0); \ |
74 | l0_%=: exit; \ |
75 | " : |
76 | : __imm(bpf_get_prandom_u32), |
77 | __imm(bpf_map_lookup_elem), |
78 | __imm_addr(map_hash_48b) |
79 | : __clobber_all); |
80 | } |
81 | |
82 | SEC("tracepoint" ) |
83 | __description("regalloc src_reg mark" ) |
84 | __success __flag(BPF_F_ANY_ALIGNMENT) |
85 | __naked void regalloc_src_reg_mark(void) |
86 | { |
87 | asm volatile (" \ |
88 | r6 = r1; \ |
89 | r1 = 0; \ |
90 | *(u64*)(r10 - 8) = r1; \ |
91 | r2 = r10; \ |
92 | r2 += -8; \ |
93 | r1 = %[map_hash_48b] ll; \ |
94 | call %[bpf_map_lookup_elem]; \ |
95 | if r0 == 0 goto l0_%=; \ |
96 | r7 = r0; \ |
97 | call %[bpf_get_prandom_u32]; \ |
98 | r2 = r0; \ |
99 | if r0 s> 20 goto l0_%=; \ |
100 | r3 = 0; \ |
101 | if r3 s>= r2 goto l0_%=; \ |
102 | r7 += r0; \ |
103 | r7 += r2; \ |
104 | r0 = *(u64*)(r7 + 0); \ |
105 | l0_%=: exit; \ |
106 | " : |
107 | : __imm(bpf_get_prandom_u32), |
108 | __imm(bpf_map_lookup_elem), |
109 | __imm_addr(map_hash_48b) |
110 | : __clobber_all); |
111 | } |
112 | |
113 | SEC("tracepoint" ) |
114 | __description("regalloc src_reg negative" ) |
115 | __failure __msg("invalid access to map value, value_size=48 off=44 size=8" ) |
116 | __flag(BPF_F_ANY_ALIGNMENT) |
117 | __naked void regalloc_src_reg_negative(void) |
118 | { |
119 | asm volatile (" \ |
120 | r6 = r1; \ |
121 | r1 = 0; \ |
122 | *(u64*)(r10 - 8) = r1; \ |
123 | r2 = r10; \ |
124 | r2 += -8; \ |
125 | r1 = %[map_hash_48b] ll; \ |
126 | call %[bpf_map_lookup_elem]; \ |
127 | if r0 == 0 goto l0_%=; \ |
128 | r7 = r0; \ |
129 | call %[bpf_get_prandom_u32]; \ |
130 | r2 = r0; \ |
131 | if r0 s> 22 goto l0_%=; \ |
132 | r3 = 0; \ |
133 | if r3 s>= r2 goto l0_%=; \ |
134 | r7 += r0; \ |
135 | r7 += r2; \ |
136 | r0 = *(u64*)(r7 + 0); \ |
137 | l0_%=: exit; \ |
138 | " : |
139 | : __imm(bpf_get_prandom_u32), |
140 | __imm(bpf_map_lookup_elem), |
141 | __imm_addr(map_hash_48b) |
142 | : __clobber_all); |
143 | } |
144 | |
145 | SEC("tracepoint" ) |
146 | __description("regalloc and spill" ) |
147 | __success __flag(BPF_F_ANY_ALIGNMENT) |
148 | __naked void regalloc_and_spill(void) |
149 | { |
150 | asm volatile (" \ |
151 | r6 = r1; \ |
152 | r1 = 0; \ |
153 | *(u64*)(r10 - 8) = r1; \ |
154 | r2 = r10; \ |
155 | r2 += -8; \ |
156 | r1 = %[map_hash_48b] ll; \ |
157 | call %[bpf_map_lookup_elem]; \ |
158 | if r0 == 0 goto l0_%=; \ |
159 | r7 = r0; \ |
160 | call %[bpf_get_prandom_u32]; \ |
161 | r2 = r0; \ |
162 | if r0 s> 20 goto l0_%=; \ |
163 | /* r0 has upper bound that should propagate into r2 */\ |
164 | *(u64*)(r10 - 8) = r2; /* spill r2 */ \ |
165 | r0 = 0; \ |
166 | r2 = 0; /* clear r0 and r2 */\ |
167 | r3 = *(u64*)(r10 - 8); /* fill r3 */ \ |
168 | if r0 s>= r3 goto l0_%=; \ |
169 | /* r3 has lower and upper bounds */ \ |
170 | r7 += r3; \ |
171 | r0 = *(u64*)(r7 + 0); \ |
172 | l0_%=: exit; \ |
173 | " : |
174 | : __imm(bpf_get_prandom_u32), |
175 | __imm(bpf_map_lookup_elem), |
176 | __imm_addr(map_hash_48b) |
177 | : __clobber_all); |
178 | } |
179 | |
180 | SEC("tracepoint" ) |
181 | __description("regalloc and spill negative" ) |
182 | __failure __msg("invalid access to map value, value_size=48 off=48 size=8" ) |
183 | __flag(BPF_F_ANY_ALIGNMENT) |
184 | __naked void regalloc_and_spill_negative(void) |
185 | { |
186 | asm volatile (" \ |
187 | r6 = r1; \ |
188 | r1 = 0; \ |
189 | *(u64*)(r10 - 8) = r1; \ |
190 | r2 = r10; \ |
191 | r2 += -8; \ |
192 | r1 = %[map_hash_48b] ll; \ |
193 | call %[bpf_map_lookup_elem]; \ |
194 | if r0 == 0 goto l0_%=; \ |
195 | r7 = r0; \ |
196 | call %[bpf_get_prandom_u32]; \ |
197 | r2 = r0; \ |
198 | if r0 s> 48 goto l0_%=; \ |
199 | /* r0 has upper bound that should propagate into r2 */\ |
200 | *(u64*)(r10 - 8) = r2; /* spill r2 */ \ |
201 | r0 = 0; \ |
202 | r2 = 0; /* clear r0 and r2 */\ |
203 | r3 = *(u64*)(r10 - 8); /* fill r3 */\ |
204 | if r0 s>= r3 goto l0_%=; \ |
205 | /* r3 has lower and upper bounds */ \ |
206 | r7 += r3; \ |
207 | r0 = *(u64*)(r7 + 0); \ |
208 | l0_%=: exit; \ |
209 | " : |
210 | : __imm(bpf_get_prandom_u32), |
211 | __imm(bpf_map_lookup_elem), |
212 | __imm_addr(map_hash_48b) |
213 | : __clobber_all); |
214 | } |
215 | |
216 | SEC("tracepoint" ) |
217 | __description("regalloc three regs" ) |
218 | __success __flag(BPF_F_ANY_ALIGNMENT) |
219 | __naked void regalloc_three_regs(void) |
220 | { |
221 | asm volatile (" \ |
222 | r6 = r1; \ |
223 | r1 = 0; \ |
224 | *(u64*)(r10 - 8) = r1; \ |
225 | r2 = r10; \ |
226 | r2 += -8; \ |
227 | r1 = %[map_hash_48b] ll; \ |
228 | call %[bpf_map_lookup_elem]; \ |
229 | if r0 == 0 goto l0_%=; \ |
230 | r7 = r0; \ |
231 | call %[bpf_get_prandom_u32]; \ |
232 | r2 = r0; \ |
233 | r4 = r2; \ |
234 | if r0 s> 12 goto l0_%=; \ |
235 | if r2 s< 0 goto l0_%=; \ |
236 | r7 += r0; \ |
237 | r7 += r2; \ |
238 | r7 += r4; \ |
239 | r0 = *(u64*)(r7 + 0); \ |
240 | l0_%=: exit; \ |
241 | " : |
242 | : __imm(bpf_get_prandom_u32), |
243 | __imm(bpf_map_lookup_elem), |
244 | __imm_addr(map_hash_48b) |
245 | : __clobber_all); |
246 | } |
247 | |
248 | SEC("tracepoint" ) |
249 | __description("regalloc after call" ) |
250 | __success __flag(BPF_F_ANY_ALIGNMENT) |
251 | __naked void regalloc_after_call(void) |
252 | { |
253 | asm volatile (" \ |
254 | r6 = r1; \ |
255 | r1 = 0; \ |
256 | *(u64*)(r10 - 8) = r1; \ |
257 | r2 = r10; \ |
258 | r2 += -8; \ |
259 | r1 = %[map_hash_48b] ll; \ |
260 | call %[bpf_map_lookup_elem]; \ |
261 | if r0 == 0 goto l0_%=; \ |
262 | r7 = r0; \ |
263 | call %[bpf_get_prandom_u32]; \ |
264 | r8 = r0; \ |
265 | r9 = r0; \ |
266 | call regalloc_after_call__1; \ |
267 | if r8 s> 20 goto l0_%=; \ |
268 | if r9 s< 0 goto l0_%=; \ |
269 | r7 += r8; \ |
270 | r7 += r9; \ |
271 | r0 = *(u64*)(r7 + 0); \ |
272 | l0_%=: exit; \ |
273 | " : |
274 | : __imm(bpf_get_prandom_u32), |
275 | __imm(bpf_map_lookup_elem), |
276 | __imm_addr(map_hash_48b) |
277 | : __clobber_all); |
278 | } |
279 | |
280 | static __naked __noinline __attribute__((used)) |
281 | void regalloc_after_call__1(void) |
282 | { |
283 | asm volatile (" \ |
284 | r0 = 0; \ |
285 | exit; \ |
286 | " ::: __clobber_all); |
287 | } |
288 | |
289 | SEC("tracepoint" ) |
290 | __description("regalloc in callee" ) |
291 | __success __flag(BPF_F_ANY_ALIGNMENT) |
292 | __naked void regalloc_in_callee(void) |
293 | { |
294 | asm volatile (" \ |
295 | r6 = r1; \ |
296 | r1 = 0; \ |
297 | *(u64*)(r10 - 8) = r1; \ |
298 | r2 = r10; \ |
299 | r2 += -8; \ |
300 | r1 = %[map_hash_48b] ll; \ |
301 | call %[bpf_map_lookup_elem]; \ |
302 | if r0 == 0 goto l0_%=; \ |
303 | r7 = r0; \ |
304 | call %[bpf_get_prandom_u32]; \ |
305 | r1 = r0; \ |
306 | r2 = r0; \ |
307 | r3 = r7; \ |
308 | call regalloc_in_callee__1; \ |
309 | l0_%=: exit; \ |
310 | " : |
311 | : __imm(bpf_get_prandom_u32), |
312 | __imm(bpf_map_lookup_elem), |
313 | __imm_addr(map_hash_48b) |
314 | : __clobber_all); |
315 | } |
316 | |
317 | static __naked __noinline __attribute__((used)) |
318 | void regalloc_in_callee__1(void) |
319 | { |
320 | asm volatile (" \ |
321 | if r1 s> 20 goto l0_%=; \ |
322 | if r2 s< 0 goto l0_%=; \ |
323 | r3 += r1; \ |
324 | r3 += r2; \ |
325 | r0 = *(u64*)(r3 + 0); \ |
326 | exit; \ |
327 | l0_%=: r0 = 0; \ |
328 | exit; \ |
329 | " ::: __clobber_all); |
330 | } |
331 | |
332 | SEC("tracepoint" ) |
333 | __description("regalloc, spill, JEQ" ) |
334 | __success |
335 | __naked void regalloc_spill_jeq(void) |
336 | { |
337 | asm volatile (" \ |
338 | r6 = r1; \ |
339 | r1 = 0; \ |
340 | *(u64*)(r10 - 8) = r1; \ |
341 | r2 = r10; \ |
342 | r2 += -8; \ |
343 | r1 = %[map_hash_48b] ll; \ |
344 | call %[bpf_map_lookup_elem]; \ |
345 | *(u64*)(r10 - 8) = r0; /* spill r0 */ \ |
346 | if r0 == 0 goto l0_%=; \ |
347 | l0_%=: /* The verifier will walk the rest twice with r0 == 0 and r0 == map_value */\ |
348 | call %[bpf_get_prandom_u32]; \ |
349 | r2 = r0; \ |
350 | if r2 == 20 goto l1_%=; \ |
351 | l1_%=: /* The verifier will walk the rest two more times with r0 == 20 and r0 == unknown */\ |
352 | r3 = *(u64*)(r10 - 8); /* fill r3 with map_value */\ |
353 | if r3 == 0 goto l2_%=; /* skip ldx if map_value == NULL */\ |
354 | /* Buggy verifier will think that r3 == 20 here */\ |
355 | r0 = *(u64*)(r3 + 0); /* read from map_value */\ |
356 | l2_%=: exit; \ |
357 | " : |
358 | : __imm(bpf_get_prandom_u32), |
359 | __imm(bpf_map_lookup_elem), |
360 | __imm_addr(map_hash_48b) |
361 | : __clobber_all); |
362 | } |
363 | |
364 | char _license[] SEC("license" ) = "GPL" ; |
365 | |