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 	bpf_this_cpu_ptr(n);
595 	return 0;
596 }
597 
598 SEC("?tc")
599 int pop_front_off(void *ctx)
600 {
601 	return pop_ptr_off((void *)bpf_list_pop_front);
602 }
603 
604 SEC("?tc")
605 int pop_back_off(void *ctx)
606 {
607 	return pop_ptr_off((void *)bpf_list_pop_back);
608 }
609 
610 char _license[] SEC("license") = "GPL";
611