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
10struct test_val {
11 unsigned int index;
12 int foo[MAX_ENTRIES];
13};
14
15struct {
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
22SEC("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); \
44l0_%=: 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
52SEC("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); \
74l0_%=: 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
82SEC("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); \
105l0_%=: 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
113SEC("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); \
137l0_%=: 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
145SEC("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); \
172l0_%=: 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
180SEC("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); \
208l0_%=: 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
216SEC("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); \
240l0_%=: 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
248SEC("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); \
272l0_%=: 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
280static __naked __noinline __attribute__((used))
281void regalloc_after_call__1(void)
282{
283 asm volatile (" \
284 r0 = 0; \
285 exit; \
286" ::: __clobber_all);
287}
288
289SEC("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; \
309l0_%=: 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
317static __naked __noinline __attribute__((used))
318void 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; \
327l0_%=: r0 = 0; \
328 exit; \
329" ::: __clobber_all);
330}
331
332SEC("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_%=; \
347l0_%=: /* 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_%=; \
351l1_%=: /* 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 */\
356l2_%=: 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
364char _license[] SEC("license") = "GPL";
365

source code of linux/tools/testing/selftests/bpf/progs/verifier_regalloc.c