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