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