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