xref: /linux/tools/testing/selftests/bpf/progs/verifier_runtime_jit.c (revision fd7d598270724cc787982ea48bbe17ad383a8b7f)
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";
361