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, push_front, &f->head);
58 CHECK(kptr, push_back, &f->head);
59 CHECK(kptr, pop_front, &f->head);
60 CHECK(kptr, pop_back, &f->head);
61 
62 CHECK(global, push_front, &ghead);
63 CHECK(global, push_back, &ghead);
64 CHECK(global, pop_front, &ghead);
65 CHECK(global, pop_back, &ghead);
66 
67 CHECK(map, push_front, &v->head);
68 CHECK(map, push_back, &v->head);
69 CHECK(map, pop_front, &v->head);
70 CHECK(map, pop_back, &v->head);
71 
72 CHECK(inner_map, push_front, &iv->head);
73 CHECK(inner_map, push_back, &iv->head);
74 CHECK(inner_map, pop_front, &iv->head);
75 CHECK(inner_map, pop_back, &iv->head);
76 
77 #undef CHECK
78 
79 #define CHECK(test, op, lexpr, hexpr)                       \
80 	SEC("?tc")                                          \
81 	int test##_incorrect_lock_##op(void *ctx)           \
82 	{                                                   \
83 		INIT;                                       \
84 		void (*p)(void *) = (void *)&bpf_list_##op; \
85 		bpf_spin_lock(lexpr);                       \
86 		p(hexpr);                                   \
87 		return 0;                                   \
88 	}
89 
90 #define CHECK_OP(op)                                           \
91 	CHECK(kptr_kptr, op, &f1->lock, &f2->head);            \
92 	CHECK(kptr_global, op, &f1->lock, &ghead);             \
93 	CHECK(kptr_map, op, &f1->lock, &v->head);              \
94 	CHECK(kptr_inner_map, op, &f1->lock, &iv->head);       \
95                                                                \
96 	CHECK(global_global, op, &glock2, &ghead);             \
97 	CHECK(global_kptr, op, &glock, &f1->head);             \
98 	CHECK(global_map, op, &glock, &v->head);               \
99 	CHECK(global_inner_map, op, &glock, &iv->head);        \
100                                                                \
101 	CHECK(map_map, op, &v->lock, &v2->head);               \
102 	CHECK(map_kptr, op, &v->lock, &f2->head);              \
103 	CHECK(map_global, op, &v->lock, &ghead);               \
104 	CHECK(map_inner_map, op, &v->lock, &iv->head);         \
105                                                                \
106 	CHECK(inner_map_inner_map, op, &iv->lock, &iv2->head); \
107 	CHECK(inner_map_kptr, op, &iv->lock, &f2->head);       \
108 	CHECK(inner_map_global, op, &iv->lock, &ghead);        \
109 	CHECK(inner_map_map, op, &iv->lock, &v->head);
110 
111 CHECK_OP(push_front);
112 CHECK_OP(push_back);
113 CHECK_OP(pop_front);
114 CHECK_OP(pop_back);
115 
116 #undef CHECK
117 #undef CHECK_OP
118 #undef INIT
119 
120 SEC("?kprobe/xyz")
121 int map_compat_kprobe(void *ctx)
122 {
123 	bpf_list_push_front(&ghead, NULL);
124 	return 0;
125 }
126 
127 SEC("?kretprobe/xyz")
128 int map_compat_kretprobe(void *ctx)
129 {
130 	bpf_list_push_front(&ghead, NULL);
131 	return 0;
132 }
133 
134 SEC("?tracepoint/xyz")
135 int map_compat_tp(void *ctx)
136 {
137 	bpf_list_push_front(&ghead, NULL);
138 	return 0;
139 }
140 
141 SEC("?perf_event")
142 int map_compat_perf(void *ctx)
143 {
144 	bpf_list_push_front(&ghead, NULL);
145 	return 0;
146 }
147 
148 SEC("?raw_tp/xyz")
149 int map_compat_raw_tp(void *ctx)
150 {
151 	bpf_list_push_front(&ghead, NULL);
152 	return 0;
153 }
154 
155 SEC("?raw_tp.w/xyz")
156 int map_compat_raw_tp_w(void *ctx)
157 {
158 	bpf_list_push_front(&ghead, NULL);
159 	return 0;
160 }
161 
162 SEC("?tc")
163 int obj_type_id_oor(void *ctx)
164 {
165 	bpf_obj_new_impl(~0UL, NULL);
166 	return 0;
167 }
168 
169 SEC("?tc")
170 int obj_new_no_composite(void *ctx)
171 {
172 	bpf_obj_new_impl(bpf_core_type_id_local(int), (void *)42);
173 	return 0;
174 }
175 
176 SEC("?tc")
177 int obj_new_no_struct(void *ctx)
178 {
179 
180 	bpf_obj_new(union { int data; unsigned udata; });
181 	return 0;
182 }
183 
184 SEC("?tc")
185 int obj_drop_non_zero_off(void *ctx)
186 {
187 	void *f;
188 
189 	f = bpf_obj_new(struct foo);
190 	if (!f)
191 		return 0;
192 	bpf_obj_drop(f+1);
193 	return 0;
194 }
195 
196 SEC("?tc")
197 int new_null_ret(void *ctx)
198 {
199 	return bpf_obj_new(struct foo)->data;
200 }
201 
202 SEC("?tc")
203 int obj_new_acq(void *ctx)
204 {
205 	bpf_obj_new(struct foo);
206 	return 0;
207 }
208 
209 SEC("?tc")
210 int use_after_drop(void *ctx)
211 {
212 	struct foo *f;
213 
214 	f = bpf_obj_new(typeof(*f));
215 	if (!f)
216 		return 0;
217 	bpf_obj_drop(f);
218 	return f->data;
219 }
220 
221 SEC("?tc")
222 int ptr_walk_scalar(void *ctx)
223 {
224 	struct test1 {
225 		struct test2 {
226 			struct test2 *next;
227 		} *ptr;
228 	} *p;
229 
230 	p = bpf_obj_new(typeof(*p));
231 	if (!p)
232 		return 0;
233 	bpf_this_cpu_ptr(p->ptr);
234 	return 0;
235 }
236 
237 SEC("?tc")
238 int direct_read_lock(void *ctx)
239 {
240 	struct foo *f;
241 
242 	f = bpf_obj_new(typeof(*f));
243 	if (!f)
244 		return 0;
245 	return *(int *)&f->lock;
246 }
247 
248 SEC("?tc")
249 int direct_write_lock(void *ctx)
250 {
251 	struct foo *f;
252 
253 	f = bpf_obj_new(typeof(*f));
254 	if (!f)
255 		return 0;
256 	*(int *)&f->lock = 0;
257 	return 0;
258 }
259 
260 SEC("?tc")
261 int direct_read_head(void *ctx)
262 {
263 	struct foo *f;
264 
265 	f = bpf_obj_new(typeof(*f));
266 	if (!f)
267 		return 0;
268 	return *(int *)&f->head;
269 }
270 
271 SEC("?tc")
272 int direct_write_head(void *ctx)
273 {
274 	struct foo *f;
275 
276 	f = bpf_obj_new(typeof(*f));
277 	if (!f)
278 		return 0;
279 	*(int *)&f->head = 0;
280 	return 0;
281 }
282 
283 SEC("?tc")
284 int direct_read_node(void *ctx)
285 {
286 	struct foo *f;
287 
288 	f = bpf_obj_new(typeof(*f));
289 	if (!f)
290 		return 0;
291 	return *(int *)&f->node;
292 }
293 
294 SEC("?tc")
295 int direct_write_node(void *ctx)
296 {
297 	struct foo *f;
298 
299 	f = bpf_obj_new(typeof(*f));
300 	if (!f)
301 		return 0;
302 	*(int *)&f->node = 0;
303 	return 0;
304 }
305 
306 static __always_inline
307 int write_after_op(void (*push_op)(void *head, void *node))
308 {
309 	struct foo *f;
310 
311 	f = bpf_obj_new(typeof(*f));
312 	if (!f)
313 		return 0;
314 	bpf_spin_lock(&glock);
315 	push_op(&ghead, &f->node);
316 	f->data = 42;
317 	bpf_spin_unlock(&glock);
318 
319 	return 0;
320 }
321 
322 SEC("?tc")
323 int write_after_push_front(void *ctx)
324 {
325 	return write_after_op((void *)bpf_list_push_front);
326 }
327 
328 SEC("?tc")
329 int write_after_push_back(void *ctx)
330 {
331 	return write_after_op((void *)bpf_list_push_back);
332 }
333 
334 static __always_inline
335 int use_after_unlock(void (*op)(void *head, void *node))
336 {
337 	struct foo *f;
338 
339 	f = bpf_obj_new(typeof(*f));
340 	if (!f)
341 		return 0;
342 	bpf_spin_lock(&glock);
343 	f->data = 42;
344 	op(&ghead, &f->node);
345 	bpf_spin_unlock(&glock);
346 
347 	return f->data;
348 }
349 
350 SEC("?tc")
351 int use_after_unlock_push_front(void *ctx)
352 {
353 	return use_after_unlock((void *)bpf_list_push_front);
354 }
355 
356 SEC("?tc")
357 int use_after_unlock_push_back(void *ctx)
358 {
359 	return use_after_unlock((void *)bpf_list_push_back);
360 }
361 
362 static __always_inline
363 int list_double_add(void (*op)(void *head, void *node))
364 {
365 	struct foo *f;
366 
367 	f = bpf_obj_new(typeof(*f));
368 	if (!f)
369 		return 0;
370 	bpf_spin_lock(&glock);
371 	op(&ghead, &f->node);
372 	op(&ghead, &f->node);
373 	bpf_spin_unlock(&glock);
374 
375 	return 0;
376 }
377 
378 SEC("?tc")
379 int double_push_front(void *ctx)
380 {
381 	return list_double_add((void *)bpf_list_push_front);
382 }
383 
384 SEC("?tc")
385 int double_push_back(void *ctx)
386 {
387 	return list_double_add((void *)bpf_list_push_back);
388 }
389 
390 SEC("?tc")
391 int no_node_value_type(void *ctx)
392 {
393 	void *p;
394 
395 	p = bpf_obj_new(struct { int data; });
396 	if (!p)
397 		return 0;
398 	bpf_spin_lock(&glock);
399 	bpf_list_push_front(&ghead, p);
400 	bpf_spin_unlock(&glock);
401 
402 	return 0;
403 }
404 
405 SEC("?tc")
406 int incorrect_value_type(void *ctx)
407 {
408 	struct bar *b;
409 
410 	b = bpf_obj_new(typeof(*b));
411 	if (!b)
412 		return 0;
413 	bpf_spin_lock(&glock);
414 	bpf_list_push_front(&ghead, &b->node);
415 	bpf_spin_unlock(&glock);
416 
417 	return 0;
418 }
419 
420 SEC("?tc")
421 int incorrect_node_var_off(struct __sk_buff *ctx)
422 {
423 	struct foo *f;
424 
425 	f = bpf_obj_new(typeof(*f));
426 	if (!f)
427 		return 0;
428 	bpf_spin_lock(&glock);
429 	bpf_list_push_front(&ghead, (void *)&f->node + ctx->protocol);
430 	bpf_spin_unlock(&glock);
431 
432 	return 0;
433 }
434 
435 SEC("?tc")
436 int incorrect_node_off1(void *ctx)
437 {
438 	struct foo *f;
439 
440 	f = bpf_obj_new(typeof(*f));
441 	if (!f)
442 		return 0;
443 	bpf_spin_lock(&glock);
444 	bpf_list_push_front(&ghead, (void *)&f->node + 1);
445 	bpf_spin_unlock(&glock);
446 
447 	return 0;
448 }
449 
450 SEC("?tc")
451 int incorrect_node_off2(void *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, &f->node2);
460 	bpf_spin_unlock(&glock);
461 
462 	return 0;
463 }
464 
465 SEC("?tc")
466 int no_head_type(void *ctx)
467 {
468 	void *p;
469 
470 	p = bpf_obj_new(typeof(struct { int data; }));
471 	if (!p)
472 		return 0;
473 	bpf_spin_lock(&glock);
474 	bpf_list_push_front(p, NULL);
475 	bpf_spin_lock(&glock);
476 
477 	return 0;
478 }
479 
480 SEC("?tc")
481 int incorrect_head_var_off1(struct __sk_buff *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((void *)&ghead + ctx->protocol, &f->node);
490 	bpf_spin_unlock(&glock);
491 
492 	return 0;
493 }
494 
495 SEC("?tc")
496 int incorrect_head_var_off2(struct __sk_buff *ctx)
497 {
498 	struct foo *f;
499 
500 	f = bpf_obj_new(typeof(*f));
501 	if (!f)
502 		return 0;
503 	bpf_spin_lock(&glock);
504 	bpf_list_push_front((void *)&f->head + ctx->protocol, &f->node);
505 	bpf_spin_unlock(&glock);
506 
507 	return 0;
508 }
509 
510 SEC("?tc")
511 int incorrect_head_off1(void *ctx)
512 {
513 	struct foo *f;
514 	struct bar *b;
515 
516 	f = bpf_obj_new(typeof(*f));
517 	if (!f)
518 		return 0;
519 	b = bpf_obj_new(typeof(*b));
520 	if (!b) {
521 		bpf_obj_drop(f);
522 		return 0;
523 	}
524 
525 	bpf_spin_lock(&f->lock);
526 	bpf_list_push_front((void *)&f->head + 1, &b->node);
527 	bpf_spin_unlock(&f->lock);
528 
529 	return 0;
530 }
531 
532 SEC("?tc")
533 int incorrect_head_off2(void *ctx)
534 {
535 	struct foo *f;
536 	struct bar *b;
537 
538 	f = bpf_obj_new(typeof(*f));
539 	if (!f)
540 		return 0;
541 
542 	bpf_spin_lock(&glock);
543 	bpf_list_push_front((void *)&ghead + 1, &f->node);
544 	bpf_spin_unlock(&glock);
545 
546 	return 0;
547 }
548 
549 static __always_inline
550 int pop_ptr_off(void *(*op)(void *head))
551 {
552 	struct {
553 		struct bpf_list_head head __contains(foo, node2);
554 		struct bpf_spin_lock lock;
555 	} *p;
556 	struct bpf_list_node *n;
557 
558 	p = bpf_obj_new(typeof(*p));
559 	if (!p)
560 		return 0;
561 	bpf_spin_lock(&p->lock);
562 	n = op(&p->head);
563 	bpf_spin_unlock(&p->lock);
564 
565 	bpf_this_cpu_ptr(n);
566 	return 0;
567 }
568 
569 SEC("?tc")
570 int pop_front_off(void *ctx)
571 {
572 	return pop_ptr_off((void *)bpf_list_pop_front);
573 }
574 
575 SEC("?tc")
576 int pop_back_off(void *ctx)
577 {
578 	return pop_ptr_off((void *)bpf_list_pop_back);
579 }
580 
581 char _license[] SEC("license") = "GPL";
582