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
8void dummy_prog_42_socket(void);
9void dummy_prog_24_socket(void);
10void dummy_prog_loop1_socket(void);
11void dummy_prog_loop2_socket(void);
12
13struct {
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
26struct {
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
39SEC("socket")
40__auxiliary __auxiliary_unpriv
41__naked void dummy_prog_42_socket(void)
42{
43 asm volatile ("r0 = 42; exit;");
44}
45
46SEC("socket")
47__auxiliary __auxiliary_unpriv
48__naked void dummy_prog_24_socket(void)
49{
50 asm volatile ("r0 = 24; exit;");
51}
52
53SEC("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
69SEC("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
85SEC("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
102SEC("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
119SEC("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
136SEC("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
153SEC("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_%=; \
166l0_%=: r3 = 2; \
167 r2 = %[map_prog1_socket] ll; \
168l1_%=: 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
178SEC("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_%=; \
191l0_%=: r3 = 2; \
192 r2 = %[map_prog1_socket] ll; \
193l1_%=: 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
203SEC("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_%=; \
216l0_%=: r3 = 2; \
217 r2 = %[map_prog1_socket] ll; \
218l1_%=: 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
228SEC("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_%=; \
241l0_%=: r3 = 2; \
242 r2 = %[map_prog1_socket] ll; \
243l1_%=: 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
253SEC("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_%=; \
267l0_%=: r3 = 0; \
268 r2 = %[map_prog2_socket] ll; \
269l1_%=: 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
280SEC("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_%=; \
294l0_%=: r3 = 0; \
295 r2 = %[map_prog2_socket] ll; \
296l1_%=: 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
307SEC("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
324SEC("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
341SEC("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
360char _license[] SEC("license") = "GPL";
361

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