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")
__flag(BPF_F_ANY_ALIGNMENT)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")
regalloc_negative(void)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")
__flag(BPF_F_ANY_ALIGNMENT)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")
__flag(BPF_F_ANY_ALIGNMENT)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")
__flag(BPF_F_ANY_ALIGNMENT)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")
__flag(BPF_F_ANY_ALIGNMENT)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")
__flag(BPF_F_ANY_ALIGNMENT)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")
__flag(BPF_F_ANY_ALIGNMENT)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))
regalloc_after_call__1(void)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")
__flag(BPF_F_ANY_ALIGNMENT)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))
regalloc_in_callee__1(void)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
regalloc_spill_jeq(void)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