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 57CHECK(kptr, pop_front, &f->head); 58CHECK(kptr, pop_back, &f->head); 59 60CHECK(global, pop_front, &ghead); 61CHECK(global, pop_back, &ghead); 62 63CHECK(map, pop_front, &v->head); 64CHECK(map, pop_back, &v->head); 65 66CHECK(inner_map, pop_front, &iv->head); 67CHECK(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 80CHECK(kptr, push_front, &f->head, &b->node); 81CHECK(kptr, push_back, &f->head, &b->node); 82 83CHECK(global, push_front, &ghead, &f->node2); 84CHECK(global, push_back, &ghead, &f->node2); 85 86CHECK(map, push_front, &v->head, &f->node2); 87CHECK(map, push_back, &v->head, &f->node2); 88 89CHECK(inner_map, push_front, &iv->head, &f->node2); 90CHECK(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 126CHECK_OP(pop_front); 127CHECK_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 163CHECK_OP(push_front); 164CHECK_OP(push_back); 165 166#undef CHECK 167#undef CHECK_OP 168#undef INIT 169 170SEC("?kprobe/xyz") 171int map_compat_kprobe(void *ctx) 172{ 173 bpf_list_push_front(&ghead, NULL); 174 return 0; 175} 176 177SEC("?kretprobe/xyz") 178int map_compat_kretprobe(void *ctx) 179{ 180 bpf_list_push_front(&ghead, NULL); 181 return 0; 182} 183 184SEC("?tracepoint/xyz") 185int map_compat_tp(void *ctx) 186{ 187 bpf_list_push_front(&ghead, NULL); 188 return 0; 189} 190 191SEC("?perf_event") 192int map_compat_perf(void *ctx) 193{ 194 bpf_list_push_front(&ghead, NULL); 195 return 0; 196} 197 198SEC("?raw_tp/xyz") 199int map_compat_raw_tp(void *ctx) 200{ 201 bpf_list_push_front(&ghead, NULL); 202 return 0; 203} 204 205SEC("?raw_tp.w/xyz") 206int map_compat_raw_tp_w(void *ctx) 207{ 208 bpf_list_push_front(&ghead, NULL); 209 return 0; 210} 211 212SEC("?tc") 213int obj_type_id_oor(void *ctx) 214{ 215 bpf_obj_new_impl(~0UL, NULL); 216 return 0; 217} 218 219SEC("?tc") 220int 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 226SEC("?tc") 227int obj_new_no_struct(void *ctx) 228{ 229 230 bpf_obj_new(union { int data; unsigned udata; }); 231 return 0; 232} 233 234SEC("?tc") 235int 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 246SEC("?tc") 247int new_null_ret(void *ctx) 248{ 249 return bpf_obj_new(struct foo)->data; 250} 251 252SEC("?tc") 253int obj_new_acq(void *ctx) 254{ 255 bpf_obj_new(struct foo); 256 return 0; 257} 258 259SEC("?tc") 260int 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 271SEC("?tc") 272int 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 287SEC("?tc") 288int 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 298SEC("?tc") 299int 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 310SEC("?tc") 311int 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 321SEC("?tc") 322int 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 333SEC("?tc") 334int 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 344SEC("?tc") 345int 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 356static __always_inline 357int 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 375SEC("?tc") 376int use_after_unlock_push_front(void *ctx) 377{ 378 return use_after_unlock(true); 379} 380 381SEC("?tc") 382int use_after_unlock_push_back(void *ctx) 383{ 384 return use_after_unlock(false); 385} 386 387static __always_inline 388int 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 408SEC("?tc") 409int double_push_front(void *ctx) 410{ 411 return list_double_add(true); 412} 413 414SEC("?tc") 415int double_push_back(void *ctx) 416{ 417 return list_double_add(false); 418} 419 420SEC("?tc") 421int 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 435SEC("?tc") 436int 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 450SEC("?tc") 451int 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 465SEC("?tc") 466int 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 480SEC("?tc") 481int 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 495SEC("?tc") 496int 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 510SEC("?tc") 511int 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 525SEC("?tc") 526int 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 540SEC("?tc") 541int 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 562SEC("?tc") 563int 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 578static __always_inline 579int 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 if (!n) 595 return 0; 596 bpf_spin_lock((void *)n); 597 return 0; 598} 599 600SEC("?tc") 601int pop_front_off(void *ctx) 602{ 603 return pop_ptr_off((void *)bpf_list_pop_front); 604} 605 606SEC("?tc") 607int pop_back_off(void *ctx) 608{ 609 return pop_ptr_off((void *)bpf_list_pop_back); 610} 611 612char _license[] SEC("license") = "GPL"; 613