1 // SPDX-License-Identifier: GPL-2.0
2 /* Converted from tools/testing/selftests/bpf/verifier/unpriv.c */
5 #include <bpf/bpf_helpers.h>
6 #include "../../../include/linux/filter.h"
9 #define BPF_SK_LOOKUP(func) \
10 /* struct bpf_sock_tuple tuple = {} */ \
12 "*(u32*)(r10 - 8) = r2;" \
13 "*(u64*)(r10 - 16) = r2;" \
14 "*(u64*)(r10 - 24) = r2;" \
15 "*(u64*)(r10 - 32) = r2;" \
16 "*(u64*)(r10 - 40) = r2;" \
17 "*(u64*)(r10 - 48) = r2;" \
18 /* sk = func(ctx, &tuple, sizeof tuple, 0, 0) */ \
21 "r3 = %[sizeof_bpf_sock_tuple];"\
27 __uint(type, BPF_MAP_TYPE_HASH);
28 __uint(max_entries, 1);
29 __type(key, long long);
30 __type(value, long long);
31 } map_hash_8b SEC(".maps");
33 void dummy_prog_42_socket(void);
34 void dummy_prog_24_socket(void);
35 void dummy_prog_loop1_socket(void);
38 __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
39 __uint(max_entries, 4);
40 __uint(key_size, sizeof(int));
41 __array(values, void (void));
42 } map_prog1_socket SEC(".maps") = {
44 [0] = (void *)&dummy_prog_42_socket,
45 [1] = (void *)&dummy_prog_loop1_socket,
46 [2] = (void *)&dummy_prog_24_socket,
51 __auxiliary __auxiliary_unpriv
52 __naked void dummy_prog_42_socket(void)
54 asm volatile ("r0 = 42; exit;");
58 __auxiliary __auxiliary_unpriv
59 __naked void dummy_prog_24_socket(void)
61 asm volatile ("r0 = 24; exit;");
65 __auxiliary __auxiliary_unpriv
66 __naked void dummy_prog_loop1_socket(void)
70 r2 = %[map_prog1_socket] ll; \
71 call %[bpf_tail_call]; \
75 : __imm(bpf_tail_call),
76 __imm_addr(map_prog1_socket)
81 __description("unpriv: return pointer")
82 __success __failure_unpriv __msg_unpriv("R0 leaks addr")
83 __retval(POINTER_VALUE)
84 __naked void unpriv_return_pointer(void)
93 __description("unpriv: add const to pointer")
94 __success __success_unpriv __retval(0)
95 __naked void unpriv_add_const_to_pointer(void)
101 " ::: __clobber_all);
105 __description("unpriv: add pointer to pointer")
106 __failure __msg("R1 pointer += pointer")
108 __naked void unpriv_add_pointer_to_pointer(void)
114 " ::: __clobber_all);
118 __description("unpriv: neg pointer")
119 __success __failure_unpriv __msg_unpriv("R1 pointer arithmetic")
121 __naked void unpriv_neg_pointer(void)
127 " ::: __clobber_all);
131 __description("unpriv: cmp pointer with const")
132 __success __failure_unpriv __msg_unpriv("R1 pointer comparison")
134 __naked void unpriv_cmp_pointer_with_const(void)
137 if r1 == 0 goto l0_%=; \
140 " ::: __clobber_all);
144 __description("unpriv: cmp pointer with pointer")
145 __success __failure_unpriv __msg_unpriv("R10 pointer comparison")
147 __naked void unpriv_cmp_pointer_with_pointer(void)
150 if r1 == r10 goto l0_%=; \
153 " ::: __clobber_all);
157 __description("unpriv: check that printk is disallowed")
159 __naked void check_that_printk_is_disallowed(void)
163 *(u64*)(r10 - 8) = r1; \
168 call %[bpf_trace_printk]; \
172 : __imm(bpf_trace_printk)
177 __description("unpriv: pass pointer to helper function")
178 __success __failure_unpriv __msg_unpriv("R4 leaks addr")
180 __naked void pass_pointer_to_helper_function(void)
184 *(u64*)(r10 - 8) = r1; \
187 r1 = %[map_hash_8b] ll; \
190 call %[bpf_map_update_elem]; \
194 : __imm(bpf_map_update_elem),
195 __imm_addr(map_hash_8b)
200 __description("unpriv: indirectly pass pointer on stack to helper function")
201 __success __failure_unpriv
202 __msg_unpriv("invalid indirect read from stack R2 off -8+0 size 8")
204 __naked void on_stack_to_helper_function(void)
207 *(u64*)(r10 - 8) = r10; \
210 r1 = %[map_hash_8b] ll; \
211 call %[bpf_map_lookup_elem]; \
215 : __imm(bpf_map_lookup_elem),
216 __imm_addr(map_hash_8b)
221 __description("unpriv: mangle pointer on stack 1")
222 __success __failure_unpriv __msg_unpriv("attempt to corrupt spilled")
224 __naked void mangle_pointer_on_stack_1(void)
227 *(u64*)(r10 - 8) = r10; \
229 *(u32*)(r10 - 8) = r0; \
232 " ::: __clobber_all);
236 __description("unpriv: mangle pointer on stack 2")
237 __success __failure_unpriv __msg_unpriv("attempt to corrupt spilled")
239 __naked void mangle_pointer_on_stack_2(void)
242 *(u64*)(r10 - 8) = r10; \
244 *(u8*)(r10 - 1) = r0; \
247 " ::: __clobber_all);
251 __description("unpriv: read pointer from stack in small chunks")
252 __failure __msg("invalid size")
254 __naked void from_stack_in_small_chunks(void)
257 *(u64*)(r10 - 8) = r10; \
258 r0 = *(u32*)(r10 - 8); \
261 " ::: __clobber_all);
265 __description("unpriv: write pointer into ctx")
266 __failure __msg("invalid bpf_context access")
267 __failure_unpriv __msg_unpriv("R1 leaks addr")
268 __naked void unpriv_write_pointer_into_ctx(void)
271 *(u64*)(r1 + 0) = r1; \
274 " ::: __clobber_all);
278 __description("unpriv: spill/fill of ctx")
279 __success __success_unpriv __retval(0)
280 __naked void unpriv_spill_fill_of_ctx(void)
285 *(u64*)(r6 + 0) = r1; \
286 r1 = *(u64*)(r6 + 0); \
289 " ::: __clobber_all);
293 __description("unpriv: spill/fill of ctx 2")
294 __success __retval(0)
295 __naked void spill_fill_of_ctx_2(void)
300 *(u64*)(r6 + 0) = r1; \
301 r1 = *(u64*)(r6 + 0); \
302 call %[bpf_get_hash_recalc]; \
306 : __imm(bpf_get_hash_recalc)
311 __description("unpriv: spill/fill of ctx 3")
312 __failure __msg("R1 type=fp expected=ctx")
313 __naked void spill_fill_of_ctx_3(void)
318 *(u64*)(r6 + 0) = r1; \
319 *(u64*)(r6 + 0) = r10; \
320 r1 = *(u64*)(r6 + 0); \
321 call %[bpf_get_hash_recalc]; \
324 : __imm(bpf_get_hash_recalc)
329 __description("unpriv: spill/fill of ctx 4")
330 __failure __msg("R1 type=scalar expected=ctx")
331 __naked void spill_fill_of_ctx_4(void)
336 *(u64*)(r6 + 0) = r1; \
338 lock *(u64 *)(r10 - 8) += r0; \
339 r1 = *(u64*)(r6 + 0); \
340 call %[bpf_get_hash_recalc]; \
343 : __imm(bpf_get_hash_recalc)
348 __description("unpriv: spill/fill of different pointers stx")
349 __failure __msg("same insn cannot be used with different pointers")
350 __naked void fill_of_different_pointers_stx(void)
356 if r1 == 0 goto l0_%=; \
359 *(u64*)(r6 + 0) = r2; \
360 l0_%=: if r1 != 0 goto l1_%=; \
361 *(u64*)(r6 + 0) = r1; \
362 l1_%=: r1 = *(u64*)(r6 + 0); \
363 *(u32*)(r1 + %[__sk_buff_mark]) = r3; \
367 : __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
371 /* Same as above, but use BPF_ST_MEM to save 42
372 * instead of BPF_STX_MEM.
375 __description("unpriv: spill/fill of different pointers st")
376 __failure __msg("same insn cannot be used with different pointers")
377 __naked void fill_of_different_pointers_st(void)
382 if r1 == 0 goto l0_%=; \
385 *(u64*)(r6 + 0) = r2; \
386 l0_%=: if r1 != 0 goto l1_%=; \
387 *(u64*)(r6 + 0) = r1; \
388 l1_%=: r1 = *(u64*)(r6 + 0); \
393 : __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)),
395 BPF_ST_MEM(BPF_W, BPF_REG_1, offsetof(struct __sk_buff, mark), 42))
400 __description("unpriv: spill/fill of different pointers stx - ctx and sock")
401 __failure __msg("type=ctx expected=sock")
402 __naked void pointers_stx_ctx_and_sock(void)
406 /* struct bpf_sock *sock = bpf_sock_lookup(...); */\
407 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
410 /* void *target = &foo; */ \
414 /* if (skb == NULL) *target = sock; */ \
415 if r1 == 0 goto l0_%=; \
416 *(u64*)(r6 + 0) = r2; \
417 l0_%=: /* else *target = skb; */ \
418 if r1 != 0 goto l1_%=; \
419 *(u64*)(r6 + 0) = r1; \
420 l1_%=: /* struct __sk_buff *skb = *target; */ \
421 r1 = *(u64*)(r6 + 0); \
422 /* skb->mark = 42; */ \
424 *(u32*)(r1 + %[__sk_buff_mark]) = r3; \
425 /* if (sk) bpf_sk_release(sk) */ \
426 if r1 == 0 goto l2_%=; \
427 call %[bpf_sk_release]; \
431 : __imm(bpf_sk_lookup_tcp),
432 __imm(bpf_sk_release),
433 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)),
434 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
439 __description("unpriv: spill/fill of different pointers stx - leak sock")
441 //.errstr = "same insn cannot be used with different pointers",
442 __msg("Unreleased reference")
443 __naked void different_pointers_stx_leak_sock(void)
447 /* struct bpf_sock *sock = bpf_sock_lookup(...); */\
448 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
451 /* void *target = &foo; */ \
455 /* if (skb == NULL) *target = sock; */ \
456 if r1 == 0 goto l0_%=; \
457 *(u64*)(r6 + 0) = r2; \
458 l0_%=: /* else *target = skb; */ \
459 if r1 != 0 goto l1_%=; \
460 *(u64*)(r6 + 0) = r1; \
461 l1_%=: /* struct __sk_buff *skb = *target; */ \
462 r1 = *(u64*)(r6 + 0); \
463 /* skb->mark = 42; */ \
465 *(u32*)(r1 + %[__sk_buff_mark]) = r3; \
468 : __imm(bpf_sk_lookup_tcp),
469 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)),
470 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
475 __description("unpriv: spill/fill of different pointers stx - sock and ctx (read)")
476 __failure __msg("same insn cannot be used with different pointers")
477 __naked void stx_sock_and_ctx_read(void)
481 /* struct bpf_sock *sock = bpf_sock_lookup(...); */\
482 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
485 /* void *target = &foo; */ \
489 /* if (skb) *target = skb */ \
490 if r1 == 0 goto l0_%=; \
491 *(u64*)(r6 + 0) = r1; \
492 l0_%=: /* else *target = sock */ \
493 if r1 != 0 goto l1_%=; \
494 *(u64*)(r6 + 0) = r2; \
495 l1_%=: /* struct bpf_sock *sk = *target; */ \
496 r1 = *(u64*)(r6 + 0); \
497 /* if (sk) u32 foo = sk->mark; bpf_sk_release(sk); */\
498 if r1 == 0 goto l2_%=; \
499 r3 = *(u32*)(r1 + %[bpf_sock_mark]); \
500 call %[bpf_sk_release]; \
504 : __imm(bpf_sk_lookup_tcp),
505 __imm(bpf_sk_release),
506 __imm_const(bpf_sock_mark, offsetof(struct bpf_sock, mark)),
507 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
512 __description("unpriv: spill/fill of different pointers stx - sock and ctx (write)")
514 //.errstr = "same insn cannot be used with different pointers",
515 __msg("cannot write into sock")
516 __naked void stx_sock_and_ctx_write(void)
520 /* struct bpf_sock *sock = bpf_sock_lookup(...); */\
521 " BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
524 /* void *target = &foo; */ \
528 /* if (skb) *target = skb */ \
529 if r1 == 0 goto l0_%=; \
530 *(u64*)(r6 + 0) = r1; \
531 l0_%=: /* else *target = sock */ \
532 if r1 != 0 goto l1_%=; \
533 *(u64*)(r6 + 0) = r2; \
534 l1_%=: /* struct bpf_sock *sk = *target; */ \
535 r1 = *(u64*)(r6 + 0); \
536 /* if (sk) sk->mark = 42; bpf_sk_release(sk); */\
537 if r1 == 0 goto l2_%=; \
539 *(u32*)(r1 + %[bpf_sock_mark]) = r3; \
540 call %[bpf_sk_release]; \
544 : __imm(bpf_sk_lookup_tcp),
545 __imm(bpf_sk_release),
546 __imm_const(bpf_sock_mark, offsetof(struct bpf_sock, mark)),
547 __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
552 __description("unpriv: write pointer into map elem value")
553 __success __failure_unpriv __msg_unpriv("R0 leaks addr")
555 __naked void pointer_into_map_elem_value(void)
559 *(u64*)(r10 - 8) = r1; \
562 r1 = %[map_hash_8b] ll; \
563 call %[bpf_map_lookup_elem]; \
564 if r0 == 0 goto l0_%=; \
565 *(u64*)(r0 + 0) = r0; \
568 : __imm(bpf_map_lookup_elem),
569 __imm_addr(map_hash_8b)
574 __description("alu32: mov u32 const")
575 __success __failure_unpriv __msg_unpriv("R7 invalid mem access 'scalar'")
577 __naked void alu32_mov_u32_const(void)
583 if r0 == 0 goto l0_%=; \
584 r0 = *(u64*)(r7 + 0); \
586 " ::: __clobber_all);
590 __description("unpriv: partial copy of pointer")
591 __success __failure_unpriv __msg_unpriv("R10 partial copy")
593 __naked void unpriv_partial_copy_of_pointer(void)
599 " ::: __clobber_all);
603 __description("unpriv: pass pointer to tail_call")
604 __success __failure_unpriv __msg_unpriv("R3 leaks addr into helper")
606 __naked void pass_pointer_to_tail_call(void)
610 r2 = %[map_prog1_socket] ll; \
611 call %[bpf_tail_call]; \
615 : __imm(bpf_tail_call),
616 __imm_addr(map_prog1_socket)
621 __description("unpriv: cmp map pointer with zero")
622 __success __failure_unpriv __msg_unpriv("R1 pointer comparison")
624 __naked void cmp_map_pointer_with_zero(void)
628 r1 = %[map_hash_8b] ll; \
629 if r1 == 0 goto l0_%=; \
633 : __imm_addr(map_hash_8b)
638 __description("unpriv: write into frame pointer")
639 __failure __msg("frame pointer is read only")
641 __naked void unpriv_write_into_frame_pointer(void)
647 " ::: __clobber_all);
651 __description("unpriv: spill/fill frame pointer")
652 __failure __msg("frame pointer is read only")
654 __naked void unpriv_spill_fill_frame_pointer(void)
659 *(u64*)(r6 + 0) = r10; \
660 r10 = *(u64*)(r6 + 0); \
663 " ::: __clobber_all);
667 __description("unpriv: cmp of frame pointer")
668 __success __failure_unpriv __msg_unpriv("R10 pointer comparison")
670 __naked void unpriv_cmp_of_frame_pointer(void)
673 if r10 == 0 goto l0_%=; \
676 " ::: __clobber_all);
680 __description("unpriv: adding of fp, reg")
681 __success __failure_unpriv
682 __msg_unpriv("R1 stack pointer arithmetic goes out of range")
684 __naked void unpriv_adding_of_fp_reg(void)
690 *(u64*)(r1 - 8) = r0; \
692 " ::: __clobber_all);
696 __description("unpriv: adding of fp, imm")
697 __success __failure_unpriv
698 __msg_unpriv("R1 stack pointer arithmetic goes out of range")
700 __naked void unpriv_adding_of_fp_imm(void)
706 *(u64*)(r1 - 8) = r0; \
708 " ::: __clobber_all);
712 __description("unpriv: cmp of stack pointer")
713 __success __failure_unpriv __msg_unpriv("R2 pointer comparison")
715 __naked void unpriv_cmp_of_stack_pointer(void)
720 if r2 == 0 goto l0_%=; \
723 " ::: __clobber_all);
726 char _license[] SEC("license") = "GPL";