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")
173 int map_compat_kprobe(void *ctx)
174 {
175 	bpf_list_push_front(&ghead, NULL);
176 	return 0;
177 }
178 
179 SEC("?kretprobe/xyz")
180 int map_compat_kretprobe(void *ctx)
181 {
182 	bpf_list_push_front(&ghead, NULL);
183 	return 0;
184 }
185 
186 SEC("?tracepoint/xyz")
187 int map_compat_tp(void *ctx)
188 {
189 	bpf_list_push_front(&ghead, NULL);
190 	return 0;
191 }
192 
193 SEC("?perf_event")
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")
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")
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")
215 int obj_type_id_oor(void *ctx)
216 {
217 	bpf_obj_new_impl(~0UL, NULL);
218 	return 0;
219 }
220 
221 SEC("?tc")
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")
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")
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")
249 int new_null_ret(void *ctx)
250 {
251 	return bpf_obj_new(struct foo)->data;
252 }
253 
254 SEC("?tc")
255 int obj_new_acq(void *ctx)
256 {
257 	bpf_obj_new(struct foo);
258 	return 0;
259 }
260 
261 SEC("?tc")
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")
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")
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")
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")
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")
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")
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")
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
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")
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")
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
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")
403 int double_push_front(void *ctx)
404 {
405 	return list_double_add((void *)bpf_list_push_front);
406 }
407 
408 SEC("?tc")
409 int double_push_back(void *ctx)
410 {
411 	return list_double_add((void *)bpf_list_push_back);
412 }
413 
414 SEC("?tc")
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")
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")
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")
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")
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")
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")
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")
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")
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")
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
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")
594 int pop_front_off(void *ctx)
595 {
596 	return pop_ptr_off((void *)bpf_list_pop_front);
597 }
598 
599 SEC("?tc")
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