// SPDX-License-Identifier: GPL-2.0 #include "vmlinux.h" #include "bpf_misc.h" #include <bpf/bpf_endian.h> #include <bpf/bpf_tracing.h> #include <bpf/bpf_helpers.h> SEC("netfilter") __description("netfilter invalid context access, size too short") __failure __msg("invalid bpf_context access") __naked void with_invalid_ctx_access_test1(void) { asm volatile (" \ r2 = *(u8*)(r1 + %[__bpf_nf_ctx_state]); \ r0 = 0; \ exit; \ " : : __imm_const(__bpf_nf_ctx_state, offsetof(struct bpf_nf_ctx, state)) : __clobber_all); } SEC("netfilter") __description("netfilter invalid context access, size too short") __failure __msg("invalid bpf_context access") __naked void with_invalid_ctx_access_test2(void) { asm volatile (" \ r2 = *(u16*)(r1 + %[__bpf_nf_ctx_skb]); \ r0 = 0; \ exit; \ " : : __imm_const(__bpf_nf_ctx_skb, offsetof(struct bpf_nf_ctx, skb)) : __clobber_all); } SEC("netfilter") __description("netfilter invalid context access, past end of ctx") __failure __msg("invalid bpf_context access") __naked void with_invalid_ctx_access_test3(void) { asm volatile (" \ r2 = *(u64*)(r1 + %[__bpf_nf_ctx_size]); \ r0 = 0; \ exit; \ " : : __imm_const(__bpf_nf_ctx_size, sizeof(struct bpf_nf_ctx)) : __clobber_all); } SEC("netfilter") __description("netfilter invalid context, write") __failure __msg("invalid bpf_context access") __naked void with_invalid_ctx_access_test4(void) { asm volatile (" \ r2 = r1; \ *(u64*)(r2 + 0) = r1; \ r0 = 1; \ exit; \ " : : __imm_const(__bpf_nf_ctx_skb, offsetof(struct bpf_nf_ctx, skb)) : __clobber_all); } #define NF_DROP 0 #define NF_ACCEPT 1 SEC("netfilter") __description("netfilter valid context read and invalid write") __failure __msg("only read is supported") int with_invalid_ctx_access_test5(struct bpf_nf_ctx *ctx) { struct nf_hook_state *state = (void *)ctx->state; state->sk = NULL; return NF_ACCEPT; } extern int bpf_dynptr_from_skb(struct sk_buff *skb, __u64 flags, struct bpf_dynptr *ptr__uninit) __ksym; extern void *bpf_dynptr_slice(const struct bpf_dynptr *ptr, uint32_t offset, void *buffer, uint32_t buffer__sz) __ksym; SEC("netfilter") __description("netfilter test prog with skb and state read access") __success __failure_unpriv __retval(0) int with_valid_ctx_access_test6(struct bpf_nf_ctx *ctx) { const struct nf_hook_state *state = ctx->state; struct sk_buff *skb = ctx->skb; const struct iphdr *iph; const struct tcphdr *th; u8 buffer_iph[20] = {}; u8 buffer_th[40] = {}; struct bpf_dynptr ptr; uint8_t ihl; if (skb->len <= 20 || bpf_dynptr_from_skb(skb, 0, &ptr)) return NF_ACCEPT; iph = bpf_dynptr_slice(&ptr, 0, buffer_iph, sizeof(buffer_iph)); if (!iph) return NF_ACCEPT; if (state->pf != 2) return NF_ACCEPT; ihl = iph->ihl << 2; th = bpf_dynptr_slice(&ptr, ihl, buffer_th, sizeof(buffer_th)); if (!th) return NF_ACCEPT; return th->dest == bpf_htons(22) ? NF_ACCEPT : NF_DROP; } char _license[] SEC("license") = "GPL";