xref: /linux/tools/testing/selftests/bpf/progs/exceptions_fail.c (revision f0e77c598ebbb1ae055b156aaa33b7433ae45e51)
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