]> Git Repo - linux.git/blob - tools/testing/selftests/bpf/progs/linked_list_fail.c
Linux 6.14-rc3
[linux.git] / tools / testing / selftests / bpf / progs / linked_list_fail.c
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")
171 int map_compat_kprobe(void *ctx)
172 {
173         bpf_list_push_front(&ghead, NULL);
174         return 0;
175 }
176
177 SEC("?kretprobe/xyz")
178 int map_compat_kretprobe(void *ctx)
179 {
180         bpf_list_push_front(&ghead, NULL);
181         return 0;
182 }
183
184 SEC("?tracepoint/xyz")
185 int map_compat_tp(void *ctx)
186 {
187         bpf_list_push_front(&ghead, NULL);
188         return 0;
189 }
190
191 SEC("?perf_event")
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")
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")
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")
213 int obj_type_id_oor(void *ctx)
214 {
215         bpf_obj_new_impl(~0UL, NULL);
216         return 0;
217 }
218
219 SEC("?tc")
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")
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")
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")
247 int new_null_ret(void *ctx)
248 {
249         return bpf_obj_new(struct foo)->data;
250 }
251
252 SEC("?tc")
253 int obj_new_acq(void *ctx)
254 {
255         bpf_obj_new(struct foo);
256         return 0;
257 }
258
259 SEC("?tc")
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")
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")
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")
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")
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")
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")
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")
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
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")
376 int use_after_unlock_push_front(void *ctx)
377 {
378         return use_after_unlock(true);
379 }
380
381 SEC("?tc")
382 int use_after_unlock_push_back(void *ctx)
383 {
384         return use_after_unlock(false);
385 }
386
387 static __always_inline
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")
409 int double_push_front(void *ctx)
410 {
411         return list_double_add(true);
412 }
413
414 SEC("?tc")
415 int double_push_back(void *ctx)
416 {
417         return list_double_add(false);
418 }
419
420 SEC("?tc")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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
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")
601 int pop_front_off(void *ctx)
602 {
603         return pop_ptr_off((void *)bpf_list_pop_front);
604 }
605
606 SEC("?tc")
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";
This page took 0.084558 seconds and 4 git commands to generate.