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
10extern void bpf_rcu_read_lock(void) __ksym;
11
12#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
13
14struct foo {
15	struct bpf_rb_node node;
16};
17
18struct hmap_elem {
19	struct bpf_timer timer;
20};
21
22struct {
23	__uint(type, BPF_MAP_TYPE_HASH);
24	__uint(max_entries, 64);
25	__type(key, int);
26	__type(value, struct hmap_elem);
27} hmap SEC(".maps");
28
29private(A) struct bpf_spin_lock lock;
30private(A) struct bpf_rb_root rbtree __contains(foo, node);
31
32__noinline void *exception_cb_bad_ret_type(u64 cookie)
33{
34	return NULL;
35}
36
37__noinline int exception_cb_bad_arg_0(void)
38{
39	return 0;
40}
41
42__noinline int exception_cb_bad_arg_2(int a, int b)
43{
44	return 0;
45}
46
47__noinline int exception_cb_ok_arg_small(int a)
48{
49	return 0;
50}
51
52SEC("?tc")
53__exception_cb(exception_cb_bad_ret_type)
54__failure __msg("Global function exception_cb_bad_ret_type() doesn't return scalar.")
55int reject_exception_cb_type_1(struct __sk_buff *ctx)
56{
57	bpf_throw(0);
58	return 0;
59}
60
61SEC("?tc")
62__exception_cb(exception_cb_bad_arg_0)
63__failure __msg("exception cb only supports single integer argument")
64int reject_exception_cb_type_2(struct __sk_buff *ctx)
65{
66	bpf_throw(0);
67	return 0;
68}
69
70SEC("?tc")
71__exception_cb(exception_cb_bad_arg_2)
72__failure __msg("exception cb only supports single integer argument")
73int reject_exception_cb_type_3(struct __sk_buff *ctx)
74{
75	bpf_throw(0);
76	return 0;
77}
78
79SEC("?tc")
80__exception_cb(exception_cb_ok_arg_small)
81__success
82int reject_exception_cb_type_4(struct __sk_buff *ctx)
83{
84	bpf_throw(0);
85	return 0;
86}
87
88__noinline
89static int timer_cb(void *map, int *key, struct bpf_timer *timer)
90{
91	bpf_throw(0);
92	return 0;
93}
94
95SEC("?tc")
96__failure __msg("cannot be called from callback subprog")
97int reject_async_callback_throw(struct __sk_buff *ctx)
98{
99	struct hmap_elem *elem;
100
101	elem = bpf_map_lookup_elem(&hmap, &(int){0});
102	if (!elem)
103		return 0;
104	return bpf_timer_set_callback(&elem->timer, timer_cb);
105}
106
107__noinline static int subprog_lock(struct __sk_buff *ctx)
108{
109	volatile int ret = 0;
110
111	bpf_spin_lock(&lock);
112	if (ctx->len)
113		bpf_throw(0);
114	return ret;
115}
116
117SEC("?tc")
118__failure __msg("function calls are not allowed while holding a lock")
119int reject_with_lock(void *ctx)
120{
121	bpf_spin_lock(&lock);
122	bpf_throw(0);
123	return 0;
124}
125
126SEC("?tc")
127__failure __msg("function calls are not allowed while holding a lock")
128int reject_subprog_with_lock(void *ctx)
129{
130	return subprog_lock(ctx);
131}
132
133SEC("?tc")
134__failure __msg("bpf_rcu_read_unlock is missing")
135int reject_with_rcu_read_lock(void *ctx)
136{
137	bpf_rcu_read_lock();
138	bpf_throw(0);
139	return 0;
140}
141
142__noinline static int throwing_subprog(struct __sk_buff *ctx)
143{
144	if (ctx->len)
145		bpf_throw(0);
146	return 0;
147}
148
149SEC("?tc")
150__failure __msg("bpf_rcu_read_unlock is missing")
151int reject_subprog_with_rcu_read_lock(void *ctx)
152{
153	bpf_rcu_read_lock();
154	return throwing_subprog(ctx);
155}
156
157static bool rbless(struct bpf_rb_node *n1, const struct bpf_rb_node *n2)
158{
159	bpf_throw(0);
160	return true;
161}
162
163SEC("?tc")
164__failure __msg("function calls are not allowed while holding a lock")
165int reject_with_rbtree_add_throw(void *ctx)
166{
167	struct foo *f;
168
169	f = bpf_obj_new(typeof(*f));
170	if (!f)
171		return 0;
172	bpf_spin_lock(&lock);
173	bpf_rbtree_add(&rbtree, &f->node, rbless);
174	bpf_spin_unlock(&lock);
175	return 0;
176}
177
178SEC("?tc")
179__failure __msg("Unreleased reference")
180int reject_with_reference(void *ctx)
181{
182	struct foo *f;
183
184	f = bpf_obj_new(typeof(*f));
185	if (!f)
186		return 0;
187	bpf_throw(0);
188	return 0;
189}
190
191__noinline static int subprog_ref(struct __sk_buff *ctx)
192{
193	struct foo *f;
194
195	f = bpf_obj_new(typeof(*f));
196	if (!f)
197		return 0;
198	bpf_throw(0);
199	return 0;
200}
201
202__noinline static int subprog_cb_ref(u32 i, void *ctx)
203{
204	bpf_throw(0);
205	return 0;
206}
207
208SEC("?tc")
209__failure __msg("Unreleased reference")
210int reject_with_cb_reference(void *ctx)
211{
212	struct foo *f;
213
214	f = bpf_obj_new(typeof(*f));
215	if (!f)
216		return 0;
217	bpf_loop(5, subprog_cb_ref, NULL, 0);
218	bpf_obj_drop(f);
219	return 0;
220}
221
222SEC("?tc")
223__failure __msg("cannot be called from callback")
224int reject_with_cb(void *ctx)
225{
226	bpf_loop(5, subprog_cb_ref, NULL, 0);
227	return 0;
228}
229
230SEC("?tc")
231__failure __msg("Unreleased reference")
232int reject_with_subprog_reference(void *ctx)
233{
234	return subprog_ref(ctx) + 1;
235}
236
237__noinline int throwing_exception_cb(u64 c)
238{
239	bpf_throw(0);
240	return c;
241}
242
243__noinline int exception_cb1(u64 c)
244{
245	return c;
246}
247
248__noinline int exception_cb2(u64 c)
249{
250	return c;
251}
252
253static __noinline int static_func(struct __sk_buff *ctx)
254{
255	return exception_cb1(ctx->tstamp);
256}
257
258__noinline int global_func(struct __sk_buff *ctx)
259{
260	return exception_cb1(ctx->tstamp);
261}
262
263SEC("?tc")
264__exception_cb(throwing_exception_cb)
265__failure __msg("cannot be called from callback subprog")
266int reject_throwing_exception_cb(struct __sk_buff *ctx)
267{
268	return 0;
269}
270
271SEC("?tc")
272__exception_cb(exception_cb1)
273__failure __msg("cannot call exception cb directly")
274int reject_exception_cb_call_global_func(struct __sk_buff *ctx)
275{
276	return global_func(ctx);
277}
278
279SEC("?tc")
280__exception_cb(exception_cb1)
281__failure __msg("cannot call exception cb directly")
282int reject_exception_cb_call_static_func(struct __sk_buff *ctx)
283{
284	return static_func(ctx);
285}
286
287SEC("?tc")
288__exception_cb(exception_cb1)
289__exception_cb(exception_cb2)
290__failure __msg("multiple exception callback tags for main subprog")
291int reject_multiple_exception_cb(struct __sk_buff *ctx)
292{
293	bpf_throw(0);
294	return 16;
295}
296
297__noinline int exception_cb_bad_ret(u64 c)
298{
299	return c;
300}
301
302SEC("?fentry/bpf_check")
303__exception_cb(exception_cb_bad_ret)
304__failure __msg("At program exit the register R0 has unknown scalar value should")
305int reject_set_exception_cb_bad_ret1(void *ctx)
306{
307	return 0;
308}
309
310SEC("?fentry/bpf_check")
311__failure __msg("At program exit the register R1 has smin=64 smax=64 should")
312int reject_set_exception_cb_bad_ret2(void *ctx)
313{
314	bpf_throw(64);
315	return 0;
316}
317
318__noinline static int loop_cb1(u32 index, int *ctx)
319{
320	bpf_throw(0);
321	return 0;
322}
323
324__noinline static int loop_cb2(u32 index, int *ctx)
325{
326	bpf_throw(0);
327	return 0;
328}
329
330SEC("?tc")
331__failure __msg("cannot be called from callback")
332int reject_exception_throw_cb(struct __sk_buff *ctx)
333{
334	bpf_loop(5, loop_cb1, NULL, 0);
335	return 0;
336}
337
338SEC("?tc")
339__failure __msg("cannot be called from callback")
340int reject_exception_throw_cb_diff(struct __sk_buff *ctx)
341{
342	if (ctx->protocol)
343		bpf_loop(5, loop_cb1, NULL, 0);
344	else
345		bpf_loop(5, loop_cb2, NULL, 0);
346	return 0;
347}
348
349char _license[] SEC("license") = "GPL";
350