1 // SPDX-License-Identifier: GPL-2.0 2 #include <vmlinux.h> 3 #include <bpf/bpf_tracing.h> 4 #include <bpf/bpf_helpers.h> 5 #include <bpf/bpf_core_read.h> 6 #include "bpf_misc.h" 7 8 struct map_value { 9 char buf[8]; 10 struct prog_test_ref_kfunc __kptr *unref_ptr; 11 struct prog_test_ref_kfunc __kptr_ref *ref_ptr; 12 struct prog_test_member __kptr_ref *ref_memb_ptr; 13 }; 14 15 struct array_map { 16 __uint(type, BPF_MAP_TYPE_ARRAY); 17 __type(key, int); 18 __type(value, struct map_value); 19 __uint(max_entries, 1); 20 } array_map SEC(".maps"); 21 22 extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; 23 extern struct prog_test_ref_kfunc * 24 bpf_kfunc_call_test_kptr_get(struct prog_test_ref_kfunc **p, int a, int b) __ksym; 25 26 SEC("?tc") 27 __failure __msg("kptr access size must be BPF_DW") 28 int size_not_bpf_dw(struct __sk_buff *ctx) 29 { 30 struct map_value *v; 31 int key = 0; 32 33 v = bpf_map_lookup_elem(&array_map, &key); 34 if (!v) 35 return 0; 36 37 *(u32 *)&v->unref_ptr = 0; 38 return 0; 39 } 40 41 SEC("?tc") 42 __failure __msg("kptr access cannot have variable offset") 43 int non_const_var_off(struct __sk_buff *ctx) 44 { 45 struct map_value *v; 46 int key = 0, id; 47 48 v = bpf_map_lookup_elem(&array_map, &key); 49 if (!v) 50 return 0; 51 52 id = ctx->protocol; 53 if (id < 4 || id > 12) 54 return 0; 55 *(u64 *)((void *)v + id) = 0; 56 57 return 0; 58 } 59 60 SEC("?tc") 61 __failure __msg("R1 doesn't have constant offset. kptr has to be") 62 int non_const_var_off_kptr_xchg(struct __sk_buff *ctx) 63 { 64 struct map_value *v; 65 int key = 0, id; 66 67 v = bpf_map_lookup_elem(&array_map, &key); 68 if (!v) 69 return 0; 70 71 id = ctx->protocol; 72 if (id < 4 || id > 12) 73 return 0; 74 bpf_kptr_xchg((void *)v + id, NULL); 75 76 return 0; 77 } 78 79 SEC("?tc") 80 __failure __msg("kptr access misaligned expected=8 off=7") 81 int misaligned_access_write(struct __sk_buff *ctx) 82 { 83 struct map_value *v; 84 int key = 0; 85 86 v = bpf_map_lookup_elem(&array_map, &key); 87 if (!v) 88 return 0; 89 90 *(void **)((void *)v + 7) = NULL; 91 92 return 0; 93 } 94 95 SEC("?tc") 96 __failure __msg("kptr access misaligned expected=8 off=1") 97 int misaligned_access_read(struct __sk_buff *ctx) 98 { 99 struct map_value *v; 100 int key = 0; 101 102 v = bpf_map_lookup_elem(&array_map, &key); 103 if (!v) 104 return 0; 105 106 return *(u64 *)((void *)v + 1); 107 } 108 109 SEC("?tc") 110 __failure __msg("variable untrusted_ptr_ access var_off=(0x0; 0x1e0)") 111 int reject_var_off_store(struct __sk_buff *ctx) 112 { 113 struct prog_test_ref_kfunc *unref_ptr; 114 struct map_value *v; 115 int key = 0, id; 116 117 v = bpf_map_lookup_elem(&array_map, &key); 118 if (!v) 119 return 0; 120 121 unref_ptr = v->unref_ptr; 122 if (!unref_ptr) 123 return 0; 124 id = ctx->protocol; 125 if (id < 4 || id > 12) 126 return 0; 127 unref_ptr += id; 128 v->unref_ptr = unref_ptr; 129 130 return 0; 131 } 132 133 SEC("?tc") 134 __failure __msg("invalid kptr access, R1 type=untrusted_ptr_prog_test_ref_kfunc") 135 int reject_bad_type_match(struct __sk_buff *ctx) 136 { 137 struct prog_test_ref_kfunc *unref_ptr; 138 struct map_value *v; 139 int key = 0; 140 141 v = bpf_map_lookup_elem(&array_map, &key); 142 if (!v) 143 return 0; 144 145 unref_ptr = v->unref_ptr; 146 if (!unref_ptr) 147 return 0; 148 unref_ptr = (void *)unref_ptr + 4; 149 v->unref_ptr = unref_ptr; 150 151 return 0; 152 } 153 154 SEC("?tc") 155 __failure __msg("R1 type=untrusted_ptr_or_null_ expected=percpu_ptr_") 156 int marked_as_untrusted_or_null(struct __sk_buff *ctx) 157 { 158 struct map_value *v; 159 int key = 0; 160 161 v = bpf_map_lookup_elem(&array_map, &key); 162 if (!v) 163 return 0; 164 165 bpf_this_cpu_ptr(v->unref_ptr); 166 return 0; 167 } 168 169 SEC("?tc") 170 __failure __msg("access beyond struct prog_test_ref_kfunc at off 32 size 4") 171 int correct_btf_id_check_size(struct __sk_buff *ctx) 172 { 173 struct prog_test_ref_kfunc *p; 174 struct map_value *v; 175 int key = 0; 176 177 v = bpf_map_lookup_elem(&array_map, &key); 178 if (!v) 179 return 0; 180 181 p = v->unref_ptr; 182 if (!p) 183 return 0; 184 return *(int *)((void *)p + bpf_core_type_size(struct prog_test_ref_kfunc)); 185 } 186 187 SEC("?tc") 188 __failure __msg("R1 type=untrusted_ptr_ expected=percpu_ptr_") 189 int inherit_untrusted_on_walk(struct __sk_buff *ctx) 190 { 191 struct prog_test_ref_kfunc *unref_ptr; 192 struct map_value *v; 193 int key = 0; 194 195 v = bpf_map_lookup_elem(&array_map, &key); 196 if (!v) 197 return 0; 198 199 unref_ptr = v->unref_ptr; 200 if (!unref_ptr) 201 return 0; 202 unref_ptr = unref_ptr->next; 203 bpf_this_cpu_ptr(unref_ptr); 204 return 0; 205 } 206 207 SEC("?tc") 208 __failure __msg("off=8 kptr isn't referenced kptr") 209 int reject_kptr_xchg_on_unref(struct __sk_buff *ctx) 210 { 211 struct map_value *v; 212 int key = 0; 213 214 v = bpf_map_lookup_elem(&array_map, &key); 215 if (!v) 216 return 0; 217 218 bpf_kptr_xchg(&v->unref_ptr, NULL); 219 return 0; 220 } 221 222 SEC("?tc") 223 __failure __msg("arg#0 expected pointer to map value") 224 int reject_kptr_get_no_map_val(struct __sk_buff *ctx) 225 { 226 bpf_kfunc_call_test_kptr_get((void *)&ctx, 0, 0); 227 return 0; 228 } 229 230 SEC("?tc") 231 __failure __msg("arg#0 expected pointer to map value") 232 int reject_kptr_get_no_null_map_val(struct __sk_buff *ctx) 233 { 234 bpf_kfunc_call_test_kptr_get(bpf_map_lookup_elem(&array_map, &(int){0}), 0, 0); 235 return 0; 236 } 237 238 SEC("?tc") 239 __failure __msg("arg#0 no referenced kptr at map value offset=0") 240 int reject_kptr_get_no_kptr(struct __sk_buff *ctx) 241 { 242 struct map_value *v; 243 int key = 0; 244 245 v = bpf_map_lookup_elem(&array_map, &key); 246 if (!v) 247 return 0; 248 249 bpf_kfunc_call_test_kptr_get((void *)v, 0, 0); 250 return 0; 251 } 252 253 SEC("?tc") 254 __failure __msg("arg#0 no referenced kptr at map value offset=8") 255 int reject_kptr_get_on_unref(struct __sk_buff *ctx) 256 { 257 struct map_value *v; 258 int key = 0; 259 260 v = bpf_map_lookup_elem(&array_map, &key); 261 if (!v) 262 return 0; 263 264 bpf_kfunc_call_test_kptr_get(&v->unref_ptr, 0, 0); 265 return 0; 266 } 267 268 SEC("?tc") 269 __failure __msg("kernel function bpf_kfunc_call_test_kptr_get args#0") 270 int reject_kptr_get_bad_type_match(struct __sk_buff *ctx) 271 { 272 struct map_value *v; 273 int key = 0; 274 275 v = bpf_map_lookup_elem(&array_map, &key); 276 if (!v) 277 return 0; 278 279 bpf_kfunc_call_test_kptr_get((void *)&v->ref_memb_ptr, 0, 0); 280 return 0; 281 } 282 283 SEC("?tc") 284 __failure __msg("R1 type=untrusted_ptr_or_null_ expected=percpu_ptr_") 285 int mark_ref_as_untrusted_or_null(struct __sk_buff *ctx) 286 { 287 struct map_value *v; 288 int key = 0; 289 290 v = bpf_map_lookup_elem(&array_map, &key); 291 if (!v) 292 return 0; 293 294 bpf_this_cpu_ptr(v->ref_ptr); 295 return 0; 296 } 297 298 SEC("?tc") 299 __failure __msg("store to referenced kptr disallowed") 300 int reject_untrusted_store_to_ref(struct __sk_buff *ctx) 301 { 302 struct prog_test_ref_kfunc *p; 303 struct map_value *v; 304 int key = 0; 305 306 v = bpf_map_lookup_elem(&array_map, &key); 307 if (!v) 308 return 0; 309 310 p = v->ref_ptr; 311 if (!p) 312 return 0; 313 /* Checkmate, clang */ 314 *(struct prog_test_ref_kfunc * volatile *)&v->ref_ptr = p; 315 return 0; 316 } 317 318 SEC("?tc") 319 __failure __msg("R2 type=untrusted_ptr_ expected=ptr_") 320 int reject_untrusted_xchg(struct __sk_buff *ctx) 321 { 322 struct prog_test_ref_kfunc *p; 323 struct map_value *v; 324 int key = 0; 325 326 v = bpf_map_lookup_elem(&array_map, &key); 327 if (!v) 328 return 0; 329 330 p = v->ref_ptr; 331 if (!p) 332 return 0; 333 bpf_kptr_xchg(&v->ref_ptr, p); 334 return 0; 335 } 336 337 SEC("?tc") 338 __failure 339 __msg("invalid kptr access, R2 type=ptr_prog_test_ref_kfunc expected=ptr_prog_test_member") 340 int reject_bad_type_xchg(struct __sk_buff *ctx) 341 { 342 struct prog_test_ref_kfunc *ref_ptr; 343 struct map_value *v; 344 int key = 0; 345 346 v = bpf_map_lookup_elem(&array_map, &key); 347 if (!v) 348 return 0; 349 350 ref_ptr = bpf_kfunc_call_test_acquire(&(unsigned long){0}); 351 if (!ref_ptr) 352 return 0; 353 bpf_kptr_xchg(&v->ref_memb_ptr, ref_ptr); 354 return 0; 355 } 356 357 SEC("?tc") 358 __failure __msg("invalid kptr access, R2 type=ptr_prog_test_ref_kfunc") 359 int reject_member_of_ref_xchg(struct __sk_buff *ctx) 360 { 361 struct prog_test_ref_kfunc *ref_ptr; 362 struct map_value *v; 363 int key = 0; 364 365 v = bpf_map_lookup_elem(&array_map, &key); 366 if (!v) 367 return 0; 368 369 ref_ptr = bpf_kfunc_call_test_acquire(&(unsigned long){0}); 370 if (!ref_ptr) 371 return 0; 372 bpf_kptr_xchg(&v->ref_memb_ptr, &ref_ptr->memb); 373 return 0; 374 } 375 376 SEC("?syscall") 377 __failure __msg("kptr cannot be accessed indirectly by helper") 378 int reject_indirect_helper_access(struct __sk_buff *ctx) 379 { 380 struct map_value *v; 381 int key = 0; 382 383 v = bpf_map_lookup_elem(&array_map, &key); 384 if (!v) 385 return 0; 386 387 bpf_get_current_comm(v, sizeof(v->buf) + 1); 388 return 0; 389 } 390 391 __noinline 392 int write_func(int *p) 393 { 394 return p ? *p = 42 : 0; 395 } 396 397 SEC("?tc") 398 __failure __msg("kptr cannot be accessed indirectly by helper") 399 int reject_indirect_global_func_access(struct __sk_buff *ctx) 400 { 401 struct map_value *v; 402 int key = 0; 403 404 v = bpf_map_lookup_elem(&array_map, &key); 405 if (!v) 406 return 0; 407 408 return write_func((void *)v + 5); 409 } 410 411 SEC("?tc") 412 __failure __msg("Unreleased reference id=5 alloc_insn=") 413 int kptr_xchg_ref_state(struct __sk_buff *ctx) 414 { 415 struct prog_test_ref_kfunc *p; 416 struct map_value *v; 417 int key = 0; 418 419 v = bpf_map_lookup_elem(&array_map, &key); 420 if (!v) 421 return 0; 422 423 p = bpf_kfunc_call_test_acquire(&(unsigned long){0}); 424 if (!p) 425 return 0; 426 bpf_kptr_xchg(&v->ref_ptr, p); 427 return 0; 428 } 429 430 SEC("?tc") 431 __failure __msg("Unreleased reference id=3 alloc_insn=") 432 int kptr_get_ref_state(struct __sk_buff *ctx) 433 { 434 struct map_value *v; 435 int key = 0; 436 437 v = bpf_map_lookup_elem(&array_map, &key); 438 if (!v) 439 return 0; 440 441 bpf_kfunc_call_test_kptr_get(&v->ref_ptr, 0, 0); 442 return 0; 443 } 444 445 char _license[] SEC("license") = "GPL"; 446