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")
map_compat_kprobe(void * ctx)171 int map_compat_kprobe(void *ctx)
172 {
173 bpf_list_push_front(&ghead, NULL);
174 return 0;
175 }
176
177 SEC("?kretprobe/xyz")
map_compat_kretprobe(void * ctx)178 int map_compat_kretprobe(void *ctx)
179 {
180 bpf_list_push_front(&ghead, NULL);
181 return 0;
182 }
183
184 SEC("?tracepoint/xyz")
map_compat_tp(void * ctx)185 int map_compat_tp(void *ctx)
186 {
187 bpf_list_push_front(&ghead, NULL);
188 return 0;
189 }
190
191 SEC("?perf_event")
map_compat_perf(void * ctx)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")
map_compat_raw_tp(void * ctx)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")
map_compat_raw_tp_w(void * ctx)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")
obj_type_id_oor(void * ctx)213 int obj_type_id_oor(void *ctx)
214 {
215 bpf_obj_new_impl(~0UL, NULL);
216 return 0;
217 }
218
219 SEC("?tc")
obj_new_no_composite(void * ctx)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")
obj_new_no_struct(void * ctx)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")
obj_drop_non_zero_off(void * ctx)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")
new_null_ret(void * ctx)247 int new_null_ret(void *ctx)
248 {
249 return bpf_obj_new(struct foo)->data;
250 }
251
252 SEC("?tc")
obj_new_acq(void * ctx)253 int obj_new_acq(void *ctx)
254 {
255 bpf_obj_new(struct foo);
256 return 0;
257 }
258
259 SEC("?tc")
use_after_drop(void * ctx)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")
ptr_walk_scalar(void * ctx)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")
direct_read_lock(void * ctx)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")
direct_write_lock(void * ctx)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")
direct_read_head(void * ctx)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")
direct_write_head(void * ctx)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")
direct_read_node(void * ctx)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")
direct_write_node(void * ctx)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
use_after_unlock(bool push_front)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")
use_after_unlock_push_front(void * ctx)376 int use_after_unlock_push_front(void *ctx)
377 {
378 return use_after_unlock(true);
379 }
380
381 SEC("?tc")
use_after_unlock_push_back(void * ctx)382 int use_after_unlock_push_back(void *ctx)
383 {
384 return use_after_unlock(false);
385 }
386
387 static __always_inline
list_double_add(bool push_front)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")
double_push_front(void * ctx)409 int double_push_front(void *ctx)
410 {
411 return list_double_add(true);
412 }
413
414 SEC("?tc")
double_push_back(void * ctx)415 int double_push_back(void *ctx)
416 {
417 return list_double_add(false);
418 }
419
420 SEC("?tc")
no_node_value_type(void * ctx)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")
incorrect_value_type(void * ctx)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")
incorrect_node_var_off(struct __sk_buff * ctx)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")
incorrect_node_off1(void * ctx)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")
incorrect_node_off2(void * ctx)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")
no_head_type(void * ctx)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")
incorrect_head_var_off1(struct __sk_buff * ctx)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")
incorrect_head_var_off2(struct __sk_buff * ctx)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")
incorrect_head_off1(void * ctx)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")
incorrect_head_off2(void * ctx)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
pop_ptr_off(void * (* op)(void * head))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 if (!n)
595 return 0;
596 bpf_spin_lock((void *)n);
597 return 0;
598 }
599
600 SEC("?tc")
pop_front_off(void * ctx)601 int pop_front_off(void *ctx)
602 {
603 return pop_ptr_off((void *)bpf_list_pop_front);
604 }
605
606 SEC("?tc")
pop_back_off(void * ctx)607 int pop_back_off(void *ctx)
608 {
609 return pop_ptr_off((void *)bpf_list_pop_back);
610 }
611
612 char _license[] SEC("license") = "GPL";
613