xref: /linux/tools/testing/selftests/bpf/progs/verifier_async_cb_context.c (revision 14c5eb685cdefbd32e73d2723071ecbd8effbce9)
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("sleepable helper bpf_copy_from_user#{{[0-9]+}} in 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("sleepable helper bpf_copy_from_user#{{[0-9]+}} in 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 static int timer_sys_bpf_cb(void *map, int *key, struct bpf_timer *timer)
66 {
67 	__u64 attr = 0;
68 
69 	bpf_sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr));
70 	return 0;
71 }
72 
73 SEC("syscall")
74 __failure __msg("sleepable helper bpf_sys_bpf#{{[0-9]+}} in non-sleepable prog")
75 int timer_sys_bpf_prog(void *ctx)
76 {
77 	struct timer_elem *val;
78 	int key = 0;
79 
80 	val = bpf_map_lookup_elem(&timer_map, &key);
81 	if (!val)
82 		return 0;
83 
84 	bpf_timer_init(&val->t, &timer_map, 0);
85 	bpf_timer_set_callback(&val->t, timer_sys_bpf_cb);
86 	return 0;
87 }
88 
89 static int timer_sys_close_cb(void *map, int *key, struct bpf_timer *timer)
90 {
91 	bpf_sys_close(0);
92 	return 0;
93 }
94 
95 SEC("syscall")
96 __failure __msg("sleepable helper bpf_sys_close#{{[0-9]+}} in non-sleepable prog")
97 int timer_sys_close_prog(void *ctx)
98 {
99 	struct timer_elem *val;
100 	int key = 0;
101 
102 	val = bpf_map_lookup_elem(&timer_map, &key);
103 	if (!val)
104 		return 0;
105 
106 	bpf_timer_init(&val->t, &timer_map, 0);
107 	bpf_timer_set_callback(&val->t, timer_sys_close_cb);
108 	return 0;
109 }
110 
111 static int timer_btf_find_cb(void *map, int *key, struct bpf_timer *timer)
112 {
113 	char name[] = "task_struct";
114 
115 	bpf_btf_find_by_name_kind(name, sizeof(name), BTF_KIND_STRUCT, 0);
116 	return 0;
117 }
118 
119 SEC("syscall")
120 __failure __msg("sleepable helper bpf_btf_find_by_name_kind#{{[0-9]+}} in non-sleepable prog")
121 int timer_btf_find_prog(void *ctx)
122 {
123 	struct timer_elem *val;
124 	int key = 0;
125 
126 	val = bpf_map_lookup_elem(&timer_map, &key);
127 	if (!val)
128 		return 0;
129 
130 	bpf_timer_init(&val->t, &timer_map, 0);
131 	bpf_timer_set_callback(&val->t, timer_btf_find_cb);
132 	return 0;
133 }
134 
135 SEC("syscall")
136 __success
137 int syscall_sys_bpf_prog(void *ctx)
138 {
139 	__u64 attr = 0;
140 
141 	bpf_sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr));
142 	return 0;
143 }
144 
145 SEC("syscall")
146 __success
147 int syscall_sys_close_prog(void *ctx)
148 {
149 	bpf_sys_close(0);
150 	return 0;
151 }
152 
153 SEC("syscall")
154 __success
155 int syscall_btf_find_prog(void *ctx)
156 {
157 	char name[] = "task_struct";
158 
159 	bpf_btf_find_by_name_kind(name, sizeof(name), BTF_KIND_STRUCT, 0);
160 	return 0;
161 }
162 
163 /* Workqueue tests */
164 
165 struct wq_elem {
166 	struct bpf_wq w;
167 };
168 
169 struct {
170 	__uint(type, BPF_MAP_TYPE_ARRAY);
171 	__uint(max_entries, 1);
172 	__type(key, int);
173 	__type(value, struct wq_elem);
174 } wq_map SEC(".maps");
175 
176 static int wq_cb(void *map, int *key, void *value)
177 {
178 	u32 data;
179 	/* Workqueue callbacks are always sleepable, even from non-sleepable programs */
180 	bpf_copy_from_user(&data, sizeof(data), NULL);
181 	return 0;
182 }
183 
184 SEC("fentry/bpf_fentry_test1")
185 __success
186 int wq_non_sleepable_prog(void *ctx)
187 {
188 	struct wq_elem *val;
189 	int key = 0;
190 
191 	val = bpf_map_lookup_elem(&wq_map, &key);
192 	if (!val)
193 		return 0;
194 
195 	if (bpf_wq_init(&val->w, &wq_map, 0) != 0)
196 		return 0;
197 	if (bpf_wq_set_callback(&val->w, wq_cb, 0) != 0)
198 		return 0;
199 	return 0;
200 }
201 
202 SEC("lsm.s/file_open")
203 __success
204 int wq_sleepable_prog(void *ctx)
205 {
206 	struct wq_elem *val;
207 	int key = 0;
208 
209 	val = bpf_map_lookup_elem(&wq_map, &key);
210 	if (!val)
211 		return 0;
212 
213 	if (bpf_wq_init(&val->w, &wq_map, 0) != 0)
214 		return 0;
215 	if (bpf_wq_set_callback(&val->w, wq_cb, 0) != 0)
216 		return 0;
217 	return 0;
218 }
219 
220 /* Task work tests */
221 
222 struct task_work_elem {
223 	struct bpf_task_work tw;
224 };
225 
226 struct {
227 	__uint(type, BPF_MAP_TYPE_ARRAY);
228 	__uint(max_entries, 1);
229 	__type(key, int);
230 	__type(value, struct task_work_elem);
231 } task_work_map SEC(".maps");
232 
233 static int task_work_cb(struct bpf_map *map, void *key, void *value)
234 {
235 	u32 data;
236 	/* Task work callbacks are always sleepable, even from non-sleepable programs */
237 	bpf_copy_from_user(&data, sizeof(data), NULL);
238 	return 0;
239 }
240 
241 SEC("fentry/bpf_fentry_test1")
242 __success
243 int task_work_non_sleepable_prog(void *ctx)
244 {
245 	struct task_work_elem *val;
246 	struct task_struct *task;
247 	int key = 0;
248 
249 	val = bpf_map_lookup_elem(&task_work_map, &key);
250 	if (!val)
251 		return 0;
252 
253 	task = bpf_get_current_task_btf();
254 	if (!task)
255 		return 0;
256 
257 	bpf_task_work_schedule_resume(task, &val->tw, &task_work_map, task_work_cb);
258 	return 0;
259 }
260 
261 SEC("lsm.s/file_open")
262 __success
263 int task_work_sleepable_prog(void *ctx)
264 {
265 	struct task_work_elem *val;
266 	struct task_struct *task;
267 	int key = 0;
268 
269 	val = bpf_map_lookup_elem(&task_work_map, &key);
270 	if (!val)
271 		return 0;
272 
273 	task = bpf_get_current_task_btf();
274 	if (!task)
275 		return 0;
276 
277 	bpf_task_work_schedule_resume(task, &val->tw, &task_work_map, task_work_cb);
278 	return 0;
279 }
280