246 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */3 4#include <linux/bpf.h>5#include <bpf/bpf_helpers.h>6#include "bpf_misc.h"7 8char _license[] SEC("license") = "GPL";9 10struct sample {11 int pid;12 int seq;13 long value;14 char comm[16];15};16 17struct {18 __uint(type, BPF_MAP_TYPE_USER_RINGBUF);19 __uint(max_entries, 4096);20} user_ringbuf SEC(".maps");21 22struct {23 __uint(type, BPF_MAP_TYPE_RINGBUF);24 __uint(max_entries, 2);25} ringbuf SEC(".maps");26 27static int map_value;28 29static long30bad_access1(struct bpf_dynptr *dynptr, void *context)31{32 const struct sample *sample;33 34 sample = bpf_dynptr_data(dynptr - 1, 0, sizeof(*sample));35 bpf_printk("Was able to pass bad pointer %lx\n", (__u64)dynptr - 1);36 37 return 0;38}39 40/* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should41 * not be able to read before the pointer.42 */43SEC("?raw_tp")44__failure __msg("negative offset dynptr_ptr ptr")45int user_ringbuf_callback_bad_access1(void *ctx)46{47 bpf_user_ringbuf_drain(&user_ringbuf, bad_access1, NULL, 0);48 49 return 0;50}51 52static long53bad_access2(struct bpf_dynptr *dynptr, void *context)54{55 const struct sample *sample;56 57 sample = bpf_dynptr_data(dynptr + 1, 0, sizeof(*sample));58 bpf_printk("Was able to pass bad pointer %lx\n", (__u64)dynptr + 1);59 60 return 0;61}62 63/* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should64 * not be able to read past the end of the pointer.65 */66SEC("?raw_tp")67__failure __msg("dereference of modified dynptr_ptr ptr")68int user_ringbuf_callback_bad_access2(void *ctx)69{70 bpf_user_ringbuf_drain(&user_ringbuf, bad_access2, NULL, 0);71 72 return 0;73}74 75static long76write_forbidden(struct bpf_dynptr *dynptr, void *context)77{78 *((long *)dynptr) = 0;79 80 return 0;81}82 83/* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should84 * not be able to write to that pointer.85 */86SEC("?raw_tp")87__failure __msg("invalid mem access 'dynptr_ptr'")88int user_ringbuf_callback_write_forbidden(void *ctx)89{90 bpf_user_ringbuf_drain(&user_ringbuf, write_forbidden, NULL, 0);91 92 return 0;93}94 95static long96null_context_write(struct bpf_dynptr *dynptr, void *context)97{98 *((__u64 *)context) = 0;99 100 return 0;101}102 103/* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should104 * not be able to write to that pointer.105 */106SEC("?raw_tp")107__failure __msg("invalid mem access 'scalar'")108int user_ringbuf_callback_null_context_write(void *ctx)109{110 bpf_user_ringbuf_drain(&user_ringbuf, null_context_write, NULL, 0);111 112 return 0;113}114 115static long116null_context_read(struct bpf_dynptr *dynptr, void *context)117{118 __u64 id = *((__u64 *)context);119 120 bpf_printk("Read id %lu\n", id);121 122 return 0;123}124 125/* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should126 * not be able to write to that pointer.127 */128SEC("?raw_tp")129__failure __msg("invalid mem access 'scalar'")130int user_ringbuf_callback_null_context_read(void *ctx)131{132 bpf_user_ringbuf_drain(&user_ringbuf, null_context_read, NULL, 0);133 134 return 0;135}136 137static long138try_discard_dynptr(struct bpf_dynptr *dynptr, void *context)139{140 bpf_ringbuf_discard_dynptr(dynptr, 0);141 142 return 0;143}144 145/* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should146 * not be able to read past the end of the pointer.147 */148SEC("?raw_tp")149__failure __msg("cannot release unowned const bpf_dynptr")150int user_ringbuf_callback_discard_dynptr(void *ctx)151{152 bpf_user_ringbuf_drain(&user_ringbuf, try_discard_dynptr, NULL, 0);153 154 return 0;155}156 157static long158try_submit_dynptr(struct bpf_dynptr *dynptr, void *context)159{160 bpf_ringbuf_submit_dynptr(dynptr, 0);161 162 return 0;163}164 165/* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should166 * not be able to read past the end of the pointer.167 */168SEC("?raw_tp")169__failure __msg("cannot release unowned const bpf_dynptr")170int user_ringbuf_callback_submit_dynptr(void *ctx)171{172 bpf_user_ringbuf_drain(&user_ringbuf, try_submit_dynptr, NULL, 0);173 174 return 0;175}176 177static long178invalid_drain_callback_return(struct bpf_dynptr *dynptr, void *context)179{180 return 2;181}182 183/* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should184 * not be able to write to that pointer.185 */186SEC("?raw_tp")187__failure __msg("At callback return the register R0 has ")188int user_ringbuf_callback_invalid_return(void *ctx)189{190 bpf_user_ringbuf_drain(&user_ringbuf, invalid_drain_callback_return, NULL, 0);191 192 return 0;193}194 195static long196try_reinit_dynptr_mem(struct bpf_dynptr *dynptr, void *context)197{198 bpf_dynptr_from_mem(&map_value, 4, 0, dynptr);199 return 0;200}201 202static long203try_reinit_dynptr_ringbuf(struct bpf_dynptr *dynptr, void *context)204{205 bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, dynptr);206 return 0;207}208 209SEC("?raw_tp")210__failure __msg("Dynptr has to be an uninitialized dynptr")211int user_ringbuf_callback_reinit_dynptr_mem(void *ctx)212{213 bpf_user_ringbuf_drain(&user_ringbuf, try_reinit_dynptr_mem, NULL, 0);214 return 0;215}216 217SEC("?raw_tp")218__failure __msg("Dynptr has to be an uninitialized dynptr")219int user_ringbuf_callback_reinit_dynptr_ringbuf(void *ctx)220{221 bpf_user_ringbuf_drain(&user_ringbuf, try_reinit_dynptr_ringbuf, NULL, 0);222 return 0;223}224 225__noinline long global_call_bpf_dynptr_data(struct bpf_dynptr *dynptr)226{227 bpf_dynptr_data(dynptr, 0xA, 0xA);228 return 0;229}230 231static long callback_adjust_bpf_dynptr_reg_off(struct bpf_dynptr *dynptr,232 void *ctx)233{234 global_call_bpf_dynptr_data(dynptr += 1024);235 return 0;236}237 238SEC("?raw_tp")239__failure __msg("dereference of modified dynptr_ptr ptr R1 off=16384 disallowed")240int user_ringbuf_callback_const_ptr_to_dynptr_reg_off(void *ctx)241{242 bpf_user_ringbuf_drain(&user_ringbuf,243 callback_adjust_bpf_dynptr_reg_off, NULL, 0);244 return 0;245}246