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
timer_cb(void * map,int * key,struct bpf_timer * timer)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")
timer_non_sleepable_prog(void * ctx)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")
timer_sleepable_prog(void * ctx)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
timer_sys_bpf_cb(void * map,int * key,struct bpf_timer * timer)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")
timer_sys_bpf_prog(void * ctx)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
timer_sys_close_cb(void * map,int * key,struct bpf_timer * timer)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")
timer_sys_close_prog(void * ctx)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
timer_btf_find_cb(void * map,int * key,struct bpf_timer * timer)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")
timer_btf_find_prog(void * ctx)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
syscall_sys_bpf_prog(void * ctx)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
syscall_sys_close_prog(void * ctx)147 int syscall_sys_close_prog(void *ctx)
148 {
149 bpf_sys_close(0);
150 return 0;
151 }
152
153 SEC("syscall")
154 __success
syscall_btf_find_prog(void * ctx)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
wq_cb(void * map,int * key,void * value)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
wq_non_sleepable_prog(void * ctx)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
wq_sleepable_prog(void * ctx)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
task_work_cb(struct bpf_map * map,void * key,void * value)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
task_work_non_sleepable_prog(void * ctx)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
task_work_sleepable_prog(void * ctx)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