File Index
Files and directories
Sign in
FILE

linked_list_fail.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/progs/linked_list_fail.c C
  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
 57CHECK(kptr, pop_front, &f->head);
 58CHECK(kptr, pop_back, &f->head);
 59
 60CHECK(global, pop_front, &ghead);
 61CHECK(global, pop_back, &ghead);
 62
 63CHECK(map, pop_front, &v->head);
 64CHECK(map, pop_back, &v->head);
 65
 66CHECK(inner_map, pop_front, &iv->head);
 67CHECK(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
 80CHECK(kptr, push_front, &f->head, &b->node);
 81CHECK(kptr, push_back, &f->head, &b->node);
 82
 83CHECK(global, push_front, &ghead, &f->node2);
 84CHECK(global, push_back, &ghead, &f->node2);
 85
 86CHECK(map, push_front, &v->head, &f->node2);
 87CHECK(map, push_back, &v->head, &f->node2);
 88
 89CHECK(inner_map, push_front, &iv->head, &f->node2);
 90CHECK(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
126CHECK_OP(pop_front);
127CHECK_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
163CHECK_OP(push_front);
164CHECK_OP(push_back);
165
166#undef CHECK
167#undef CHECK_OP
168#undef INIT
169
170SEC("?kprobe/xyz")
171int map_compat_kprobe(void *ctx)
172{
173	bpf_list_push_front(&ghead, NULL);
174	return 0;
175}
176
177SEC("?kretprobe/xyz")
178int map_compat_kretprobe(void *ctx)
179{
180	bpf_list_push_front(&ghead, NULL);
181	return 0;
182}
183
184SEC("?tracepoint/xyz")
185int map_compat_tp(void *ctx)
186{
187	bpf_list_push_front(&ghead, NULL);
188	return 0;
189}
190
191SEC("?perf_event")
192int map_compat_perf(void *ctx)
193{
194	bpf_list_push_front(&ghead, NULL);
195	return 0;
196}
197
198SEC("?raw_tp/xyz")
199int map_compat_raw_tp(void *ctx)
200{
201	bpf_list_push_front(&ghead, NULL);
202	return 0;
203}
204
205SEC("?raw_tp.w/xyz")
206int map_compat_raw_tp_w(void *ctx)
207{
208	bpf_list_push_front(&ghead, NULL);
209	return 0;
210}
211
212SEC("?tc")
213int obj_type_id_oor(void *ctx)
214{
215	bpf_obj_new_impl(~0UL, NULL);
216	return 0;
217}
218
219SEC("?tc")
220int 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
226SEC("?tc")
227int obj_new_no_struct(void *ctx)
228{
229	(void)bpf_obj_new(union { int data; unsigned udata; });
230	return 0;
231}
232
233SEC("?tc")
234int 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
245SEC("?tc")
246int new_null_ret(void *ctx)
247{
248	return bpf_obj_new(struct foo)->data;
249}
250
251SEC("?tc")
252int obj_new_acq(void *ctx)
253{
254	(void)bpf_obj_new(struct foo);
255	return 0;
256}
257
258SEC("?tc")
259int 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
270SEC("?tc")
271int 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
286SEC("?tc")
287int 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
297SEC("?tc")
298int 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
309SEC("?tc")
310int 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
320SEC("?tc")
321int 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
332SEC("?tc")
333int 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
343SEC("?tc")
344int 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
355static __always_inline
356int 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
374SEC("?tc")
375int use_after_unlock_push_front(void *ctx)
376{
377	return use_after_unlock(true);
378}
379
380SEC("?tc")
381int use_after_unlock_push_back(void *ctx)
382{
383	return use_after_unlock(false);
384}
385
386static __always_inline
387int 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
407SEC("?tc")
408int double_push_front(void *ctx)
409{
410	return list_double_add(true);
411}
412
413SEC("?tc")
414int double_push_back(void *ctx)
415{
416	return list_double_add(false);
417}
418
419SEC("?tc")
420int 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
434SEC("?tc")
435int 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
449SEC("?tc")
450int 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
464SEC("?tc")
465int 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
479SEC("?tc")
480int 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
494SEC("?tc")
495int 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
509SEC("?tc")
510int 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
524SEC("?tc")
525int 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
539SEC("?tc")
540int 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
561SEC("?tc")
562int 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
577static __always_inline
578int 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
599SEC("?tc")
600int pop_front_off(void *ctx)
601{
602	return pop_ptr_off((void *)bpf_list_pop_front);
603}
604
605SEC("?tc")
606int pop_back_off(void *ctx)
607{
608	return pop_ptr_off((void *)bpf_list_pop_back);
609}
610
611char _license[] SEC("license") = "GPL";
~/ Read-only file preview.