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 | |