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
7 #include "bpf_misc.h"
8 #include "bpf_experimental.h"
9
10 extern void bpf_rcu_read_lock(void) __ksym;
11 extern void bpf_rcu_read_unlock(void) __ksym;
12 extern void bpf_preempt_disable(void) __ksym;
13 extern void bpf_preempt_enable(void) __ksym;
14 extern void bpf_local_irq_save(unsigned long *) __ksym;
15 extern void bpf_local_irq_restore(unsigned long *) __ksym;
16
17 #define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
18
19 struct foo {
20 struct bpf_rb_node node;
21 };
22
23 struct hmap_elem {
24 struct bpf_timer timer;
25 };
26
27 struct {
28 __uint(type, BPF_MAP_TYPE_HASH);
29 __uint(max_entries, 64);
30 __type(key, int);
31 __type(value, struct hmap_elem);
32 } hmap SEC(".maps");
33
34 private(A) struct bpf_spin_lock lock;
35 private(A) struct bpf_rb_root rbtree __contains(foo, node);
36
exception_cb_bad_ret_type1(u64 cookie)37 __noinline void *exception_cb_bad_ret_type1(u64 cookie)
38 {
39 return NULL;
40 }
41
exception_cb_bad_ret_type2(u64 cookie)42 __noinline void exception_cb_bad_ret_type2(u64 cookie)
43 {
44 }
45
exception_cb_bad_arg_0(void)46 __noinline int exception_cb_bad_arg_0(void)
47 {
48 return 0;
49 }
50
exception_cb_bad_arg_2(int a,int b)51 __noinline int exception_cb_bad_arg_2(int a, int b)
52 {
53 return 0;
54 }
55
exception_cb_ok_arg_small(int a)56 __noinline int exception_cb_ok_arg_small(int a)
57 {
58 return 0;
59 }
60
61 SEC("?tc")
__exception_cb(exception_cb_bad_ret_type1)62 __exception_cb(exception_cb_bad_ret_type1)
63 __failure __msg("Global function exception_cb_bad_ret_type1() return value not void or scalar.")
64 int reject_exception_cb_type_1(struct __sk_buff *ctx)
65 {
66 bpf_throw(0);
67 return 0;
68 }
69
70 SEC("?tc")
__exception_cb(exception_cb_bad_arg_0)71 __exception_cb(exception_cb_bad_arg_0)
72 __failure __msg("exception cb only supports single integer argument")
73 int reject_exception_cb_type_2(struct __sk_buff *ctx)
74 {
75 bpf_throw(0);
76 return 0;
77 }
78
79 SEC("?tc")
__exception_cb(exception_cb_bad_arg_2)80 __exception_cb(exception_cb_bad_arg_2)
81 __failure __msg("exception cb only supports single integer argument")
82 int reject_exception_cb_type_3(struct __sk_buff *ctx)
83 {
84 bpf_throw(0);
85 return 0;
86 }
87
88 SEC("?tc")
__exception_cb(exception_cb_ok_arg_small)89 __exception_cb(exception_cb_ok_arg_small)
90 __success
91 int reject_exception_cb_type_4(struct __sk_buff *ctx)
92 {
93 bpf_throw(0);
94 return 0;
95 }
96
97 SEC("?tc")
__exception_cb(exception_cb_bad_ret_type2)98 __exception_cb(exception_cb_bad_ret_type2)
99 __failure __msg("exception cb cannot return void")
100 int reject_exception_cb_type_5(struct __sk_buff *ctx)
101 {
102 bpf_throw(0);
103 return 0;
104 }
105
106 __noinline
timer_cb(void * map,int * key,struct bpf_timer * timer)107 static int timer_cb(void *map, int *key, struct bpf_timer *timer)
108 {
109 bpf_throw(0);
110 return 0;
111 }
112
113 SEC("?tc")
114 __failure __msg("cannot be called from callback subprog")
reject_async_callback_throw(struct __sk_buff * ctx)115 int reject_async_callback_throw(struct __sk_buff *ctx)
116 {
117 struct hmap_elem *elem;
118
119 elem = bpf_map_lookup_elem(&hmap, &(int){0});
120 if (!elem)
121 return 0;
122 return bpf_timer_set_callback(&elem->timer, timer_cb);
123 }
124
subprog_lock(struct __sk_buff * ctx)125 __noinline static int subprog_lock(struct __sk_buff *ctx)
126 {
127 volatile int ret = 0;
128
129 bpf_spin_lock(&lock);
130 if (ctx->len)
131 bpf_throw(0);
132 return ret;
133 }
134
135 SEC("?tc")
136 __failure __msg("function calls are not allowed while holding a lock")
reject_with_lock(void * ctx)137 int reject_with_lock(void *ctx)
138 {
139 bpf_spin_lock(&lock);
140 bpf_throw(0);
141 return 0;
142 }
143
144 SEC("?tc")
145 __failure __msg("function calls are not allowed while holding a lock")
reject_subprog_with_lock(void * ctx)146 int reject_subprog_with_lock(void *ctx)
147 {
148 return subprog_lock(ctx);
149 }
150
151 SEC("?tc")
152 __failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
reject_with_rcu_read_lock(void * ctx)153 int reject_with_rcu_read_lock(void *ctx)
154 {
155 bpf_rcu_read_lock();
156 bpf_throw(0);
157 return 0;
158 }
159
throwing_subprog(struct __sk_buff * ctx)160 __noinline static int throwing_subprog(struct __sk_buff *ctx)
161 {
162 if (ctx->len)
163 bpf_throw(0);
164 return 0;
165 }
166
167 SEC("?tc")
168 __failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
reject_subprog_with_rcu_read_lock(void * ctx)169 int reject_subprog_with_rcu_read_lock(void *ctx)
170 {
171 bpf_rcu_read_lock();
172 throwing_subprog(ctx);
173 bpf_rcu_read_unlock();
174 return 0;
175 }
176
rbless(struct bpf_rb_node * n1,const struct bpf_rb_node * n2)177 static bool rbless(struct bpf_rb_node *n1, const struct bpf_rb_node *n2)
178 {
179 bpf_throw(0);
180 return true;
181 }
182
183 SEC("?tc")
184 __failure __msg("function calls are not allowed while holding a lock")
reject_with_rbtree_add_throw(void * ctx)185 int reject_with_rbtree_add_throw(void *ctx)
186 {
187 struct foo *f;
188
189 f = bpf_obj_new(typeof(*f));
190 if (!f)
191 return 0;
192 bpf_spin_lock(&lock);
193 bpf_rbtree_add(&rbtree, &f->node, rbless);
194 bpf_spin_unlock(&lock);
195 return 0;
196 }
197
198 SEC("?tc")
199 __failure __msg("Unreleased reference")
reject_with_reference(void * ctx)200 int reject_with_reference(void *ctx)
201 {
202 struct foo *f;
203
204 f = bpf_obj_new(typeof(*f));
205 if (!f)
206 return 0;
207 bpf_throw(0);
208 return 0;
209 }
210
global_subprog_may_throw(struct __sk_buff * ctx)211 __noinline int global_subprog_may_throw(struct __sk_buff *ctx)
212 {
213 if (ctx->len)
214 bpf_throw(0);
215 return 0;
216 }
217
218 SEC("?tc")
219 __failure __msg("Unreleased reference")
reject_global_subprog_throw_with_reference(struct __sk_buff * ctx)220 int reject_global_subprog_throw_with_reference(struct __sk_buff *ctx)
221 {
222 struct foo *f;
223
224 f = bpf_obj_new(typeof(*f));
225 if (!f)
226 return 0;
227 if (ctx->protocol)
228 global_subprog_may_throw(ctx);
229 bpf_obj_drop(f);
230 return 0;
231 }
232
subprog_ref(struct __sk_buff * ctx)233 __noinline static int subprog_ref(struct __sk_buff *ctx)
234 {
235 struct foo *f;
236
237 f = bpf_obj_new(typeof(*f));
238 if (!f)
239 return 0;
240 bpf_throw(0);
241 return 0;
242 }
243
subprog_cb_ref(u32 i,void * ctx)244 __noinline static int subprog_cb_ref(u32 i, void *ctx)
245 {
246 bpf_throw(0);
247 return 0;
248 }
249
250 SEC("?tc")
251 __failure __msg("Unreleased reference")
reject_with_cb_reference(void * ctx)252 int reject_with_cb_reference(void *ctx)
253 {
254 struct foo *f;
255
256 f = bpf_obj_new(typeof(*f));
257 if (!f)
258 return 0;
259 bpf_loop(5, subprog_cb_ref, NULL, 0);
260 bpf_obj_drop(f);
261 return 0;
262 }
263
264 SEC("?tc")
265 __failure __msg("cannot be called from callback")
reject_with_cb(void * ctx)266 int reject_with_cb(void *ctx)
267 {
268 bpf_loop(5, subprog_cb_ref, NULL, 0);
269 return 0;
270 }
271
272 SEC("?tc")
273 __failure __msg("Unreleased reference")
reject_with_subprog_reference(void * ctx)274 int reject_with_subprog_reference(void *ctx)
275 {
276 return subprog_ref(ctx) + 1;
277 }
278
throwing_exception_cb(u64 c)279 __noinline int throwing_exception_cb(u64 c)
280 {
281 bpf_throw(0);
282 return c;
283 }
284
exception_cb1(u64 c)285 __noinline int exception_cb1(u64 c)
286 {
287 return c;
288 }
289
exception_cb2(u64 c)290 __noinline int exception_cb2(u64 c)
291 {
292 return c;
293 }
294
static_func(struct __sk_buff * ctx)295 static __noinline int static_func(struct __sk_buff *ctx)
296 {
297 return exception_cb1(ctx->tstamp);
298 }
299
global_func(struct __sk_buff * ctx)300 __noinline int global_func(struct __sk_buff *ctx)
301 {
302 return exception_cb1(ctx->tstamp);
303 }
304
305 SEC("?tc")
__exception_cb(throwing_exception_cb)306 __exception_cb(throwing_exception_cb)
307 __failure __msg("cannot be called from callback subprog")
308 int reject_throwing_exception_cb(struct __sk_buff *ctx)
309 {
310 return 0;
311 }
312
313 SEC("?tc")
__exception_cb(exception_cb1)314 __exception_cb(exception_cb1)
315 __failure __msg("cannot call exception cb directly")
316 int reject_exception_cb_call_global_func(struct __sk_buff *ctx)
317 {
318 return global_func(ctx);
319 }
320
321 SEC("?tc")
__exception_cb(exception_cb1)322 __exception_cb(exception_cb1)
323 __failure __msg("cannot call exception cb directly")
324 int reject_exception_cb_call_static_func(struct __sk_buff *ctx)
325 {
326 return static_func(ctx);
327 }
328
329 SEC("?tc")
__exception_cb(exception_cb1)330 __exception_cb(exception_cb1)
331 __exception_cb(exception_cb2)
332 __failure __msg("multiple exception callback tags for main subprog")
333 int reject_multiple_exception_cb(struct __sk_buff *ctx)
334 {
335 bpf_throw(0);
336 return 16;
337 }
338
exception_cb_bad_ret(u64 c)339 __noinline int exception_cb_bad_ret(u64 c)
340 {
341 return c;
342 }
343
344 SEC("?fentry/bpf_check")
__exception_cb(exception_cb_bad_ret)345 __exception_cb(exception_cb_bad_ret)
346 __failure __msg("At program exit the register R0 has unknown scalar value should")
347 int reject_set_exception_cb_bad_ret1(void *ctx)
348 {
349 return 0;
350 }
351
352 SEC("?fentry/bpf_check")
353 __failure __msg("At program exit the register R1 has smin=64 smax=64 should")
reject_set_exception_cb_bad_ret2(void * ctx)354 int reject_set_exception_cb_bad_ret2(void *ctx)
355 {
356 bpf_throw(64);
357 return 0;
358 }
359
loop_cb1(u32 index,int * ctx)360 __noinline static int loop_cb1(u32 index, int *ctx)
361 {
362 bpf_throw(0);
363 return 0;
364 }
365
loop_cb2(u32 index,int * ctx)366 __noinline static int loop_cb2(u32 index, int *ctx)
367 {
368 bpf_throw(0);
369 return 0;
370 }
371
372 SEC("?tc")
373 __failure __msg("cannot be called from callback")
reject_exception_throw_cb(struct __sk_buff * ctx)374 int reject_exception_throw_cb(struct __sk_buff *ctx)
375 {
376 bpf_loop(5, loop_cb1, NULL, 0);
377 return 0;
378 }
379
380 SEC("?tc")
381 __failure __msg("cannot be called from callback")
reject_exception_throw_cb_diff(struct __sk_buff * ctx)382 int reject_exception_throw_cb_diff(struct __sk_buff *ctx)
383 {
384 if (ctx->protocol)
385 bpf_loop(5, loop_cb1, NULL, 0);
386 else
387 bpf_loop(5, loop_cb2, NULL, 0);
388 return 0;
389 }
390
391 __weak
foo(void)392 void foo(void)
393 {
394 bpf_throw(1);
395 }
396
397 SEC("?fentry/bpf_check")
398 __failure __msg("At program exit the register R1 has smin=1 smax=1 should")
reject_out_of_range_global_throw(struct __sk_buff * skb)399 int reject_out_of_range_global_throw(struct __sk_buff *skb)
400 {
401 foo();
402
403 return 0;
404 }
405
always_throws(void)406 __noinline static int always_throws(void)
407 {
408 bpf_throw(0);
409 return 0;
410 }
411
rcu_lock_then_throw(void)412 __noinline static int rcu_lock_then_throw(void)
413 {
414 bpf_rcu_read_lock();
415 bpf_throw(0);
416 return 0;
417 }
418
419 SEC("?tc")
420 __failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
reject_subprog_rcu_lock_throw(void * ctx)421 int reject_subprog_rcu_lock_throw(void *ctx)
422 {
423 rcu_lock_then_throw();
424 return 0;
425 }
426
427 SEC("?tc")
428 __failure __msg("bpf_throw cannot be used inside bpf_preempt_disable-ed region")
reject_subprog_throw_preempt_lock(void * ctx)429 int reject_subprog_throw_preempt_lock(void *ctx)
430 {
431 bpf_preempt_disable();
432 always_throws();
433 bpf_preempt_enable();
434 return 0;
435 }
436
437 SEC("?tc")
438 __failure __msg("bpf_throw cannot be used inside bpf_local_irq_save-ed region")
reject_subprog_throw_irq_lock(void * ctx)439 int reject_subprog_throw_irq_lock(void *ctx)
440 {
441 unsigned long flags;
442
443 bpf_local_irq_save(&flags);
444 always_throws();
445 bpf_local_irq_restore(&flags);
446 return 0;
447 }
448
449 char _license[] SEC("license") = "GPL";
450