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 __uint(max_entries, 4096); 20 } user_ringbuf SEC(".maps"); 21 22 struct { 23 __uint(type, BPF_MAP_TYPE_RINGBUF); 24 __uint(max_entries, 2); 25 } ringbuf SEC(".maps"); 26 27 static int map_value; 28 29 static long 30 bad_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 */ 43 SEC("?raw_tp") 44 __failure __msg("negative offset dynptr_ptr ptr") 45 int 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 52 static long 53 bad_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 */ 66 SEC("?raw_tp") 67 __failure __msg("dereference of modified dynptr_ptr ptr") 68 int 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 75 static long 76 write_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 */ 86 SEC("?raw_tp") 87 __failure __msg("invalid mem access 'dynptr_ptr'") 88 int 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 95 static long 96 null_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 */ 106 SEC("?raw_tp") 107 __failure __msg("invalid mem access 'scalar'") 108 int 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 115 static long 116 null_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 */ 128 SEC("?raw_tp") 129 __failure __msg("invalid mem access 'scalar'") 130 int 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 137 static long 138 try_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 */ 148 SEC("?raw_tp") 149 __failure __msg("cannot release unowned const bpf_dynptr") 150 int 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 157 static long 158 try_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 */ 168 SEC("?raw_tp") 169 __failure __msg("cannot release unowned const bpf_dynptr") 170 int 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 177 static long 178 invalid_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 */ 186 SEC("?raw_tp") 187 __failure __msg("At callback return the register R0 has value") 188 int 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 195 static long 196 try_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 202 static long 203 try_reinit_dynptr_ringbuf(struct bpf_dynptr *dynptr, void *context) 204 { 205 bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, dynptr); 206 return 0; 207 } 208 209 SEC("?raw_tp") 210 __failure __msg("Dynptr has to be an uninitialized dynptr") 211 int 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 217 SEC("?raw_tp") 218 __failure __msg("Dynptr has to be an uninitialized dynptr") 219 int 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