613 lines · c
1// SPDX-License-Identifier: GPL-2.02#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 CHECK70 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 CHECK93 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 CHECK130#undef CHECK_OP131 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 CHECK167#undef CHECK_OP168#undef INIT169 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_inline357int 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 else369 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_inline388int 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_inline579int 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