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