xref: /linux/tools/testing/selftests/bpf/progs/linked_list_fail.c (revision 35758b0032c056cdff3e8f5a70669cb3e2c8d0e4)
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 	(void)bpf_obj_new(union { int data; unsigned udata; });
230 	return 0;
231 }
232 
233 SEC("?tc")
234 int 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 
245 SEC("?tc")
246 int new_null_ret(void *ctx)
247 {
248 	return bpf_obj_new(struct foo)->data;
249 }
250 
251 SEC("?tc")
252 int obj_new_acq(void *ctx)
253 {
254 	(void)bpf_obj_new(struct foo);
255 	return 0;
256 }
257 
258 SEC("?tc")
259 int 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 
270 SEC("?tc")
271 int 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 
286 SEC("?tc")
287 int 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 
297 SEC("?tc")
298 int 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 
309 SEC("?tc")
310 int 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 
320 SEC("?tc")
321 int 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 
332 SEC("?tc")
333 int 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 
343 SEC("?tc")
344 int 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 
355 static __always_inline
356 int 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 
374 SEC("?tc")
375 int use_after_unlock_push_front(void *ctx)
376 {
377 	return use_after_unlock(true);
378 }
379 
380 SEC("?tc")
381 int use_after_unlock_push_back(void *ctx)
382 {
383 	return use_after_unlock(false);
384 }
385 
386 static __always_inline
387 int 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 
407 SEC("?tc")
408 int double_push_front(void *ctx)
409 {
410 	return list_double_add(true);
411 }
412 
413 SEC("?tc")
414 int double_push_back(void *ctx)
415 {
416 	return list_double_add(false);
417 }
418 
419 SEC("?tc")
420 int 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 
434 SEC("?tc")
435 int 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 
449 SEC("?tc")
450 int 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 
464 SEC("?tc")
465 int 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 
479 SEC("?tc")
480 int 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 
494 SEC("?tc")
495 int 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 
509 SEC("?tc")
510 int 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 
524 SEC("?tc")
525 int 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 
539 SEC("?tc")
540 int 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 
561 SEC("?tc")
562 int 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 
577 static __always_inline
578 int 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 
599 SEC("?tc")
600 int pop_front_off(void *ctx)
601 {
602 	return pop_ptr_off((void *)bpf_list_pop_front);
603 }
604 
605 SEC("?tc")
606 int pop_back_off(void *ctx)
607 {
608 	return pop_ptr_off((void *)bpf_list_pop_back);
609 }
610 
611 char _license[] SEC("license") = "GPL";
612