xref: /linux/tools/testing/selftests/bpf/progs/verifier_async_cb_context.c (revision 17566cf0e3629728b692e35213a4fd6ea9f86150)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3 
4 #include <vmlinux.h>
5 #include <bpf/bpf_helpers.h>
6 #include <bpf/bpf_tracing.h>
7 #include "bpf_misc.h"
8 #include "bpf_experimental.h"
9 
10 char _license[] SEC("license") = "GPL";
11 
12 /* Timer tests */
13 
14 struct timer_elem {
15 	struct bpf_timer t;
16 };
17 
18 struct {
19 	__uint(type, BPF_MAP_TYPE_ARRAY);
20 	__uint(max_entries, 1);
21 	__type(key, int);
22 	__type(value, struct timer_elem);
23 } timer_map SEC(".maps");
24 
25 static int timer_cb(void *map, int *key, struct bpf_timer *timer)
26 {
27 	u32 data;
28 	/* Timer callbacks are never sleepable, even from non-sleepable programs */
29 	bpf_copy_from_user(&data, sizeof(data), NULL);
30 	return 0;
31 }
32 
33 SEC("fentry/bpf_fentry_test1")
34 __failure __msg("helper call might sleep in a non-sleepable prog")
35 int timer_non_sleepable_prog(void *ctx)
36 {
37 	struct timer_elem *val;
38 	int key = 0;
39 
40 	val = bpf_map_lookup_elem(&timer_map, &key);
41 	if (!val)
42 		return 0;
43 
44 	bpf_timer_init(&val->t, &timer_map, 0);
45 	bpf_timer_set_callback(&val->t, timer_cb);
46 	return 0;
47 }
48 
49 SEC("lsm.s/file_open")
50 __failure __msg("helper call might sleep in a non-sleepable prog")
51 int timer_sleepable_prog(void *ctx)
52 {
53 	struct timer_elem *val;
54 	int key = 0;
55 
56 	val = bpf_map_lookup_elem(&timer_map, &key);
57 	if (!val)
58 		return 0;
59 
60 	bpf_timer_init(&val->t, &timer_map, 0);
61 	bpf_timer_set_callback(&val->t, timer_cb);
62 	return 0;
63 }
64 
65 /* Workqueue tests */
66 
67 struct wq_elem {
68 	struct bpf_wq w;
69 };
70 
71 struct {
72 	__uint(type, BPF_MAP_TYPE_ARRAY);
73 	__uint(max_entries, 1);
74 	__type(key, int);
75 	__type(value, struct wq_elem);
76 } wq_map SEC(".maps");
77 
78 static int wq_cb(void *map, int *key, void *value)
79 {
80 	u32 data;
81 	/* Workqueue callbacks are always sleepable, even from non-sleepable programs */
82 	bpf_copy_from_user(&data, sizeof(data), NULL);
83 	return 0;
84 }
85 
86 SEC("fentry/bpf_fentry_test1")
87 __success
88 int wq_non_sleepable_prog(void *ctx)
89 {
90 	struct wq_elem *val;
91 	int key = 0;
92 
93 	val = bpf_map_lookup_elem(&wq_map, &key);
94 	if (!val)
95 		return 0;
96 
97 	if (bpf_wq_init(&val->w, &wq_map, 0) != 0)
98 		return 0;
99 	if (bpf_wq_set_callback_impl(&val->w, wq_cb, 0, NULL) != 0)
100 		return 0;
101 	return 0;
102 }
103 
104 SEC("lsm.s/file_open")
105 __success
106 int wq_sleepable_prog(void *ctx)
107 {
108 	struct wq_elem *val;
109 	int key = 0;
110 
111 	val = bpf_map_lookup_elem(&wq_map, &key);
112 	if (!val)
113 		return 0;
114 
115 	if (bpf_wq_init(&val->w, &wq_map, 0) != 0)
116 		return 0;
117 	if (bpf_wq_set_callback_impl(&val->w, wq_cb, 0, NULL) != 0)
118 		return 0;
119 	return 0;
120 }
121 
122 /* Task work tests */
123 
124 struct task_work_elem {
125 	struct bpf_task_work tw;
126 };
127 
128 struct {
129 	__uint(type, BPF_MAP_TYPE_ARRAY);
130 	__uint(max_entries, 1);
131 	__type(key, int);
132 	__type(value, struct task_work_elem);
133 } task_work_map SEC(".maps");
134 
135 static int task_work_cb(struct bpf_map *map, void *key, void *value)
136 {
137 	u32 data;
138 	/* Task work callbacks are always sleepable, even from non-sleepable programs */
139 	bpf_copy_from_user(&data, sizeof(data), NULL);
140 	return 0;
141 }
142 
143 SEC("fentry/bpf_fentry_test1")
144 __success
145 int task_work_non_sleepable_prog(void *ctx)
146 {
147 	struct task_work_elem *val;
148 	struct task_struct *task;
149 	int key = 0;
150 
151 	val = bpf_map_lookup_elem(&task_work_map, &key);
152 	if (!val)
153 		return 0;
154 
155 	task = bpf_get_current_task_btf();
156 	if (!task)
157 		return 0;
158 
159 	bpf_task_work_schedule_resume(task, &val->tw, &task_work_map, task_work_cb, NULL);
160 	return 0;
161 }
162 
163 SEC("lsm.s/file_open")
164 __success
165 int task_work_sleepable_prog(void *ctx)
166 {
167 	struct task_work_elem *val;
168 	struct task_struct *task;
169 	int key = 0;
170 
171 	val = bpf_map_lookup_elem(&task_work_map, &key);
172 	if (!val)
173 		return 0;
174 
175 	task = bpf_get_current_task_btf();
176 	if (!task)
177 		return 0;
178 
179 	bpf_task_work_schedule_resume(task, &val->tw, &task_work_map, task_work_cb, NULL);
180 	return 0;
181 }
182