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 8 char _license[] SEC("license") = "GPL"; 9 10 struct sample { 11 int pid; 12 int seq; 13 long value; 14 char comm[16]; 15 }; 16 17 struct { 18 __uint(type, BPF_MAP_TYPE_USER_RINGBUF); 19 } user_ringbuf SEC(".maps"); 20 21 struct { 22 __uint(type, BPF_MAP_TYPE_RINGBUF); 23 __uint(max_entries, 2); 24 } ringbuf SEC(".maps"); 25 26 static int map_value; 27 28 static long 29 bad_access1(struct bpf_dynptr *dynptr, void *context) 30 { 31 const struct sample *sample; 32 33 sample = bpf_dynptr_data(dynptr - 1, 0, sizeof(*sample)); 34 bpf_printk("Was able to pass bad pointer %lx\n", (__u64)dynptr - 1); 35 36 return 0; 37 } 38 39 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should 40 * not be able to read before the pointer. 41 */ 42 SEC("?raw_tp/") 43 int user_ringbuf_callback_bad_access1(void *ctx) 44 { 45 bpf_user_ringbuf_drain(&user_ringbuf, bad_access1, NULL, 0); 46 47 return 0; 48 } 49 50 static long 51 bad_access2(struct bpf_dynptr *dynptr, void *context) 52 { 53 const struct sample *sample; 54 55 sample = bpf_dynptr_data(dynptr + 1, 0, sizeof(*sample)); 56 bpf_printk("Was able to pass bad pointer %lx\n", (__u64)dynptr + 1); 57 58 return 0; 59 } 60 61 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should 62 * not be able to read past the end of the pointer. 63 */ 64 SEC("?raw_tp/") 65 int user_ringbuf_callback_bad_access2(void *ctx) 66 { 67 bpf_user_ringbuf_drain(&user_ringbuf, bad_access2, NULL, 0); 68 69 return 0; 70 } 71 72 static long 73 write_forbidden(struct bpf_dynptr *dynptr, void *context) 74 { 75 *((long *)dynptr) = 0; 76 77 return 0; 78 } 79 80 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should 81 * not be able to write to that pointer. 82 */ 83 SEC("?raw_tp/") 84 int user_ringbuf_callback_write_forbidden(void *ctx) 85 { 86 bpf_user_ringbuf_drain(&user_ringbuf, write_forbidden, NULL, 0); 87 88 return 0; 89 } 90 91 static long 92 null_context_write(struct bpf_dynptr *dynptr, void *context) 93 { 94 *((__u64 *)context) = 0; 95 96 return 0; 97 } 98 99 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should 100 * not be able to write to that pointer. 101 */ 102 SEC("?raw_tp/") 103 int user_ringbuf_callback_null_context_write(void *ctx) 104 { 105 bpf_user_ringbuf_drain(&user_ringbuf, null_context_write, NULL, 0); 106 107 return 0; 108 } 109 110 static long 111 null_context_read(struct bpf_dynptr *dynptr, void *context) 112 { 113 __u64 id = *((__u64 *)context); 114 115 bpf_printk("Read id %lu\n", id); 116 117 return 0; 118 } 119 120 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should 121 * not be able to write to that pointer. 122 */ 123 SEC("?raw_tp/") 124 int user_ringbuf_callback_null_context_read(void *ctx) 125 { 126 bpf_user_ringbuf_drain(&user_ringbuf, null_context_read, NULL, 0); 127 128 return 0; 129 } 130 131 static long 132 try_discard_dynptr(struct bpf_dynptr *dynptr, void *context) 133 { 134 bpf_ringbuf_discard_dynptr(dynptr, 0); 135 136 return 0; 137 } 138 139 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should 140 * not be able to read past the end of the pointer. 141 */ 142 SEC("?raw_tp/") 143 int user_ringbuf_callback_discard_dynptr(void *ctx) 144 { 145 bpf_user_ringbuf_drain(&user_ringbuf, try_discard_dynptr, NULL, 0); 146 147 return 0; 148 } 149 150 static long 151 try_submit_dynptr(struct bpf_dynptr *dynptr, void *context) 152 { 153 bpf_ringbuf_submit_dynptr(dynptr, 0); 154 155 return 0; 156 } 157 158 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should 159 * not be able to read past the end of the pointer. 160 */ 161 SEC("?raw_tp/") 162 int user_ringbuf_callback_submit_dynptr(void *ctx) 163 { 164 bpf_user_ringbuf_drain(&user_ringbuf, try_submit_dynptr, NULL, 0); 165 166 return 0; 167 } 168 169 static long 170 invalid_drain_callback_return(struct bpf_dynptr *dynptr, void *context) 171 { 172 return 2; 173 } 174 175 /* A callback that accesses a dynptr in a bpf_user_ringbuf_drain callback should 176 * not be able to write to that pointer. 177 */ 178 SEC("?raw_tp/") 179 int user_ringbuf_callback_invalid_return(void *ctx) 180 { 181 bpf_user_ringbuf_drain(&user_ringbuf, invalid_drain_callback_return, NULL, 0); 182 183 return 0; 184 } 185 186 static long 187 try_reinit_dynptr_mem(struct bpf_dynptr *dynptr, void *context) 188 { 189 bpf_dynptr_from_mem(&map_value, 4, 0, dynptr); 190 return 0; 191 } 192 193 static long 194 try_reinit_dynptr_ringbuf(struct bpf_dynptr *dynptr, void *context) 195 { 196 bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, dynptr); 197 return 0; 198 } 199 200 SEC("?raw_tp/") 201 int user_ringbuf_callback_reinit_dynptr_mem(void *ctx) 202 { 203 bpf_user_ringbuf_drain(&user_ringbuf, try_reinit_dynptr_mem, NULL, 0); 204 return 0; 205 } 206 207 SEC("?raw_tp/") 208 int user_ringbuf_callback_reinit_dynptr_ringbuf(void *ctx) 209 { 210 bpf_user_ringbuf_drain(&user_ringbuf, try_reinit_dynptr_ringbuf, NULL, 0); 211 return 0; 212 } 213