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_experimental.h" 7 8 #include "linked_list.h" 9 10 #define INIT \ 11 struct map_value *v, *v2, *iv, *iv2; \ 12 struct foo *f, *f1, *f2; \ 13 struct bar *b; \ 14 void *map; \ 15 \ 16 map = bpf_map_lookup_elem(&map_of_maps, &(int){ 0 }); \ 17 if (!map) \ 18 return 0; \ 19 v = bpf_map_lookup_elem(&array_map, &(int){ 0 }); \ 20 if (!v) \ 21 return 0; \ 22 v2 = bpf_map_lookup_elem(&array_map, &(int){ 0 }); \ 23 if (!v2) \ 24 return 0; \ 25 iv = bpf_map_lookup_elem(map, &(int){ 0 }); \ 26 if (!iv) \ 27 return 0; \ 28 iv2 = bpf_map_lookup_elem(map, &(int){ 0 }); \ 29 if (!iv2) \ 30 return 0; \ 31 f = bpf_obj_new(typeof(*f)); \ 32 if (!f) \ 33 return 0; \ 34 f1 = f; \ 35 f2 = bpf_obj_new(typeof(*f2)); \ 36 if (!f2) { \ 37 bpf_obj_drop(f1); \ 38 return 0; \ 39 } \ 40 b = bpf_obj_new(typeof(*b)); \ 41 if (!b) { \ 42 bpf_obj_drop(f2); \ 43 bpf_obj_drop(f1); \ 44 return 0; \ 45 } 46 47 #define CHECK(test, op, hexpr) \ 48 SEC("?tc") \ 49 int test##_missing_lock_##op(void *ctx) \ 50 { \ 51 INIT; \ 52 void (*p)(void *) = (void *)&bpf_list_##op; \ 53 p(hexpr); \ 54 return 0; \ 55 } 56 57 CHECK(kptr, pop_front, &f->head); 58 CHECK(kptr, pop_back, &f->head); 59 60 CHECK(global, pop_front, &ghead); 61 CHECK(global, pop_back, &ghead); 62 63 CHECK(map, pop_front, &v->head); 64 CHECK(map, pop_back, &v->head); 65 66 CHECK(inner_map, pop_front, &iv->head); 67 CHECK(inner_map, pop_back, &iv->head); 68 69 #undef CHECK 70 71 #define CHECK(test, op, hexpr, nexpr) \ 72 SEC("?tc") \ 73 int test##_missing_lock_##op(void *ctx) \ 74 { \ 75 INIT; \ 76 void (*p)(void *, void *) = (void *)&bpf_list_##op; \ 77 p(hexpr, nexpr); \ 78 return 0; \ 79 } 80 81 CHECK(kptr, push_front, &f->head, b); 82 CHECK(kptr, push_back, &f->head, b); 83 84 CHECK(global, push_front, &ghead, f); 85 CHECK(global, push_back, &ghead, f); 86 87 CHECK(map, push_front, &v->head, f); 88 CHECK(map, push_back, &v->head, f); 89 90 CHECK(inner_map, push_front, &iv->head, f); 91 CHECK(inner_map, push_back, &iv->head, f); 92 93 #undef CHECK 94 95 #define CHECK(test, op, lexpr, hexpr) \ 96 SEC("?tc") \ 97 int test##_incorrect_lock_##op(void *ctx) \ 98 { \ 99 INIT; \ 100 void (*p)(void *) = (void *)&bpf_list_##op; \ 101 bpf_spin_lock(lexpr); \ 102 p(hexpr); \ 103 return 0; \ 104 } 105 106 #define CHECK_OP(op) \ 107 CHECK(kptr_kptr, op, &f1->lock, &f2->head); \ 108 CHECK(kptr_global, op, &f1->lock, &ghead); \ 109 CHECK(kptr_map, op, &f1->lock, &v->head); \ 110 CHECK(kptr_inner_map, op, &f1->lock, &iv->head); \ 111 \ 112 CHECK(global_global, op, &glock2, &ghead); \ 113 CHECK(global_kptr, op, &glock, &f1->head); \ 114 CHECK(global_map, op, &glock, &v->head); \ 115 CHECK(global_inner_map, op, &glock, &iv->head); \ 116 \ 117 CHECK(map_map, op, &v->lock, &v2->head); \ 118 CHECK(map_kptr, op, &v->lock, &f2->head); \ 119 CHECK(map_global, op, &v->lock, &ghead); \ 120 CHECK(map_inner_map, op, &v->lock, &iv->head); \ 121 \ 122 CHECK(inner_map_inner_map, op, &iv->lock, &iv2->head); \ 123 CHECK(inner_map_kptr, op, &iv->lock, &f2->head); \ 124 CHECK(inner_map_global, op, &iv->lock, &ghead); \ 125 CHECK(inner_map_map, op, &iv->lock, &v->head); 126 127 CHECK_OP(pop_front); 128 CHECK_OP(pop_back); 129 130 #undef CHECK 131 #undef CHECK_OP 132 133 #define CHECK(test, op, lexpr, hexpr, nexpr) \ 134 SEC("?tc") \ 135 int test##_incorrect_lock_##op(void *ctx) \ 136 { \ 137 INIT; \ 138 void (*p)(void *, void*) = (void *)&bpf_list_##op; \ 139 bpf_spin_lock(lexpr); \ 140 p(hexpr, nexpr); \ 141 return 0; \ 142 } 143 144 #define CHECK_OP(op) \ 145 CHECK(kptr_kptr, op, &f1->lock, &f2->head, b); \ 146 CHECK(kptr_global, op, &f1->lock, &ghead, f); \ 147 CHECK(kptr_map, op, &f1->lock, &v->head, f); \ 148 CHECK(kptr_inner_map, op, &f1->lock, &iv->head, f); \ 149 \ 150 CHECK(global_global, op, &glock2, &ghead, f); \ 151 CHECK(global_kptr, op, &glock, &f1->head, b); \ 152 CHECK(global_map, op, &glock, &v->head, f); \ 153 CHECK(global_inner_map, op, &glock, &iv->head, f); \ 154 \ 155 CHECK(map_map, op, &v->lock, &v2->head, f); \ 156 CHECK(map_kptr, op, &v->lock, &f2->head, b); \ 157 CHECK(map_global, op, &v->lock, &ghead, f); \ 158 CHECK(map_inner_map, op, &v->lock, &iv->head, f); \ 159 \ 160 CHECK(inner_map_inner_map, op, &iv->lock, &iv2->head, f); \ 161 CHECK(inner_map_kptr, op, &iv->lock, &f2->head, b); \ 162 CHECK(inner_map_global, op, &iv->lock, &ghead, f); \ 163 CHECK(inner_map_map, op, &iv->lock, &v->head, f); 164 165 CHECK_OP(push_front); 166 CHECK_OP(push_back); 167 168 #undef CHECK 169 #undef CHECK_OP 170 #undef INIT 171 172 SEC("?kprobe/xyz") 173 int map_compat_kprobe(void *ctx) 174 { 175 bpf_list_push_front(&ghead, NULL); 176 return 0; 177 } 178 179 SEC("?kretprobe/xyz") 180 int map_compat_kretprobe(void *ctx) 181 { 182 bpf_list_push_front(&ghead, NULL); 183 return 0; 184 } 185 186 SEC("?tracepoint/xyz") 187 int map_compat_tp(void *ctx) 188 { 189 bpf_list_push_front(&ghead, NULL); 190 return 0; 191 } 192 193 SEC("?perf_event") 194 int map_compat_perf(void *ctx) 195 { 196 bpf_list_push_front(&ghead, NULL); 197 return 0; 198 } 199 200 SEC("?raw_tp/xyz") 201 int map_compat_raw_tp(void *ctx) 202 { 203 bpf_list_push_front(&ghead, NULL); 204 return 0; 205 } 206 207 SEC("?raw_tp.w/xyz") 208 int map_compat_raw_tp_w(void *ctx) 209 { 210 bpf_list_push_front(&ghead, NULL); 211 return 0; 212 } 213 214 SEC("?tc") 215 int obj_type_id_oor(void *ctx) 216 { 217 bpf_obj_new_impl(~0UL, NULL); 218 return 0; 219 } 220 221 SEC("?tc") 222 int obj_new_no_composite(void *ctx) 223 { 224 bpf_obj_new_impl(bpf_core_type_id_local(int), (void *)42); 225 return 0; 226 } 227 228 SEC("?tc") 229 int obj_new_no_struct(void *ctx) 230 { 231 232 bpf_obj_new(union { int data; unsigned udata; }); 233 return 0; 234 } 235 236 SEC("?tc") 237 int obj_drop_non_zero_off(void *ctx) 238 { 239 void *f; 240 241 f = bpf_obj_new(struct foo); 242 if (!f) 243 return 0; 244 bpf_obj_drop(f+1); 245 return 0; 246 } 247 248 SEC("?tc") 249 int new_null_ret(void *ctx) 250 { 251 return bpf_obj_new(struct foo)->data; 252 } 253 254 SEC("?tc") 255 int obj_new_acq(void *ctx) 256 { 257 bpf_obj_new(struct foo); 258 return 0; 259 } 260 261 SEC("?tc") 262 int use_after_drop(void *ctx) 263 { 264 struct foo *f; 265 266 f = bpf_obj_new(typeof(*f)); 267 if (!f) 268 return 0; 269 bpf_obj_drop(f); 270 return f->data; 271 } 272 273 SEC("?tc") 274 int ptr_walk_scalar(void *ctx) 275 { 276 struct test1 { 277 struct test2 { 278 struct test2 *next; 279 } *ptr; 280 } *p; 281 282 p = bpf_obj_new(typeof(*p)); 283 if (!p) 284 return 0; 285 bpf_this_cpu_ptr(p->ptr); 286 return 0; 287 } 288 289 SEC("?tc") 290 int direct_read_lock(void *ctx) 291 { 292 struct foo *f; 293 294 f = bpf_obj_new(typeof(*f)); 295 if (!f) 296 return 0; 297 return *(int *)&f->lock; 298 } 299 300 SEC("?tc") 301 int direct_write_lock(void *ctx) 302 { 303 struct foo *f; 304 305 f = bpf_obj_new(typeof(*f)); 306 if (!f) 307 return 0; 308 *(int *)&f->lock = 0; 309 return 0; 310 } 311 312 SEC("?tc") 313 int direct_read_head(void *ctx) 314 { 315 struct foo *f; 316 317 f = bpf_obj_new(typeof(*f)); 318 if (!f) 319 return 0; 320 return *(int *)&f->head; 321 } 322 323 SEC("?tc") 324 int direct_write_head(void *ctx) 325 { 326 struct foo *f; 327 328 f = bpf_obj_new(typeof(*f)); 329 if (!f) 330 return 0; 331 *(int *)&f->head = 0; 332 return 0; 333 } 334 335 SEC("?tc") 336 int direct_read_node(void *ctx) 337 { 338 struct foo *f; 339 340 f = bpf_obj_new(typeof(*f)); 341 if (!f) 342 return 0; 343 return *(int *)&f->node; 344 } 345 346 SEC("?tc") 347 int direct_write_node(void *ctx) 348 { 349 struct foo *f; 350 351 f = bpf_obj_new(typeof(*f)); 352 if (!f) 353 return 0; 354 *(int *)&f->node = 0; 355 return 0; 356 } 357 358 static __always_inline 359 int use_after_unlock(void (*op)(void *head, void *node)) 360 { 361 struct foo *f; 362 363 f = bpf_obj_new(typeof(*f)); 364 if (!f) 365 return 0; 366 bpf_spin_lock(&glock); 367 f->data = 42; 368 op(&ghead, &f->node); 369 bpf_spin_unlock(&glock); 370 371 return f->data; 372 } 373 374 SEC("?tc") 375 int use_after_unlock_push_front(void *ctx) 376 { 377 return use_after_unlock((void *)bpf_list_push_front); 378 } 379 380 SEC("?tc") 381 int use_after_unlock_push_back(void *ctx) 382 { 383 return use_after_unlock((void *)bpf_list_push_back); 384 } 385 386 static __always_inline 387 int list_double_add(void (*op)(void *head, void *node)) 388 { 389 struct foo *f; 390 391 f = bpf_obj_new(typeof(*f)); 392 if (!f) 393 return 0; 394 bpf_spin_lock(&glock); 395 op(&ghead, &f->node); 396 op(&ghead, &f->node); 397 bpf_spin_unlock(&glock); 398 399 return 0; 400 } 401 402 SEC("?tc") 403 int double_push_front(void *ctx) 404 { 405 return list_double_add((void *)bpf_list_push_front); 406 } 407 408 SEC("?tc") 409 int double_push_back(void *ctx) 410 { 411 return list_double_add((void *)bpf_list_push_back); 412 } 413 414 SEC("?tc") 415 int no_node_value_type(void *ctx) 416 { 417 void *p; 418 419 p = bpf_obj_new(struct { int data; }); 420 if (!p) 421 return 0; 422 bpf_spin_lock(&glock); 423 bpf_list_push_front(&ghead, p); 424 bpf_spin_unlock(&glock); 425 426 return 0; 427 } 428 429 SEC("?tc") 430 int incorrect_value_type(void *ctx) 431 { 432 struct bar *b; 433 434 b = bpf_obj_new(typeof(*b)); 435 if (!b) 436 return 0; 437 bpf_spin_lock(&glock); 438 bpf_list_push_front(&ghead, &b->node); 439 bpf_spin_unlock(&glock); 440 441 return 0; 442 } 443 444 SEC("?tc") 445 int incorrect_node_var_off(struct __sk_buff *ctx) 446 { 447 struct foo *f; 448 449 f = bpf_obj_new(typeof(*f)); 450 if (!f) 451 return 0; 452 bpf_spin_lock(&glock); 453 bpf_list_push_front(&ghead, (void *)&f->node + ctx->protocol); 454 bpf_spin_unlock(&glock); 455 456 return 0; 457 } 458 459 SEC("?tc") 460 int incorrect_node_off1(void *ctx) 461 { 462 struct foo *f; 463 464 f = bpf_obj_new(typeof(*f)); 465 if (!f) 466 return 0; 467 bpf_spin_lock(&glock); 468 bpf_list_push_front(&ghead, (void *)&f->node + 1); 469 bpf_spin_unlock(&glock); 470 471 return 0; 472 } 473 474 SEC("?tc") 475 int incorrect_node_off2(void *ctx) 476 { 477 struct foo *f; 478 479 f = bpf_obj_new(typeof(*f)); 480 if (!f) 481 return 0; 482 bpf_spin_lock(&glock); 483 bpf_list_push_front(&ghead, &f->node2); 484 bpf_spin_unlock(&glock); 485 486 return 0; 487 } 488 489 SEC("?tc") 490 int no_head_type(void *ctx) 491 { 492 void *p; 493 494 p = bpf_obj_new(typeof(struct { int data; })); 495 if (!p) 496 return 0; 497 bpf_spin_lock(&glock); 498 bpf_list_push_front(p, NULL); 499 bpf_spin_lock(&glock); 500 501 return 0; 502 } 503 504 SEC("?tc") 505 int incorrect_head_var_off1(struct __sk_buff *ctx) 506 { 507 struct foo *f; 508 509 f = bpf_obj_new(typeof(*f)); 510 if (!f) 511 return 0; 512 bpf_spin_lock(&glock); 513 bpf_list_push_front((void *)&ghead + ctx->protocol, &f->node); 514 bpf_spin_unlock(&glock); 515 516 return 0; 517 } 518 519 SEC("?tc") 520 int incorrect_head_var_off2(struct __sk_buff *ctx) 521 { 522 struct foo *f; 523 524 f = bpf_obj_new(typeof(*f)); 525 if (!f) 526 return 0; 527 bpf_spin_lock(&glock); 528 bpf_list_push_front((void *)&f->head + ctx->protocol, &f->node); 529 bpf_spin_unlock(&glock); 530 531 return 0; 532 } 533 534 SEC("?tc") 535 int incorrect_head_off1(void *ctx) 536 { 537 struct foo *f; 538 struct bar *b; 539 540 f = bpf_obj_new(typeof(*f)); 541 if (!f) 542 return 0; 543 b = bpf_obj_new(typeof(*b)); 544 if (!b) { 545 bpf_obj_drop(f); 546 return 0; 547 } 548 549 bpf_spin_lock(&f->lock); 550 bpf_list_push_front((void *)&f->head + 1, &b->node); 551 bpf_spin_unlock(&f->lock); 552 553 return 0; 554 } 555 556 SEC("?tc") 557 int incorrect_head_off2(void *ctx) 558 { 559 struct foo *f; 560 struct bar *b; 561 562 f = bpf_obj_new(typeof(*f)); 563 if (!f) 564 return 0; 565 566 bpf_spin_lock(&glock); 567 bpf_list_push_front((void *)&ghead + 1, &f->node); 568 bpf_spin_unlock(&glock); 569 570 return 0; 571 } 572 573 static __always_inline 574 int pop_ptr_off(void *(*op)(void *head)) 575 { 576 struct { 577 struct bpf_list_head head __contains(foo, node2); 578 struct bpf_spin_lock lock; 579 } *p; 580 struct bpf_list_node *n; 581 582 p = bpf_obj_new(typeof(*p)); 583 if (!p) 584 return 0; 585 bpf_spin_lock(&p->lock); 586 n = op(&p->head); 587 bpf_spin_unlock(&p->lock); 588 589 bpf_this_cpu_ptr(n); 590 return 0; 591 } 592 593 SEC("?tc") 594 int pop_front_off(void *ctx) 595 { 596 return pop_ptr_off((void *)bpf_list_pop_front); 597 } 598 599 SEC("?tc") 600 int pop_back_off(void *ctx) 601 { 602 return pop_ptr_off((void *)bpf_list_pop_back); 603 } 604 605 char _license[] SEC("license") = "GPL"; 606