Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 (void)bpf_obj_new(union { int data; unsigned udata; });
230 return 0;
231}
232
233SEC("?tc")
234int obj_drop_non_zero_off(void *ctx)
235{
236 void *f;
237
238 f = bpf_obj_new(struct foo);
239 if (!f)
240 return 0;
241 bpf_obj_drop(f+1);
242 return 0;
243}
244
245SEC("?tc")
246int new_null_ret(void *ctx)
247{
248 return bpf_obj_new(struct foo)->data;
249}
250
251SEC("?tc")
252int obj_new_acq(void *ctx)
253{
254 (void)bpf_obj_new(struct foo);
255 return 0;
256}
257
258SEC("?tc")
259int use_after_drop(void *ctx)
260{
261 struct foo *f;
262
263 f = bpf_obj_new(typeof(*f));
264 if (!f)
265 return 0;
266 bpf_obj_drop(f);
267 return f->data;
268}
269
270SEC("?tc")
271int ptr_walk_scalar(void *ctx)
272{
273 struct test1 {
274 struct test2 {
275 struct test2 *next;
276 } *ptr;
277 } *p;
278
279 p = bpf_obj_new(typeof(*p));
280 if (!p)
281 return 0;
282 bpf_this_cpu_ptr(p->ptr);
283 return 0;
284}
285
286SEC("?tc")
287int direct_read_lock(void *ctx)
288{
289 struct foo *f;
290
291 f = bpf_obj_new(typeof(*f));
292 if (!f)
293 return 0;
294 return *(int *)&f->lock;
295}
296
297SEC("?tc")
298int direct_write_lock(void *ctx)
299{
300 struct foo *f;
301
302 f = bpf_obj_new(typeof(*f));
303 if (!f)
304 return 0;
305 *(int *)&f->lock = 0;
306 return 0;
307}
308
309SEC("?tc")
310int direct_read_head(void *ctx)
311{
312 struct foo *f;
313
314 f = bpf_obj_new(typeof(*f));
315 if (!f)
316 return 0;
317 return *(int *)&f->head;
318}
319
320SEC("?tc")
321int direct_write_head(void *ctx)
322{
323 struct foo *f;
324
325 f = bpf_obj_new(typeof(*f));
326 if (!f)
327 return 0;
328 *(int *)&f->head = 0;
329 return 0;
330}
331
332SEC("?tc")
333int direct_read_node(void *ctx)
334{
335 struct foo *f;
336
337 f = bpf_obj_new(typeof(*f));
338 if (!f)
339 return 0;
340 return *(int *)&f->node2;
341}
342
343SEC("?tc")
344int direct_write_node(void *ctx)
345{
346 struct foo *f;
347
348 f = bpf_obj_new(typeof(*f));
349 if (!f)
350 return 0;
351 *(int *)&f->node2 = 0;
352 return 0;
353}
354
355static __always_inline
356int use_after_unlock(bool push_front)
357{
358 struct foo *f;
359
360 f = bpf_obj_new(typeof(*f));
361 if (!f)
362 return 0;
363 bpf_spin_lock(&glock);
364 f->data = 42;
365 if (push_front)
366 bpf_list_push_front(&ghead, &f->node2);
367 else
368 bpf_list_push_back(&ghead, &f->node2);
369 bpf_spin_unlock(&glock);
370
371 return f->data;
372}
373
374SEC("?tc")
375int use_after_unlock_push_front(void *ctx)
376{
377 return use_after_unlock(true);
378}
379
380SEC("?tc")
381int use_after_unlock_push_back(void *ctx)
382{
383 return use_after_unlock(false);
384}
385
386static __always_inline
387int list_double_add(bool push_front)
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 if (push_front) {
396 bpf_list_push_front(&ghead, &f->node2);
397 bpf_list_push_front(&ghead, &f->node2);
398 } else {
399 bpf_list_push_back(&ghead, &f->node2);
400 bpf_list_push_back(&ghead, &f->node2);
401 }
402 bpf_spin_unlock(&glock);
403
404 return 0;
405}
406
407SEC("?tc")
408int double_push_front(void *ctx)
409{
410 return list_double_add(true);
411}
412
413SEC("?tc")
414int double_push_back(void *ctx)
415{
416 return list_double_add(false);
417}
418
419SEC("?tc")
420int no_node_value_type(void *ctx)
421{
422 void *p;
423
424 p = bpf_obj_new(struct { int data; });
425 if (!p)
426 return 0;
427 bpf_spin_lock(&glock);
428 bpf_list_push_front(&ghead, p);
429 bpf_spin_unlock(&glock);
430
431 return 0;
432}
433
434SEC("?tc")
435int incorrect_value_type(void *ctx)
436{
437 struct bar *b;
438
439 b = bpf_obj_new(typeof(*b));
440 if (!b)
441 return 0;
442 bpf_spin_lock(&glock);
443 bpf_list_push_front(&ghead, &b->node);
444 bpf_spin_unlock(&glock);
445
446 return 0;
447}
448
449SEC("?tc")
450int incorrect_node_var_off(struct __sk_buff *ctx)
451{
452 struct foo *f;
453
454 f = bpf_obj_new(typeof(*f));
455 if (!f)
456 return 0;
457 bpf_spin_lock(&glock);
458 bpf_list_push_front(&ghead, (void *)&f->node2 + ctx->protocol);
459 bpf_spin_unlock(&glock);
460
461 return 0;
462}
463
464SEC("?tc")
465int incorrect_node_off1(void *ctx)
466{
467 struct foo *f;
468
469 f = bpf_obj_new(typeof(*f));
470 if (!f)
471 return 0;
472 bpf_spin_lock(&glock);
473 bpf_list_push_front(&ghead, (void *)&f->node2 + 1);
474 bpf_spin_unlock(&glock);
475
476 return 0;
477}
478
479SEC("?tc")
480int incorrect_node_off2(void *ctx)
481{
482 struct foo *f;
483
484 f = bpf_obj_new(typeof(*f));
485 if (!f)
486 return 0;
487 bpf_spin_lock(&glock);
488 bpf_list_push_front(&ghead, &f->node);
489 bpf_spin_unlock(&glock);
490
491 return 0;
492}
493
494SEC("?tc")
495int no_head_type(void *ctx)
496{
497 void *p;
498
499 p = bpf_obj_new(typeof(struct { int data; }));
500 if (!p)
501 return 0;
502 bpf_spin_lock(&glock);
503 bpf_list_push_front(p, NULL);
504 bpf_spin_lock(&glock);
505
506 return 0;
507}
508
509SEC("?tc")
510int incorrect_head_var_off1(struct __sk_buff *ctx)
511{
512 struct foo *f;
513
514 f = bpf_obj_new(typeof(*f));
515 if (!f)
516 return 0;
517 bpf_spin_lock(&glock);
518 bpf_list_push_front((void *)&ghead + ctx->protocol, &f->node2);
519 bpf_spin_unlock(&glock);
520
521 return 0;
522}
523
524SEC("?tc")
525int incorrect_head_var_off2(struct __sk_buff *ctx)
526{
527 struct foo *f;
528
529 f = bpf_obj_new(typeof(*f));
530 if (!f)
531 return 0;
532 bpf_spin_lock(&glock);
533 bpf_list_push_front((void *)&f->head + ctx->protocol, &f->node2);
534 bpf_spin_unlock(&glock);
535
536 return 0;
537}
538
539SEC("?tc")
540int incorrect_head_off1(void *ctx)
541{
542 struct foo *f;
543 struct bar *b;
544
545 f = bpf_obj_new(typeof(*f));
546 if (!f)
547 return 0;
548 b = bpf_obj_new(typeof(*b));
549 if (!b) {
550 bpf_obj_drop(f);
551 return 0;
552 }
553
554 bpf_spin_lock(&f->lock);
555 bpf_list_push_front((void *)&f->head + 1, &b->node);
556 bpf_spin_unlock(&f->lock);
557
558 return 0;
559}
560
561SEC("?tc")
562int incorrect_head_off2(void *ctx)
563{
564 struct foo *f;
565
566 f = bpf_obj_new(typeof(*f));
567 if (!f)
568 return 0;
569
570 bpf_spin_lock(&glock);
571 bpf_list_push_front((void *)&ghead + 1, &f->node2);
572 bpf_spin_unlock(&glock);
573
574 return 0;
575}
576
577static __always_inline
578int pop_ptr_off(void *(*op)(void *head))
579{
580 struct {
581 struct bpf_list_head head __contains(foo, node2);
582 struct bpf_spin_lock lock;
583 } *p;
584 struct bpf_list_node *n;
585
586 p = bpf_obj_new(typeof(*p));
587 if (!p)
588 return 0;
589 bpf_spin_lock(&p->lock);
590 n = op(&p->head);
591 bpf_spin_unlock(&p->lock);
592
593 if (!n)
594 return 0;
595 bpf_spin_lock((void *)n);
596 return 0;
597}
598
599SEC("?tc")
600int pop_front_off(void *ctx)
601{
602 return pop_ptr_off((void *)bpf_list_pop_front);
603}
604
605SEC("?tc")
606int pop_back_off(void *ctx)
607{
608 return pop_ptr_off((void *)bpf_list_pop_back);
609}
610
611char _license[] SEC("license") = "GPL";