1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include "vmlinux.h" |
4 | |
5 | #include "bpf_misc.h" |
6 | |
7 | #include <bpf/bpf_endian.h> |
8 | #include <bpf/bpf_tracing.h> |
9 | #include <bpf/bpf_helpers.h> |
10 | |
11 | SEC("netfilter" ) |
12 | __description("netfilter invalid context access, size too short" ) |
13 | __failure __msg("invalid bpf_context access" ) |
14 | __naked void with_invalid_ctx_access_test1(void) |
15 | { |
16 | asm volatile (" \ |
17 | r2 = *(u8*)(r1 + %[__bpf_nf_ctx_state]); \ |
18 | r0 = 0; \ |
19 | exit; \ |
20 | " : |
21 | : __imm_const(__bpf_nf_ctx_state, offsetof(struct bpf_nf_ctx, state)) |
22 | : __clobber_all); |
23 | } |
24 | |
25 | SEC("netfilter" ) |
26 | __description("netfilter invalid context access, size too short" ) |
27 | __failure __msg("invalid bpf_context access" ) |
28 | __naked void with_invalid_ctx_access_test2(void) |
29 | { |
30 | asm volatile (" \ |
31 | r2 = *(u16*)(r1 + %[__bpf_nf_ctx_skb]); \ |
32 | r0 = 0; \ |
33 | exit; \ |
34 | " : |
35 | : __imm_const(__bpf_nf_ctx_skb, offsetof(struct bpf_nf_ctx, skb)) |
36 | : __clobber_all); |
37 | } |
38 | |
39 | SEC("netfilter" ) |
40 | __description("netfilter invalid context access, past end of ctx" ) |
41 | __failure __msg("invalid bpf_context access" ) |
42 | __naked void with_invalid_ctx_access_test3(void) |
43 | { |
44 | asm volatile (" \ |
45 | r2 = *(u64*)(r1 + %[__bpf_nf_ctx_size]); \ |
46 | r0 = 0; \ |
47 | exit; \ |
48 | " : |
49 | : __imm_const(__bpf_nf_ctx_size, sizeof(struct bpf_nf_ctx)) |
50 | : __clobber_all); |
51 | } |
52 | |
53 | SEC("netfilter" ) |
54 | __description("netfilter invalid context, write" ) |
55 | __failure __msg("invalid bpf_context access" ) |
56 | __naked void with_invalid_ctx_access_test4(void) |
57 | { |
58 | asm volatile (" \ |
59 | r2 = r1; \ |
60 | *(u64*)(r2 + 0) = r1; \ |
61 | r0 = 1; \ |
62 | exit; \ |
63 | " : |
64 | : __imm_const(__bpf_nf_ctx_skb, offsetof(struct bpf_nf_ctx, skb)) |
65 | : __clobber_all); |
66 | } |
67 | |
68 | #define NF_DROP 0 |
69 | #define NF_ACCEPT 1 |
70 | |
71 | SEC("netfilter" ) |
72 | __description("netfilter valid context read and invalid write" ) |
73 | __failure __msg("only read is supported" ) |
74 | int with_invalid_ctx_access_test5(struct bpf_nf_ctx *ctx) |
75 | { |
76 | struct nf_hook_state *state = (void *)ctx->state; |
77 | |
78 | state->sk = NULL; |
79 | return NF_ACCEPT; |
80 | } |
81 | |
82 | extern int bpf_dynptr_from_skb(struct sk_buff *skb, __u64 flags, |
83 | struct bpf_dynptr *ptr__uninit) __ksym; |
84 | extern void *bpf_dynptr_slice(const struct bpf_dynptr *ptr, uint32_t offset, |
85 | void *buffer, uint32_t buffer__sz) __ksym; |
86 | |
87 | SEC("netfilter" ) |
88 | __description("netfilter test prog with skb and state read access" ) |
89 | __success __failure_unpriv |
90 | __retval(0) |
91 | int with_valid_ctx_access_test6(struct bpf_nf_ctx *ctx) |
92 | { |
93 | const struct nf_hook_state *state = ctx->state; |
94 | struct sk_buff *skb = ctx->skb; |
95 | const struct iphdr *iph; |
96 | const struct tcphdr *th; |
97 | u8 buffer_iph[20] = {}; |
98 | u8 buffer_th[40] = {}; |
99 | struct bpf_dynptr ptr; |
100 | uint8_t ihl; |
101 | |
102 | if (skb->len <= 20 || bpf_dynptr_from_skb(skb, 0, &ptr)) |
103 | return NF_ACCEPT; |
104 | |
105 | iph = bpf_dynptr_slice(&ptr, 0, buffer_iph, sizeof(buffer_iph)); |
106 | if (!iph) |
107 | return NF_ACCEPT; |
108 | |
109 | if (state->pf != 2) |
110 | return NF_ACCEPT; |
111 | |
112 | ihl = iph->ihl << 2; |
113 | |
114 | th = bpf_dynptr_slice(&ptr, ihl, buffer_th, sizeof(buffer_th)); |
115 | if (!th) |
116 | return NF_ACCEPT; |
117 | |
118 | return th->dest == bpf_htons(22) ? NF_ACCEPT : NF_DROP; |
119 | } |
120 | |
121 | char _license[] SEC("license" ) = "GPL" ; |
122 | |