Skip to content

Commit 16a4257

Browse files
eddyz87Alexei Starovoitov
authored andcommitted
selftests/bpf: verifier/regalloc converted to inline assembly
Test verifier/regalloc automatically converted to use inline assembly. Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/r/20230421174234.2391278-17-eddyz87@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 8be6327 commit 16a4257

3 files changed

Lines changed: 366 additions & 277 deletions

File tree

tools/testing/selftests/bpf/prog_tests/verifier.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "verifier_raw_tp_writable.skel.h"
4747
#include "verifier_reg_equal.skel.h"
4848
#include "verifier_ref_tracking.skel.h"
49+
#include "verifier_regalloc.skel.h"
4950
#include "verifier_ringbuf.skel.h"
5051
#include "verifier_spill_fill.skel.h"
5152
#include "verifier_stack_ptr.skel.h"
@@ -134,6 +135,7 @@ void test_verifier_raw_stack(void) { RUN(verifier_raw_stack); }
134135
void test_verifier_raw_tp_writable(void) { RUN(verifier_raw_tp_writable); }
135136
void test_verifier_reg_equal(void) { RUN(verifier_reg_equal); }
136137
void test_verifier_ref_tracking(void) { RUN(verifier_ref_tracking); }
138+
void test_verifier_regalloc(void) { RUN(verifier_regalloc); }
137139
void test_verifier_ringbuf(void) { RUN(verifier_ringbuf); }
138140
void test_verifier_spill_fill(void) { RUN(verifier_spill_fill); }
139141
void test_verifier_stack_ptr(void) { RUN(verifier_stack_ptr); }
Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
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";

0 commit comments

Comments
 (0)