1// SPDX-License-Identifier: GPL-2.0 2/* 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 long 30bad_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 should 41 * 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 long 53bad_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 should 64 * 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 long 76write_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 should 84 * 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 long 96null_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 should 104 * 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 long 116null_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 should 126 * 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 long 138try_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 should 146 * 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 long 158try_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 should 166 * 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 long 178invalid_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 should 184 * 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 long 196try_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 long 203try_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