1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Converted from tools/testing/selftests/bpf/verifier/direct_packet_access.c */ |
3 | |
4 | #include <linux/bpf.h> |
5 | #include <bpf/bpf_helpers.h> |
6 | #include "bpf_misc.h" |
7 | |
8 | SEC("tc" ) |
9 | __description("pkt_end - pkt_start is allowed" ) |
10 | __success __retval(TEST_DATA_LEN) |
11 | __naked void end_pkt_start_is_allowed(void) |
12 | { |
13 | asm volatile (" \ |
14 | r0 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
15 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
16 | r0 -= r2; \ |
17 | exit; \ |
18 | " : |
19 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
20 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
21 | : __clobber_all); |
22 | } |
23 | |
24 | SEC("tc" ) |
25 | __description("direct packet access: test1" ) |
26 | __success __retval(0) |
27 | __naked void direct_packet_access_test1(void) |
28 | { |
29 | asm volatile (" \ |
30 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
31 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
32 | r0 = r2; \ |
33 | r0 += 8; \ |
34 | if r0 > r3 goto l0_%=; \ |
35 | r0 = *(u8*)(r2 + 0); \ |
36 | l0_%=: r0 = 0; \ |
37 | exit; \ |
38 | " : |
39 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
40 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
41 | : __clobber_all); |
42 | } |
43 | |
44 | SEC("tc" ) |
45 | __description("direct packet access: test2" ) |
46 | __success __retval(0) |
47 | __naked void direct_packet_access_test2(void) |
48 | { |
49 | asm volatile (" \ |
50 | r0 = 1; \ |
51 | r4 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
52 | r3 = *(u32*)(r1 + %[__sk_buff_data]); \ |
53 | r5 = r3; \ |
54 | r5 += 14; \ |
55 | if r5 > r4 goto l0_%=; \ |
56 | r0 = *(u8*)(r3 + 7); \ |
57 | r4 = *(u8*)(r3 + 12); \ |
58 | r4 *= 14; \ |
59 | r3 = *(u32*)(r1 + %[__sk_buff_data]); \ |
60 | r3 += r4; \ |
61 | r2 = *(u32*)(r1 + %[__sk_buff_len]); \ |
62 | r2 <<= 49; \ |
63 | r2 >>= 49; \ |
64 | r3 += r2; \ |
65 | r2 = r3; \ |
66 | r2 += 8; \ |
67 | r1 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
68 | if r2 > r1 goto l1_%=; \ |
69 | r1 = *(u8*)(r3 + 4); \ |
70 | l1_%=: r0 = 0; \ |
71 | l0_%=: exit; \ |
72 | " : |
73 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
74 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)), |
75 | __imm_const(__sk_buff_len, offsetof(struct __sk_buff, len)) |
76 | : __clobber_all); |
77 | } |
78 | |
79 | SEC("socket" ) |
80 | __description("direct packet access: test3" ) |
81 | __failure __msg("invalid bpf_context access off=76" ) |
82 | __failure_unpriv |
83 | __naked void direct_packet_access_test3(void) |
84 | { |
85 | asm volatile (" \ |
86 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
87 | r0 = 0; \ |
88 | exit; \ |
89 | " : |
90 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)) |
91 | : __clobber_all); |
92 | } |
93 | |
94 | SEC("tc" ) |
95 | __description("direct packet access: test4 (write)" ) |
96 | __success __retval(0) |
97 | __naked void direct_packet_access_test4_write(void) |
98 | { |
99 | asm volatile (" \ |
100 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
101 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
102 | r0 = r2; \ |
103 | r0 += 8; \ |
104 | if r0 > r3 goto l0_%=; \ |
105 | *(u8*)(r2 + 0) = r2; \ |
106 | l0_%=: r0 = 0; \ |
107 | exit; \ |
108 | " : |
109 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
110 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
111 | : __clobber_all); |
112 | } |
113 | |
114 | SEC("tc" ) |
115 | __description("direct packet access: test5 (pkt_end >= reg, good access)" ) |
116 | __success __retval(0) |
117 | __naked void pkt_end_reg_good_access(void) |
118 | { |
119 | asm volatile (" \ |
120 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
121 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
122 | r0 = r2; \ |
123 | r0 += 8; \ |
124 | if r3 >= r0 goto l0_%=; \ |
125 | r0 = 1; \ |
126 | exit; \ |
127 | l0_%=: r0 = *(u8*)(r2 + 0); \ |
128 | r0 = 0; \ |
129 | exit; \ |
130 | " : |
131 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
132 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
133 | : __clobber_all); |
134 | } |
135 | |
136 | SEC("tc" ) |
137 | __description("direct packet access: test6 (pkt_end >= reg, bad access)" ) |
138 | __failure __msg("invalid access to packet" ) |
139 | __naked void pkt_end_reg_bad_access(void) |
140 | { |
141 | asm volatile (" \ |
142 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
143 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
144 | r0 = r2; \ |
145 | r0 += 8; \ |
146 | if r3 >= r0 goto l0_%=; \ |
147 | r0 = *(u8*)(r2 + 0); \ |
148 | r0 = 1; \ |
149 | exit; \ |
150 | l0_%=: r0 = 0; \ |
151 | exit; \ |
152 | " : |
153 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
154 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
155 | : __clobber_all); |
156 | } |
157 | |
158 | SEC("tc" ) |
159 | __description("direct packet access: test7 (pkt_end >= reg, both accesses)" ) |
160 | __failure __msg("invalid access to packet" ) |
161 | __naked void pkt_end_reg_both_accesses(void) |
162 | { |
163 | asm volatile (" \ |
164 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
165 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
166 | r0 = r2; \ |
167 | r0 += 8; \ |
168 | if r3 >= r0 goto l0_%=; \ |
169 | r0 = *(u8*)(r2 + 0); \ |
170 | r0 = 1; \ |
171 | exit; \ |
172 | l0_%=: r0 = *(u8*)(r2 + 0); \ |
173 | r0 = 0; \ |
174 | exit; \ |
175 | " : |
176 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
177 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
178 | : __clobber_all); |
179 | } |
180 | |
181 | SEC("tc" ) |
182 | __description("direct packet access: test8 (double test, variant 1)" ) |
183 | __success __retval(0) |
184 | __naked void test8_double_test_variant_1(void) |
185 | { |
186 | asm volatile (" \ |
187 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
188 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
189 | r0 = r2; \ |
190 | r0 += 8; \ |
191 | if r3 >= r0 goto l0_%=; \ |
192 | if r0 > r3 goto l1_%=; \ |
193 | r0 = *(u8*)(r2 + 0); \ |
194 | l1_%=: r0 = 1; \ |
195 | exit; \ |
196 | l0_%=: r0 = *(u8*)(r2 + 0); \ |
197 | r0 = 0; \ |
198 | exit; \ |
199 | " : |
200 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
201 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
202 | : __clobber_all); |
203 | } |
204 | |
205 | SEC("tc" ) |
206 | __description("direct packet access: test9 (double test, variant 2)" ) |
207 | __success __retval(0) |
208 | __naked void test9_double_test_variant_2(void) |
209 | { |
210 | asm volatile (" \ |
211 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
212 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
213 | r0 = r2; \ |
214 | r0 += 8; \ |
215 | if r3 >= r0 goto l0_%=; \ |
216 | r0 = 1; \ |
217 | exit; \ |
218 | l0_%=: if r0 > r3 goto l1_%=; \ |
219 | r0 = *(u8*)(r2 + 0); \ |
220 | l1_%=: r0 = *(u8*)(r2 + 0); \ |
221 | r0 = 0; \ |
222 | exit; \ |
223 | " : |
224 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
225 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
226 | : __clobber_all); |
227 | } |
228 | |
229 | SEC("tc" ) |
230 | __description("direct packet access: test10 (write invalid)" ) |
231 | __failure __msg("invalid access to packet" ) |
232 | __naked void packet_access_test10_write_invalid(void) |
233 | { |
234 | asm volatile (" \ |
235 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
236 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
237 | r0 = r2; \ |
238 | r0 += 8; \ |
239 | if r0 > r3 goto l0_%=; \ |
240 | r0 = 0; \ |
241 | exit; \ |
242 | l0_%=: *(u8*)(r2 + 0) = r2; \ |
243 | r0 = 0; \ |
244 | exit; \ |
245 | " : |
246 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
247 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
248 | : __clobber_all); |
249 | } |
250 | |
251 | SEC("tc" ) |
252 | __description("direct packet access: test11 (shift, good access)" ) |
253 | __success __retval(1) |
254 | __naked void access_test11_shift_good_access(void) |
255 | { |
256 | asm volatile (" \ |
257 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
258 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
259 | r0 = r2; \ |
260 | r0 += 22; \ |
261 | if r0 > r3 goto l0_%=; \ |
262 | r3 = 144; \ |
263 | r5 = r3; \ |
264 | r5 += 23; \ |
265 | r5 >>= 3; \ |
266 | r6 = r2; \ |
267 | r6 += r5; \ |
268 | r0 = 1; \ |
269 | exit; \ |
270 | l0_%=: r0 = 0; \ |
271 | exit; \ |
272 | " : |
273 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
274 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
275 | : __clobber_all); |
276 | } |
277 | |
278 | SEC("tc" ) |
279 | __description("direct packet access: test12 (and, good access)" ) |
280 | __success __retval(1) |
281 | __naked void access_test12_and_good_access(void) |
282 | { |
283 | asm volatile (" \ |
284 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
285 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
286 | r0 = r2; \ |
287 | r0 += 22; \ |
288 | if r0 > r3 goto l0_%=; \ |
289 | r3 = 144; \ |
290 | r5 = r3; \ |
291 | r5 += 23; \ |
292 | r5 &= 15; \ |
293 | r6 = r2; \ |
294 | r6 += r5; \ |
295 | r0 = 1; \ |
296 | exit; \ |
297 | l0_%=: r0 = 0; \ |
298 | exit; \ |
299 | " : |
300 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
301 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
302 | : __clobber_all); |
303 | } |
304 | |
305 | SEC("tc" ) |
306 | __description("direct packet access: test13 (branches, good access)" ) |
307 | __success __retval(1) |
308 | __naked void access_test13_branches_good_access(void) |
309 | { |
310 | asm volatile (" \ |
311 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
312 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
313 | r0 = r2; \ |
314 | r0 += 22; \ |
315 | if r0 > r3 goto l0_%=; \ |
316 | r3 = *(u32*)(r1 + %[__sk_buff_mark]); \ |
317 | r4 = 1; \ |
318 | if r3 > r4 goto l1_%=; \ |
319 | r3 = 14; \ |
320 | goto l2_%=; \ |
321 | l1_%=: r3 = 24; \ |
322 | l2_%=: r5 = r3; \ |
323 | r5 += 23; \ |
324 | r5 &= 15; \ |
325 | r6 = r2; \ |
326 | r6 += r5; \ |
327 | r0 = 1; \ |
328 | exit; \ |
329 | l0_%=: r0 = 0; \ |
330 | exit; \ |
331 | " : |
332 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
333 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)), |
334 | __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) |
335 | : __clobber_all); |
336 | } |
337 | |
338 | SEC("tc" ) |
339 | __description("direct packet access: test14 (pkt_ptr += 0, CONST_IMM, good access)" ) |
340 | __success __retval(1) |
341 | __naked void _0_const_imm_good_access(void) |
342 | { |
343 | asm volatile (" \ |
344 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
345 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
346 | r0 = r2; \ |
347 | r0 += 22; \ |
348 | if r0 > r3 goto l0_%=; \ |
349 | r5 = 12; \ |
350 | r5 >>= 4; \ |
351 | r6 = r2; \ |
352 | r6 += r5; \ |
353 | r0 = *(u8*)(r6 + 0); \ |
354 | r0 = 1; \ |
355 | exit; \ |
356 | l0_%=: r0 = 0; \ |
357 | exit; \ |
358 | " : |
359 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
360 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
361 | : __clobber_all); |
362 | } |
363 | |
364 | SEC("tc" ) |
365 | __description("direct packet access: test15 (spill with xadd)" ) |
366 | __failure __msg("R2 invalid mem access 'scalar'" ) |
367 | __flag(BPF_F_ANY_ALIGNMENT) |
368 | __naked void access_test15_spill_with_xadd(void) |
369 | { |
370 | asm volatile (" \ |
371 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
372 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
373 | r0 = r2; \ |
374 | r0 += 8; \ |
375 | if r0 > r3 goto l0_%=; \ |
376 | r5 = 4096; \ |
377 | r4 = r10; \ |
378 | r4 += -8; \ |
379 | *(u64*)(r4 + 0) = r2; \ |
380 | lock *(u64 *)(r4 + 0) += r5; \ |
381 | r2 = *(u64*)(r4 + 0); \ |
382 | *(u32*)(r2 + 0) = r5; \ |
383 | r0 = 0; \ |
384 | l0_%=: exit; \ |
385 | " : |
386 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
387 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
388 | : __clobber_all); |
389 | } |
390 | |
391 | SEC("tc" ) |
392 | __description("direct packet access: test16 (arith on data_end)" ) |
393 | __failure __msg("R3 pointer arithmetic on pkt_end" ) |
394 | __naked void test16_arith_on_data_end(void) |
395 | { |
396 | asm volatile (" \ |
397 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
398 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
399 | r0 = r2; \ |
400 | r0 += 8; \ |
401 | r3 += 16; \ |
402 | if r0 > r3 goto l0_%=; \ |
403 | *(u8*)(r2 + 0) = r2; \ |
404 | l0_%=: r0 = 0; \ |
405 | exit; \ |
406 | " : |
407 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
408 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
409 | : __clobber_all); |
410 | } |
411 | |
412 | SEC("tc" ) |
413 | __description("direct packet access: test17 (pruning, alignment)" ) |
414 | __failure __msg("misaligned packet access off 2+0+15+-4 size 4" ) |
415 | __flag(BPF_F_STRICT_ALIGNMENT) |
416 | __naked void packet_access_test17_pruning_alignment(void) |
417 | { |
418 | asm volatile (" \ |
419 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
420 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
421 | r7 = *(u32*)(r1 + %[__sk_buff_mark]); \ |
422 | r0 = r2; \ |
423 | r0 += 14; \ |
424 | if r7 > 1 goto l0_%=; \ |
425 | l2_%=: if r0 > r3 goto l1_%=; \ |
426 | *(u32*)(r0 - 4) = r0; \ |
427 | l1_%=: r0 = 0; \ |
428 | exit; \ |
429 | l0_%=: r0 += 1; \ |
430 | goto l2_%=; \ |
431 | " : |
432 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
433 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)), |
434 | __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) |
435 | : __clobber_all); |
436 | } |
437 | |
438 | SEC("tc" ) |
439 | __description("direct packet access: test18 (imm += pkt_ptr, 1)" ) |
440 | __success __retval(0) |
441 | __naked void test18_imm_pkt_ptr_1(void) |
442 | { |
443 | asm volatile (" \ |
444 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
445 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
446 | r0 = 8; \ |
447 | r0 += r2; \ |
448 | if r0 > r3 goto l0_%=; \ |
449 | *(u8*)(r2 + 0) = r2; \ |
450 | l0_%=: r0 = 0; \ |
451 | exit; \ |
452 | " : |
453 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
454 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
455 | : __clobber_all); |
456 | } |
457 | |
458 | SEC("tc" ) |
459 | __description("direct packet access: test19 (imm += pkt_ptr, 2)" ) |
460 | __success __retval(0) |
461 | __naked void test19_imm_pkt_ptr_2(void) |
462 | { |
463 | asm volatile (" \ |
464 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
465 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
466 | r0 = r2; \ |
467 | r0 += 8; \ |
468 | if r0 > r3 goto l0_%=; \ |
469 | r4 = 4; \ |
470 | r4 += r2; \ |
471 | *(u8*)(r4 + 0) = r4; \ |
472 | l0_%=: r0 = 0; \ |
473 | exit; \ |
474 | " : |
475 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
476 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
477 | : __clobber_all); |
478 | } |
479 | |
480 | SEC("tc" ) |
481 | __description("direct packet access: test20 (x += pkt_ptr, 1)" ) |
482 | __success __retval(0) __flag(BPF_F_ANY_ALIGNMENT) |
483 | __naked void test20_x_pkt_ptr_1(void) |
484 | { |
485 | asm volatile (" \ |
486 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
487 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
488 | r0 = 0xffffffff; \ |
489 | *(u64*)(r10 - 8) = r0; \ |
490 | r0 = *(u64*)(r10 - 8); \ |
491 | r0 &= 0x7fff; \ |
492 | r4 = r0; \ |
493 | r4 += r2; \ |
494 | r5 = r4; \ |
495 | r4 += %[__imm_0]; \ |
496 | if r4 > r3 goto l0_%=; \ |
497 | *(u64*)(r5 + 0) = r4; \ |
498 | l0_%=: r0 = 0; \ |
499 | exit; \ |
500 | " : |
501 | : __imm_const(__imm_0, 0x7fff - 1), |
502 | __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
503 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
504 | : __clobber_all); |
505 | } |
506 | |
507 | SEC("tc" ) |
508 | __description("direct packet access: test21 (x += pkt_ptr, 2)" ) |
509 | __success __retval(0) __flag(BPF_F_ANY_ALIGNMENT) |
510 | __naked void test21_x_pkt_ptr_2(void) |
511 | { |
512 | asm volatile (" \ |
513 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
514 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
515 | r0 = r2; \ |
516 | r0 += 8; \ |
517 | if r0 > r3 goto l0_%=; \ |
518 | r4 = 0xffffffff; \ |
519 | *(u64*)(r10 - 8) = r4; \ |
520 | r4 = *(u64*)(r10 - 8); \ |
521 | r4 &= 0x7fff; \ |
522 | r4 += r2; \ |
523 | r5 = r4; \ |
524 | r4 += %[__imm_0]; \ |
525 | if r4 > r3 goto l0_%=; \ |
526 | *(u64*)(r5 + 0) = r4; \ |
527 | l0_%=: r0 = 0; \ |
528 | exit; \ |
529 | " : |
530 | : __imm_const(__imm_0, 0x7fff - 1), |
531 | __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
532 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
533 | : __clobber_all); |
534 | } |
535 | |
536 | SEC("tc" ) |
537 | __description("direct packet access: test22 (x += pkt_ptr, 3)" ) |
538 | __success __retval(0) __flag(BPF_F_ANY_ALIGNMENT) |
539 | __naked void test22_x_pkt_ptr_3(void) |
540 | { |
541 | asm volatile (" \ |
542 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
543 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
544 | r0 = r2; \ |
545 | r0 += 8; \ |
546 | *(u64*)(r10 - 8) = r2; \ |
547 | *(u64*)(r10 - 16) = r3; \ |
548 | r3 = *(u64*)(r10 - 16); \ |
549 | if r0 > r3 goto l0_%=; \ |
550 | r2 = *(u64*)(r10 - 8); \ |
551 | r4 = 0xffffffff; \ |
552 | lock *(u64 *)(r10 - 8) += r4; \ |
553 | r4 = *(u64*)(r10 - 8); \ |
554 | r4 >>= 49; \ |
555 | r4 += r2; \ |
556 | r0 = r4; \ |
557 | r0 += 2; \ |
558 | if r0 > r3 goto l0_%=; \ |
559 | r2 = 1; \ |
560 | *(u16*)(r4 + 0) = r2; \ |
561 | l0_%=: r0 = 0; \ |
562 | exit; \ |
563 | " : |
564 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
565 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
566 | : __clobber_all); |
567 | } |
568 | |
569 | SEC("tc" ) |
570 | __description("direct packet access: test23 (x += pkt_ptr, 4)" ) |
571 | __failure __msg("invalid access to packet, off=0 size=8, R5(id=3,off=0,r=0)" ) |
572 | __flag(BPF_F_ANY_ALIGNMENT) |
573 | __naked void test23_x_pkt_ptr_4(void) |
574 | { |
575 | asm volatile (" \ |
576 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
577 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
578 | r0 = *(u32*)(r1 + %[__sk_buff_mark]); \ |
579 | *(u64*)(r10 - 8) = r0; \ |
580 | r0 = *(u64*)(r10 - 8); \ |
581 | r0 &= 0xffff; \ |
582 | r4 = r0; \ |
583 | r0 = 31; \ |
584 | r0 += r4; \ |
585 | r0 += r2; \ |
586 | r5 = r0; \ |
587 | r0 += %[__imm_0]; \ |
588 | if r0 > r3 goto l0_%=; \ |
589 | *(u64*)(r5 + 0) = r0; \ |
590 | l0_%=: r0 = 0; \ |
591 | exit; \ |
592 | " : |
593 | : __imm_const(__imm_0, 0xffff - 1), |
594 | __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
595 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)), |
596 | __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) |
597 | : __clobber_all); |
598 | } |
599 | |
600 | SEC("tc" ) |
601 | __description("direct packet access: test24 (x += pkt_ptr, 5)" ) |
602 | __success __retval(0) __flag(BPF_F_ANY_ALIGNMENT) |
603 | __naked void test24_x_pkt_ptr_5(void) |
604 | { |
605 | asm volatile (" \ |
606 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
607 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
608 | r0 = 0xffffffff; \ |
609 | *(u64*)(r10 - 8) = r0; \ |
610 | r0 = *(u64*)(r10 - 8); \ |
611 | r0 &= 0xff; \ |
612 | r4 = r0; \ |
613 | r0 = 64; \ |
614 | r0 += r4; \ |
615 | r0 += r2; \ |
616 | r5 = r0; \ |
617 | r0 += %[__imm_0]; \ |
618 | if r0 > r3 goto l0_%=; \ |
619 | *(u64*)(r5 + 0) = r0; \ |
620 | l0_%=: r0 = 0; \ |
621 | exit; \ |
622 | " : |
623 | : __imm_const(__imm_0, 0x7fff - 1), |
624 | __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
625 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
626 | : __clobber_all); |
627 | } |
628 | |
629 | SEC("tc" ) |
630 | __description("direct packet access: test25 (marking on <, good access)" ) |
631 | __success __retval(0) |
632 | __naked void test25_marking_on_good_access(void) |
633 | { |
634 | asm volatile (" \ |
635 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
636 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
637 | r0 = r2; \ |
638 | r0 += 8; \ |
639 | if r0 < r3 goto l0_%=; \ |
640 | l1_%=: r0 = 0; \ |
641 | exit; \ |
642 | l0_%=: r0 = *(u8*)(r2 + 0); \ |
643 | goto l1_%=; \ |
644 | " : |
645 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
646 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
647 | : __clobber_all); |
648 | } |
649 | |
650 | SEC("tc" ) |
651 | __description("direct packet access: test26 (marking on <, bad access)" ) |
652 | __failure __msg("invalid access to packet" ) |
653 | __naked void test26_marking_on_bad_access(void) |
654 | { |
655 | asm volatile (" \ |
656 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
657 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
658 | r0 = r2; \ |
659 | r0 += 8; \ |
660 | if r0 < r3 goto l0_%=; \ |
661 | r0 = *(u8*)(r2 + 0); \ |
662 | l1_%=: r0 = 0; \ |
663 | exit; \ |
664 | l0_%=: goto l1_%=; \ |
665 | " : |
666 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
667 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
668 | : __clobber_all); |
669 | } |
670 | |
671 | SEC("tc" ) |
672 | __description("direct packet access: test27 (marking on <=, good access)" ) |
673 | __success __retval(1) |
674 | __naked void test27_marking_on_good_access(void) |
675 | { |
676 | asm volatile (" \ |
677 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
678 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
679 | r0 = r2; \ |
680 | r0 += 8; \ |
681 | if r3 <= r0 goto l0_%=; \ |
682 | r0 = *(u8*)(r2 + 0); \ |
683 | l0_%=: r0 = 1; \ |
684 | exit; \ |
685 | " : |
686 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
687 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
688 | : __clobber_all); |
689 | } |
690 | |
691 | SEC("tc" ) |
692 | __description("direct packet access: test28 (marking on <=, bad access)" ) |
693 | __failure __msg("invalid access to packet" ) |
694 | __naked void test28_marking_on_bad_access(void) |
695 | { |
696 | asm volatile (" \ |
697 | r2 = *(u32*)(r1 + %[__sk_buff_data]); \ |
698 | r3 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
699 | r0 = r2; \ |
700 | r0 += 8; \ |
701 | if r3 <= r0 goto l0_%=; \ |
702 | l1_%=: r0 = 1; \ |
703 | exit; \ |
704 | l0_%=: r0 = *(u8*)(r2 + 0); \ |
705 | goto l1_%=; \ |
706 | " : |
707 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
708 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
709 | : __clobber_all); |
710 | } |
711 | |
712 | SEC("tc" ) |
713 | __description("direct packet access: test29 (reg > pkt_end in subprog)" ) |
714 | __success __retval(0) |
715 | __naked void reg_pkt_end_in_subprog(void) |
716 | { |
717 | asm volatile (" \ |
718 | r6 = *(u32*)(r1 + %[__sk_buff_data]); \ |
719 | r2 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
720 | r3 = r6; \ |
721 | r3 += 8; \ |
722 | call reg_pkt_end_in_subprog__1; \ |
723 | if r0 == 0 goto l0_%=; \ |
724 | r0 = *(u8*)(r6 + 0); \ |
725 | l0_%=: r0 = 0; \ |
726 | exit; \ |
727 | " : |
728 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
729 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
730 | : __clobber_all); |
731 | } |
732 | |
733 | static __naked __noinline __attribute__((used)) |
734 | void reg_pkt_end_in_subprog__1(void) |
735 | { |
736 | asm volatile (" \ |
737 | r0 = 0; \ |
738 | if r3 > r2 goto l0_%=; \ |
739 | r0 = 1; \ |
740 | l0_%=: exit; \ |
741 | " ::: __clobber_all); |
742 | } |
743 | |
744 | SEC("tc" ) |
745 | __description("direct packet access: test30 (check_id() in regsafe(), bad access)" ) |
746 | __failure __msg("invalid access to packet, off=0 size=1, R2" ) |
747 | __flag(BPF_F_TEST_STATE_FREQ) |
748 | __naked void id_in_regsafe_bad_access(void) |
749 | { |
750 | asm volatile (" \ |
751 | /* r9 = ctx */ \ |
752 | r9 = r1; \ |
753 | /* r7 = ktime_get_ns() */ \ |
754 | call %[bpf_ktime_get_ns]; \ |
755 | r7 = r0; \ |
756 | /* r6 = ktime_get_ns() */ \ |
757 | call %[bpf_ktime_get_ns]; \ |
758 | r6 = r0; \ |
759 | /* r2 = ctx->data \ |
760 | * r3 = ctx->data \ |
761 | * r4 = ctx->data_end \ |
762 | */ \ |
763 | r2 = *(u32*)(r9 + %[__sk_buff_data]); \ |
764 | r3 = *(u32*)(r9 + %[__sk_buff_data]); \ |
765 | r4 = *(u32*)(r9 + %[__sk_buff_data_end]); \ |
766 | /* if r6 > 100 goto exit \ |
767 | * if r7 > 100 goto exit \ |
768 | */ \ |
769 | if r6 > 100 goto l0_%=; \ |
770 | if r7 > 100 goto l0_%=; \ |
771 | /* r2 += r6 ; this forces assignment of ID to r2\ |
772 | * r2 += 1 ; get some fixed off for r2\ |
773 | * r3 += r7 ; this forces assignment of ID to r3\ |
774 | * r3 += 1 ; get some fixed off for r3\ |
775 | */ \ |
776 | r2 += r6; \ |
777 | r2 += 1; \ |
778 | r3 += r7; \ |
779 | r3 += 1; \ |
780 | /* if r6 > r7 goto +1 ; no new information about the state is derived from\ |
781 | * ; this check, thus produced verifier states differ\ |
782 | * ; only in 'insn_idx' \ |
783 | * r2 = r3 ; optionally share ID between r2 and r3\ |
784 | */ \ |
785 | if r6 != r7 goto l1_%=; \ |
786 | r2 = r3; \ |
787 | l1_%=: /* if r3 > ctx->data_end goto exit */ \ |
788 | if r3 > r4 goto l0_%=; \ |
789 | /* r5 = *(u8 *) (r2 - 1) ; access packet memory using r2,\ |
790 | * ; this is not always safe\ |
791 | */ \ |
792 | r5 = *(u8*)(r2 - 1); \ |
793 | l0_%=: /* exit(0) */ \ |
794 | r0 = 0; \ |
795 | exit; \ |
796 | " : |
797 | : __imm(bpf_ktime_get_ns), |
798 | __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
799 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
800 | : __clobber_all); |
801 | } |
802 | |
803 | char _license[] SEC("license" ) = "GPL" ; |
804 | |