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