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
dummy_prog_42_socket(void)41 __naked void dummy_prog_42_socket(void)
42 {
43 asm volatile ("r0 = 42; exit;");
44 }
45
46 SEC("socket")
47 __auxiliary __auxiliary_unpriv
dummy_prog_24_socket(void)48 __naked void dummy_prog_24_socket(void)
49 {
50 asm volatile ("r0 = 24; exit;");
51 }
52
53 SEC("socket")
54 __auxiliary __auxiliary_unpriv
dummy_prog_loop1_socket(void)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
dummy_prog_loop2_socket(void)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)
call_within_bounds_prog_once(void)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)
call_within_bounds_prog_loop(void)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)
call_within_bounds_no_prog(void)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)
call_within_bounds_key_2(void)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)
_2_key_2_first_branch(void)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)
_2_key_2_second_branch(void)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)
_0_key_2_first_branch(void)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)
_0_key_2_second_branch(void)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)
bounds_different_maps_first_branch(void)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)
bounds_different_maps_second_branch(void)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)
tail_call_out_of_bounds(void)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)
negative_index_to_tail_call(void)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)
_32bit_index_to_tail_call(void)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";
361