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
11SEC("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
25SEC("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
39SEC("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
53SEC("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
71SEC("netfilter")
72__description("netfilter valid context read and invalid write")
73__failure __msg("only read is supported")
74int 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
82extern int bpf_dynptr_from_skb(struct sk_buff *skb, __u64 flags,
83 struct bpf_dynptr *ptr__uninit) __ksym;
84extern void *bpf_dynptr_slice(const struct bpf_dynptr *ptr, uint32_t offset,
85 void *buffer, uint32_t buffer__sz) __ksym;
86
87SEC("netfilter")
88__description("netfilter test prog with skb and state read access")
89__success __failure_unpriv
90__retval(0)
91int 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
121char _license[] SEC("license") = "GPL";
122

source code of linux/tools/testing/selftests/bpf/progs/verifier_netfilter_ctx.c