Skip to content

Commit 6522284

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

3 files changed

Lines changed: 362 additions & 231 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
@@ -48,6 +48,7 @@
4848
#include "verifier_ref_tracking.skel.h"
4949
#include "verifier_regalloc.skel.h"
5050
#include "verifier_ringbuf.skel.h"
51+
#include "verifier_runtime_jit.skel.h"
5152
#include "verifier_spill_fill.skel.h"
5253
#include "verifier_stack_ptr.skel.h"
5354
#include "verifier_uninit.skel.h"
@@ -137,6 +138,7 @@ void test_verifier_reg_equal(void) { RUN(verifier_reg_equal); }
137138
void test_verifier_ref_tracking(void) { RUN(verifier_ref_tracking); }
138139
void test_verifier_regalloc(void) { RUN(verifier_regalloc); }
139140
void test_verifier_ringbuf(void) { RUN(verifier_ringbuf); }
141+
void test_verifier_runtime_jit(void) { RUN(verifier_runtime_jit); }
140142
void test_verifier_spill_fill(void) { RUN(verifier_spill_fill); }
141143
void test_verifier_stack_ptr(void) { RUN(verifier_stack_ptr); }
142144
void test_verifier_uninit(void) { RUN(verifier_uninit); }
Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Converted from tools/testing/selftests/bpf/verifier/runtime_jit.c */
3+
4+
#include <linux/bpf.h>
5+
#include <bpf/bpf_helpers.h>
6+
#include "bpf_misc.h"
7+
8+
void dummy_prog_42_socket(void);
9+
void dummy_prog_24_socket(void);
10+
void dummy_prog_loop1_socket(void);
11+
void dummy_prog_loop2_socket(void);
12+
13+
struct {
14+
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
15+
__uint(max_entries, 4);
16+
__uint(key_size, sizeof(int));
17+
__array(values, void (void));
18+
} map_prog1_socket SEC(".maps") = {
19+
.values = {
20+
[0] = (void *)&dummy_prog_42_socket,
21+
[1] = (void *)&dummy_prog_loop1_socket,
22+
[2] = (void *)&dummy_prog_24_socket,
23+
},
24+
};
25+
26+
struct {
27+
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
28+
__uint(max_entries, 8);
29+
__uint(key_size, sizeof(int));
30+
__array(values, void (void));
31+
} map_prog2_socket SEC(".maps") = {
32+
.values = {
33+
[1] = (void *)&dummy_prog_loop2_socket,
34+
[2] = (void *)&dummy_prog_24_socket,
35+
[7] = (void *)&dummy_prog_42_socket,
36+
},
37+
};
38+
39+
SEC("socket")
40+
__auxiliary __auxiliary_unpriv
41+
__naked void dummy_prog_42_socket(void)
42+
{
43+
asm volatile ("r0 = 42; exit;");
44+
}
45+
46+
SEC("socket")
47+
__auxiliary __auxiliary_unpriv
48+
__naked void dummy_prog_24_socket(void)
49+
{
50+
asm volatile ("r0 = 24; exit;");
51+
}
52+
53+
SEC("socket")
54+
__auxiliary __auxiliary_unpriv
55+
__naked void dummy_prog_loop1_socket(void)
56+
{
57+
asm volatile (" \
58+
r3 = 1; \
59+
r2 = %[map_prog1_socket] ll; \
60+
call %[bpf_tail_call]; \
61+
r0 = 41; \
62+
exit; \
63+
" :
64+
: __imm(bpf_tail_call),
65+
__imm_addr(map_prog1_socket)
66+
: __clobber_all);
67+
}
68+
69+
SEC("socket")
70+
__auxiliary __auxiliary_unpriv
71+
__naked void dummy_prog_loop2_socket(void)
72+
{
73+
asm volatile (" \
74+
r3 = 1; \
75+
r2 = %[map_prog2_socket] ll; \
76+
call %[bpf_tail_call]; \
77+
r0 = 41; \
78+
exit; \
79+
" :
80+
: __imm(bpf_tail_call),
81+
__imm_addr(map_prog2_socket)
82+
: __clobber_all);
83+
}
84+
85+
SEC("socket")
86+
__description("runtime/jit: tail_call within bounds, prog once")
87+
__success __success_unpriv __retval(42)
88+
__naked void call_within_bounds_prog_once(void)
89+
{
90+
asm volatile (" \
91+
r3 = 0; \
92+
r2 = %[map_prog1_socket] ll; \
93+
call %[bpf_tail_call]; \
94+
r0 = 1; \
95+
exit; \
96+
" :
97+
: __imm(bpf_tail_call),
98+
__imm_addr(map_prog1_socket)
99+
: __clobber_all);
100+
}
101+
102+
SEC("socket")
103+
__description("runtime/jit: tail_call within bounds, prog loop")
104+
__success __success_unpriv __retval(41)
105+
__naked void call_within_bounds_prog_loop(void)
106+
{
107+
asm volatile (" \
108+
r3 = 1; \
109+
r2 = %[map_prog1_socket] ll; \
110+
call %[bpf_tail_call]; \
111+
r0 = 1; \
112+
exit; \
113+
" :
114+
: __imm(bpf_tail_call),
115+
__imm_addr(map_prog1_socket)
116+
: __clobber_all);
117+
}
118+
119+
SEC("socket")
120+
__description("runtime/jit: tail_call within bounds, no prog")
121+
__success __success_unpriv __retval(1)
122+
__naked void call_within_bounds_no_prog(void)
123+
{
124+
asm volatile (" \
125+
r3 = 3; \
126+
r2 = %[map_prog1_socket] ll; \
127+
call %[bpf_tail_call]; \
128+
r0 = 1; \
129+
exit; \
130+
" :
131+
: __imm(bpf_tail_call),
132+
__imm_addr(map_prog1_socket)
133+
: __clobber_all);
134+
}
135+
136+
SEC("socket")
137+
__description("runtime/jit: tail_call within bounds, key 2")
138+
__success __success_unpriv __retval(24)
139+
__naked void call_within_bounds_key_2(void)
140+
{
141+
asm volatile (" \
142+
r3 = 2; \
143+
r2 = %[map_prog1_socket] ll; \
144+
call %[bpf_tail_call]; \
145+
r0 = 1; \
146+
exit; \
147+
" :
148+
: __imm(bpf_tail_call),
149+
__imm_addr(map_prog1_socket)
150+
: __clobber_all);
151+
}
152+
153+
SEC("socket")
154+
__description("runtime/jit: tail_call within bounds, key 2 / key 2, first branch")
155+
__success __success_unpriv __retval(24)
156+
__naked void _2_key_2_first_branch(void)
157+
{
158+
asm volatile (" \
159+
r0 = 13; \
160+
*(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \
161+
r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \
162+
if r0 == 13 goto l0_%=; \
163+
r3 = 2; \
164+
r2 = %[map_prog1_socket] ll; \
165+
goto l1_%=; \
166+
l0_%=: r3 = 2; \
167+
r2 = %[map_prog1_socket] ll; \
168+
l1_%=: call %[bpf_tail_call]; \
169+
r0 = 1; \
170+
exit; \
171+
" :
172+
: __imm(bpf_tail_call),
173+
__imm_addr(map_prog1_socket),
174+
__imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0]))
175+
: __clobber_all);
176+
}
177+
178+
SEC("socket")
179+
__description("runtime/jit: tail_call within bounds, key 2 / key 2, second branch")
180+
__success __success_unpriv __retval(24)
181+
__naked void _2_key_2_second_branch(void)
182+
{
183+
asm volatile (" \
184+
r0 = 14; \
185+
*(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \
186+
r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \
187+
if r0 == 13 goto l0_%=; \
188+
r3 = 2; \
189+
r2 = %[map_prog1_socket] ll; \
190+
goto l1_%=; \
191+
l0_%=: r3 = 2; \
192+
r2 = %[map_prog1_socket] ll; \
193+
l1_%=: call %[bpf_tail_call]; \
194+
r0 = 1; \
195+
exit; \
196+
" :
197+
: __imm(bpf_tail_call),
198+
__imm_addr(map_prog1_socket),
199+
__imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0]))
200+
: __clobber_all);
201+
}
202+
203+
SEC("socket")
204+
__description("runtime/jit: tail_call within bounds, key 0 / key 2, first branch")
205+
__success __success_unpriv __retval(24)
206+
__naked void _0_key_2_first_branch(void)
207+
{
208+
asm volatile (" \
209+
r0 = 13; \
210+
*(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \
211+
r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \
212+
if r0 == 13 goto l0_%=; \
213+
r3 = 0; \
214+
r2 = %[map_prog1_socket] ll; \
215+
goto l1_%=; \
216+
l0_%=: r3 = 2; \
217+
r2 = %[map_prog1_socket] ll; \
218+
l1_%=: call %[bpf_tail_call]; \
219+
r0 = 1; \
220+
exit; \
221+
" :
222+
: __imm(bpf_tail_call),
223+
__imm_addr(map_prog1_socket),
224+
__imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0]))
225+
: __clobber_all);
226+
}
227+
228+
SEC("socket")
229+
__description("runtime/jit: tail_call within bounds, key 0 / key 2, second branch")
230+
__success __success_unpriv __retval(42)
231+
__naked void _0_key_2_second_branch(void)
232+
{
233+
asm volatile (" \
234+
r0 = 14; \
235+
*(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \
236+
r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \
237+
if r0 == 13 goto l0_%=; \
238+
r3 = 0; \
239+
r2 = %[map_prog1_socket] ll; \
240+
goto l1_%=; \
241+
l0_%=: r3 = 2; \
242+
r2 = %[map_prog1_socket] ll; \
243+
l1_%=: call %[bpf_tail_call]; \
244+
r0 = 1; \
245+
exit; \
246+
" :
247+
: __imm(bpf_tail_call),
248+
__imm_addr(map_prog1_socket),
249+
__imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0]))
250+
: __clobber_all);
251+
}
252+
253+
SEC("socket")
254+
__description("runtime/jit: tail_call within bounds, different maps, first branch")
255+
__success __failure_unpriv __msg_unpriv("tail_call abusing map_ptr")
256+
__retval(1)
257+
__naked void bounds_different_maps_first_branch(void)
258+
{
259+
asm volatile (" \
260+
r0 = 13; \
261+
*(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \
262+
r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \
263+
if r0 == 13 goto l0_%=; \
264+
r3 = 0; \
265+
r2 = %[map_prog1_socket] ll; \
266+
goto l1_%=; \
267+
l0_%=: r3 = 0; \
268+
r2 = %[map_prog2_socket] ll; \
269+
l1_%=: call %[bpf_tail_call]; \
270+
r0 = 1; \
271+
exit; \
272+
" :
273+
: __imm(bpf_tail_call),
274+
__imm_addr(map_prog1_socket),
275+
__imm_addr(map_prog2_socket),
276+
__imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0]))
277+
: __clobber_all);
278+
}
279+
280+
SEC("socket")
281+
__description("runtime/jit: tail_call within bounds, different maps, second branch")
282+
__success __failure_unpriv __msg_unpriv("tail_call abusing map_ptr")
283+
__retval(42)
284+
__naked void bounds_different_maps_second_branch(void)
285+
{
286+
asm volatile (" \
287+
r0 = 14; \
288+
*(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \
289+
r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \
290+
if r0 == 13 goto l0_%=; \
291+
r3 = 0; \
292+
r2 = %[map_prog1_socket] ll; \
293+
goto l1_%=; \
294+
l0_%=: r3 = 0; \
295+
r2 = %[map_prog2_socket] ll; \
296+
l1_%=: call %[bpf_tail_call]; \
297+
r0 = 1; \
298+
exit; \
299+
" :
300+
: __imm(bpf_tail_call),
301+
__imm_addr(map_prog1_socket),
302+
__imm_addr(map_prog2_socket),
303+
__imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0]))
304+
: __clobber_all);
305+
}
306+
307+
SEC("socket")
308+
__description("runtime/jit: tail_call out of bounds")
309+
__success __success_unpriv __retval(2)
310+
__naked void tail_call_out_of_bounds(void)
311+
{
312+
asm volatile (" \
313+
r3 = 256; \
314+
r2 = %[map_prog1_socket] ll; \
315+
call %[bpf_tail_call]; \
316+
r0 = 2; \
317+
exit; \
318+
" :
319+
: __imm(bpf_tail_call),
320+
__imm_addr(map_prog1_socket)
321+
: __clobber_all);
322+
}
323+
324+
SEC("socket")
325+
__description("runtime/jit: pass negative index to tail_call")
326+
__success __success_unpriv __retval(2)
327+
__naked void negative_index_to_tail_call(void)
328+
{
329+
asm volatile (" \
330+
r3 = -1; \
331+
r2 = %[map_prog1_socket] ll; \
332+
call %[bpf_tail_call]; \
333+
r0 = 2; \
334+
exit; \
335+
" :
336+
: __imm(bpf_tail_call),
337+
__imm_addr(map_prog1_socket)
338+
: __clobber_all);
339+
}
340+
341+
SEC("socket")
342+
__description("runtime/jit: pass > 32bit index to tail_call")
343+
__success __success_unpriv __retval(42)
344+
/* Verifier rewrite for unpriv skips tail call here. */
345+
__retval_unpriv(2)
346+
__naked void _32bit_index_to_tail_call(void)
347+
{
348+
asm volatile (" \
349+
r3 = 0x100000000 ll; \
350+
r2 = %[map_prog1_socket] ll; \
351+
call %[bpf_tail_call]; \
352+
r0 = 2; \
353+
exit; \
354+
" :
355+
: __imm(bpf_tail_call),
356+
__imm_addr(map_prog1_socket)
357+
: __clobber_all);
358+
}
359+
360+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)