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