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
subprog_ref(struct __sk_buff * ctx)211 __noinline static int subprog_ref(struct __sk_buff *ctx)
212 {
213 struct foo *f;
214
215 f = bpf_obj_new(typeof(*f));
216 if (!f)
217 return 0;
218 bpf_throw(0);
219 return 0;
220 }
221
subprog_cb_ref(u32 i,void * ctx)222 __noinline static int subprog_cb_ref(u32 i, void *ctx)
223 {
224 bpf_throw(0);
225 return 0;
226 }
227
228 SEC("?tc")
229 __failure __msg("Unreleased reference")
reject_with_cb_reference(void * ctx)230 int reject_with_cb_reference(void *ctx)
231 {
232 struct foo *f;
233
234 f = bpf_obj_new(typeof(*f));
235 if (!f)
236 return 0;
237 bpf_loop(5, subprog_cb_ref, NULL, 0);
238 bpf_obj_drop(f);
239 return 0;
240 }
241
242 SEC("?tc")
243 __failure __msg("cannot be called from callback")
reject_with_cb(void * ctx)244 int reject_with_cb(void *ctx)
245 {
246 bpf_loop(5, subprog_cb_ref, NULL, 0);
247 return 0;
248 }
249
250 SEC("?tc")
251 __failure __msg("Unreleased reference")
reject_with_subprog_reference(void * ctx)252 int reject_with_subprog_reference(void *ctx)
253 {
254 return subprog_ref(ctx) + 1;
255 }
256
throwing_exception_cb(u64 c)257 __noinline int throwing_exception_cb(u64 c)
258 {
259 bpf_throw(0);
260 return c;
261 }
262
exception_cb1(u64 c)263 __noinline int exception_cb1(u64 c)
264 {
265 return c;
266 }
267
exception_cb2(u64 c)268 __noinline int exception_cb2(u64 c)
269 {
270 return c;
271 }
272
static_func(struct __sk_buff * ctx)273 static __noinline int static_func(struct __sk_buff *ctx)
274 {
275 return exception_cb1(ctx->tstamp);
276 }
277
global_func(struct __sk_buff * ctx)278 __noinline int global_func(struct __sk_buff *ctx)
279 {
280 return exception_cb1(ctx->tstamp);
281 }
282
283 SEC("?tc")
__exception_cb(throwing_exception_cb)284 __exception_cb(throwing_exception_cb)
285 __failure __msg("cannot be called from callback subprog")
286 int reject_throwing_exception_cb(struct __sk_buff *ctx)
287 {
288 return 0;
289 }
290
291 SEC("?tc")
__exception_cb(exception_cb1)292 __exception_cb(exception_cb1)
293 __failure __msg("cannot call exception cb directly")
294 int reject_exception_cb_call_global_func(struct __sk_buff *ctx)
295 {
296 return global_func(ctx);
297 }
298
299 SEC("?tc")
__exception_cb(exception_cb1)300 __exception_cb(exception_cb1)
301 __failure __msg("cannot call exception cb directly")
302 int reject_exception_cb_call_static_func(struct __sk_buff *ctx)
303 {
304 return static_func(ctx);
305 }
306
307 SEC("?tc")
__exception_cb(exception_cb1)308 __exception_cb(exception_cb1)
309 __exception_cb(exception_cb2)
310 __failure __msg("multiple exception callback tags for main subprog")
311 int reject_multiple_exception_cb(struct __sk_buff *ctx)
312 {
313 bpf_throw(0);
314 return 16;
315 }
316
exception_cb_bad_ret(u64 c)317 __noinline int exception_cb_bad_ret(u64 c)
318 {
319 return c;
320 }
321
322 SEC("?fentry/bpf_check")
__exception_cb(exception_cb_bad_ret)323 __exception_cb(exception_cb_bad_ret)
324 __failure __msg("At program exit the register R0 has unknown scalar value should")
325 int reject_set_exception_cb_bad_ret1(void *ctx)
326 {
327 return 0;
328 }
329
330 SEC("?fentry/bpf_check")
331 __failure __msg("At program exit the register R1 has smin=64 smax=64 should")
reject_set_exception_cb_bad_ret2(void * ctx)332 int reject_set_exception_cb_bad_ret2(void *ctx)
333 {
334 bpf_throw(64);
335 return 0;
336 }
337
loop_cb1(u32 index,int * ctx)338 __noinline static int loop_cb1(u32 index, int *ctx)
339 {
340 bpf_throw(0);
341 return 0;
342 }
343
loop_cb2(u32 index,int * ctx)344 __noinline static int loop_cb2(u32 index, int *ctx)
345 {
346 bpf_throw(0);
347 return 0;
348 }
349
350 SEC("?tc")
351 __failure __msg("cannot be called from callback")
reject_exception_throw_cb(struct __sk_buff * ctx)352 int reject_exception_throw_cb(struct __sk_buff *ctx)
353 {
354 bpf_loop(5, loop_cb1, NULL, 0);
355 return 0;
356 }
357
358 SEC("?tc")
359 __failure __msg("cannot be called from callback")
reject_exception_throw_cb_diff(struct __sk_buff * ctx)360 int reject_exception_throw_cb_diff(struct __sk_buff *ctx)
361 {
362 if (ctx->protocol)
363 bpf_loop(5, loop_cb1, NULL, 0);
364 else
365 bpf_loop(5, loop_cb2, NULL, 0);
366 return 0;
367 }
368
369 __weak
foo(void)370 void foo(void)
371 {
372 bpf_throw(1);
373 }
374
375 SEC("?fentry/bpf_check")
376 __failure __msg("At program exit the register R1 has smin=1 smax=1 should")
reject_out_of_range_global_throw(struct __sk_buff * skb)377 int reject_out_of_range_global_throw(struct __sk_buff *skb)
378 {
379 foo();
380
381 return 0;
382 }
383
always_throws(void)384 __noinline static int always_throws(void)
385 {
386 bpf_throw(0);
387 return 0;
388 }
389
rcu_lock_then_throw(void)390 __noinline static int rcu_lock_then_throw(void)
391 {
392 bpf_rcu_read_lock();
393 bpf_throw(0);
394 return 0;
395 }
396
397 SEC("?tc")
398 __failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
reject_subprog_rcu_lock_throw(void * ctx)399 int reject_subprog_rcu_lock_throw(void *ctx)
400 {
401 rcu_lock_then_throw();
402 return 0;
403 }
404
405 SEC("?tc")
406 __failure __msg("bpf_throw cannot be used inside bpf_preempt_disable-ed region")
reject_subprog_throw_preempt_lock(void * ctx)407 int reject_subprog_throw_preempt_lock(void *ctx)
408 {
409 bpf_preempt_disable();
410 always_throws();
411 bpf_preempt_enable();
412 return 0;
413 }
414
415 SEC("?tc")
416 __failure __msg("bpf_throw cannot be used inside bpf_local_irq_save-ed region")
reject_subprog_throw_irq_lock(void * ctx)417 int reject_subprog_throw_irq_lock(void *ctx)
418 {
419 unsigned long flags;
420
421 bpf_local_irq_save(&flags);
422 always_throws();
423 bpf_local_irq_restore(&flags);
424 return 0;
425 }
426
427 char _license[] SEC("license") = "GPL";
428