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 230 bpf_obj_new(union { int data; unsigned udata; }); 231 return 0; 232 } 233 234 SEC("?tc") 235 int obj_drop_non_zero_off(void *ctx) 236 { 237 void *f; 238 239 f = bpf_obj_new(struct foo); 240 if (!f) 241 return 0; 242 bpf_obj_drop(f+1); 243 return 0; 244 } 245 246 SEC("?tc") 247 int new_null_ret(void *ctx) 248 { 249 return bpf_obj_new(struct foo)->data; 250 } 251 252 SEC("?tc") 253 int obj_new_acq(void *ctx) 254 { 255 bpf_obj_new(struct foo); 256 return 0; 257 } 258 259 SEC("?tc") 260 int use_after_drop(void *ctx) 261 { 262 struct foo *f; 263 264 f = bpf_obj_new(typeof(*f)); 265 if (!f) 266 return 0; 267 bpf_obj_drop(f); 268 return f->data; 269 } 270 271 SEC("?tc") 272 int ptr_walk_scalar(void *ctx) 273 { 274 struct test1 { 275 struct test2 { 276 struct test2 *next; 277 } *ptr; 278 } *p; 279 280 p = bpf_obj_new(typeof(*p)); 281 if (!p) 282 return 0; 283 bpf_this_cpu_ptr(p->ptr); 284 return 0; 285 } 286 287 SEC("?tc") 288 int direct_read_lock(void *ctx) 289 { 290 struct foo *f; 291 292 f = bpf_obj_new(typeof(*f)); 293 if (!f) 294 return 0; 295 return *(int *)&f->lock; 296 } 297 298 SEC("?tc") 299 int direct_write_lock(void *ctx) 300 { 301 struct foo *f; 302 303 f = bpf_obj_new(typeof(*f)); 304 if (!f) 305 return 0; 306 *(int *)&f->lock = 0; 307 return 0; 308 } 309 310 SEC("?tc") 311 int direct_read_head(void *ctx) 312 { 313 struct foo *f; 314 315 f = bpf_obj_new(typeof(*f)); 316 if (!f) 317 return 0; 318 return *(int *)&f->head; 319 } 320 321 SEC("?tc") 322 int direct_write_head(void *ctx) 323 { 324 struct foo *f; 325 326 f = bpf_obj_new(typeof(*f)); 327 if (!f) 328 return 0; 329 *(int *)&f->head = 0; 330 return 0; 331 } 332 333 SEC("?tc") 334 int direct_read_node(void *ctx) 335 { 336 struct foo *f; 337 338 f = bpf_obj_new(typeof(*f)); 339 if (!f) 340 return 0; 341 return *(int *)&f->node2; 342 } 343 344 SEC("?tc") 345 int direct_write_node(void *ctx) 346 { 347 struct foo *f; 348 349 f = bpf_obj_new(typeof(*f)); 350 if (!f) 351 return 0; 352 *(int *)&f->node2 = 0; 353 return 0; 354 } 355 356 static __always_inline 357 int use_after_unlock(bool push_front) 358 { 359 struct foo *f; 360 361 f = bpf_obj_new(typeof(*f)); 362 if (!f) 363 return 0; 364 bpf_spin_lock(&glock); 365 f->data = 42; 366 if (push_front) 367 bpf_list_push_front(&ghead, &f->node2); 368 else 369 bpf_list_push_back(&ghead, &f->node2); 370 bpf_spin_unlock(&glock); 371 372 return f->data; 373 } 374 375 SEC("?tc") 376 int use_after_unlock_push_front(void *ctx) 377 { 378 return use_after_unlock(true); 379 } 380 381 SEC("?tc") 382 int use_after_unlock_push_back(void *ctx) 383 { 384 return use_after_unlock(false); 385 } 386 387 static __always_inline 388 int list_double_add(bool push_front) 389 { 390 struct foo *f; 391 392 f = bpf_obj_new(typeof(*f)); 393 if (!f) 394 return 0; 395 bpf_spin_lock(&glock); 396 if (push_front) { 397 bpf_list_push_front(&ghead, &f->node2); 398 bpf_list_push_front(&ghead, &f->node2); 399 } else { 400 bpf_list_push_back(&ghead, &f->node2); 401 bpf_list_push_back(&ghead, &f->node2); 402 } 403 bpf_spin_unlock(&glock); 404 405 return 0; 406 } 407 408 SEC("?tc") 409 int double_push_front(void *ctx) 410 { 411 return list_double_add(true); 412 } 413 414 SEC("?tc") 415 int double_push_back(void *ctx) 416 { 417 return list_double_add(false); 418 } 419 420 SEC("?tc") 421 int no_node_value_type(void *ctx) 422 { 423 void *p; 424 425 p = bpf_obj_new(struct { int data; }); 426 if (!p) 427 return 0; 428 bpf_spin_lock(&glock); 429 bpf_list_push_front(&ghead, p); 430 bpf_spin_unlock(&glock); 431 432 return 0; 433 } 434 435 SEC("?tc") 436 int incorrect_value_type(void *ctx) 437 { 438 struct bar *b; 439 440 b = bpf_obj_new(typeof(*b)); 441 if (!b) 442 return 0; 443 bpf_spin_lock(&glock); 444 bpf_list_push_front(&ghead, &b->node); 445 bpf_spin_unlock(&glock); 446 447 return 0; 448 } 449 450 SEC("?tc") 451 int incorrect_node_var_off(struct __sk_buff *ctx) 452 { 453 struct foo *f; 454 455 f = bpf_obj_new(typeof(*f)); 456 if (!f) 457 return 0; 458 bpf_spin_lock(&glock); 459 bpf_list_push_front(&ghead, (void *)&f->node2 + ctx->protocol); 460 bpf_spin_unlock(&glock); 461 462 return 0; 463 } 464 465 SEC("?tc") 466 int incorrect_node_off1(void *ctx) 467 { 468 struct foo *f; 469 470 f = bpf_obj_new(typeof(*f)); 471 if (!f) 472 return 0; 473 bpf_spin_lock(&glock); 474 bpf_list_push_front(&ghead, (void *)&f->node2 + 1); 475 bpf_spin_unlock(&glock); 476 477 return 0; 478 } 479 480 SEC("?tc") 481 int incorrect_node_off2(void *ctx) 482 { 483 struct foo *f; 484 485 f = bpf_obj_new(typeof(*f)); 486 if (!f) 487 return 0; 488 bpf_spin_lock(&glock); 489 bpf_list_push_front(&ghead, &f->node); 490 bpf_spin_unlock(&glock); 491 492 return 0; 493 } 494 495 SEC("?tc") 496 int no_head_type(void *ctx) 497 { 498 void *p; 499 500 p = bpf_obj_new(typeof(struct { int data; })); 501 if (!p) 502 return 0; 503 bpf_spin_lock(&glock); 504 bpf_list_push_front(p, NULL); 505 bpf_spin_lock(&glock); 506 507 return 0; 508 } 509 510 SEC("?tc") 511 int incorrect_head_var_off1(struct __sk_buff *ctx) 512 { 513 struct foo *f; 514 515 f = bpf_obj_new(typeof(*f)); 516 if (!f) 517 return 0; 518 bpf_spin_lock(&glock); 519 bpf_list_push_front((void *)&ghead + ctx->protocol, &f->node2); 520 bpf_spin_unlock(&glock); 521 522 return 0; 523 } 524 525 SEC("?tc") 526 int incorrect_head_var_off2(struct __sk_buff *ctx) 527 { 528 struct foo *f; 529 530 f = bpf_obj_new(typeof(*f)); 531 if (!f) 532 return 0; 533 bpf_spin_lock(&glock); 534 bpf_list_push_front((void *)&f->head + ctx->protocol, &f->node2); 535 bpf_spin_unlock(&glock); 536 537 return 0; 538 } 539 540 SEC("?tc") 541 int incorrect_head_off1(void *ctx) 542 { 543 struct foo *f; 544 struct bar *b; 545 546 f = bpf_obj_new(typeof(*f)); 547 if (!f) 548 return 0; 549 b = bpf_obj_new(typeof(*b)); 550 if (!b) { 551 bpf_obj_drop(f); 552 return 0; 553 } 554 555 bpf_spin_lock(&f->lock); 556 bpf_list_push_front((void *)&f->head + 1, &b->node); 557 bpf_spin_unlock(&f->lock); 558 559 return 0; 560 } 561 562 SEC("?tc") 563 int incorrect_head_off2(void *ctx) 564 { 565 struct foo *f; 566 567 f = bpf_obj_new(typeof(*f)); 568 if (!f) 569 return 0; 570 571 bpf_spin_lock(&glock); 572 bpf_list_push_front((void *)&ghead + 1, &f->node2); 573 bpf_spin_unlock(&glock); 574 575 return 0; 576 } 577 578 static __always_inline 579 int pop_ptr_off(void *(*op)(void *head)) 580 { 581 struct { 582 struct bpf_list_head head __contains(foo, node2); 583 struct bpf_spin_lock lock; 584 } *p; 585 struct bpf_list_node *n; 586 587 p = bpf_obj_new(typeof(*p)); 588 if (!p) 589 return 0; 590 bpf_spin_lock(&p->lock); 591 n = op(&p->head); 592 bpf_spin_unlock(&p->lock); 593 594 bpf_this_cpu_ptr(n); 595 return 0; 596 } 597 598 SEC("?tc") 599 int pop_front_off(void *ctx) 600 { 601 return pop_ptr_off((void *)bpf_list_pop_front); 602 } 603 604 SEC("?tc") 605 int pop_back_off(void *ctx) 606 { 607 return pop_ptr_off((void *)bpf_list_pop_back); 608 } 609 610 char _license[] SEC("license") = "GPL"; 611