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 | |
12 | #define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8))) |
13 | |
14 | struct foo { |
15 | struct bpf_rb_node node; |
16 | }; |
17 | |
18 | struct hmap_elem { |
19 | struct bpf_timer timer; |
20 | }; |
21 | |
22 | struct { |
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 | |
29 | private(A) struct bpf_spin_lock lock; |
30 | private(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 | |
52 | SEC("?tc" ) |
53 | __exception_cb(exception_cb_bad_ret_type) |
54 | __failure __msg("Global function exception_cb_bad_ret_type() doesn't return scalar." ) |
55 | int reject_exception_cb_type_1(struct __sk_buff *ctx) |
56 | { |
57 | bpf_throw(0); |
58 | return 0; |
59 | } |
60 | |
61 | SEC("?tc" ) |
62 | __exception_cb(exception_cb_bad_arg_0) |
63 | __failure __msg("exception cb only supports single integer argument" ) |
64 | int reject_exception_cb_type_2(struct __sk_buff *ctx) |
65 | { |
66 | bpf_throw(0); |
67 | return 0; |
68 | } |
69 | |
70 | SEC("?tc" ) |
71 | __exception_cb(exception_cb_bad_arg_2) |
72 | __failure __msg("exception cb only supports single integer argument" ) |
73 | int reject_exception_cb_type_3(struct __sk_buff *ctx) |
74 | { |
75 | bpf_throw(0); |
76 | return 0; |
77 | } |
78 | |
79 | SEC("?tc" ) |
80 | __exception_cb(exception_cb_ok_arg_small) |
81 | __success |
82 | int reject_exception_cb_type_4(struct __sk_buff *ctx) |
83 | { |
84 | bpf_throw(0); |
85 | return 0; |
86 | } |
87 | |
88 | __noinline |
89 | static int timer_cb(void *map, int *key, struct bpf_timer *timer) |
90 | { |
91 | bpf_throw(0); |
92 | return 0; |
93 | } |
94 | |
95 | SEC("?tc" ) |
96 | __failure __msg("cannot be called from callback subprog" ) |
97 | int 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 | |
117 | SEC("?tc" ) |
118 | __failure __msg("function calls are not allowed while holding a lock" ) |
119 | int reject_with_lock(void *ctx) |
120 | { |
121 | bpf_spin_lock(&lock); |
122 | bpf_throw(0); |
123 | return 0; |
124 | } |
125 | |
126 | SEC("?tc" ) |
127 | __failure __msg("function calls are not allowed while holding a lock" ) |
128 | int reject_subprog_with_lock(void *ctx) |
129 | { |
130 | return subprog_lock(ctx); |
131 | } |
132 | |
133 | SEC("?tc" ) |
134 | __failure __msg("bpf_rcu_read_unlock is missing" ) |
135 | int 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 | |
149 | SEC("?tc" ) |
150 | __failure __msg("bpf_rcu_read_unlock is missing" ) |
151 | int reject_subprog_with_rcu_read_lock(void *ctx) |
152 | { |
153 | bpf_rcu_read_lock(); |
154 | return throwing_subprog(ctx); |
155 | } |
156 | |
157 | static bool rbless(struct bpf_rb_node *n1, const struct bpf_rb_node *n2) |
158 | { |
159 | bpf_throw(0); |
160 | return true; |
161 | } |
162 | |
163 | SEC("?tc" ) |
164 | __failure __msg("function calls are not allowed while holding a lock" ) |
165 | int 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 | |
178 | SEC("?tc" ) |
179 | __failure __msg("Unreleased reference" ) |
180 | int 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 | |
208 | SEC("?tc" ) |
209 | __failure __msg("Unreleased reference" ) |
210 | int 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 | |
222 | SEC("?tc" ) |
223 | __failure __msg("cannot be called from callback" ) |
224 | int reject_with_cb(void *ctx) |
225 | { |
226 | bpf_loop(5, subprog_cb_ref, NULL, 0); |
227 | return 0; |
228 | } |
229 | |
230 | SEC("?tc" ) |
231 | __failure __msg("Unreleased reference" ) |
232 | int 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 | |
253 | static __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 | |
263 | SEC("?tc" ) |
264 | __exception_cb(throwing_exception_cb) |
265 | __failure __msg("cannot be called from callback subprog" ) |
266 | int reject_throwing_exception_cb(struct __sk_buff *ctx) |
267 | { |
268 | return 0; |
269 | } |
270 | |
271 | SEC("?tc" ) |
272 | __exception_cb(exception_cb1) |
273 | __failure __msg("cannot call exception cb directly" ) |
274 | int reject_exception_cb_call_global_func(struct __sk_buff *ctx) |
275 | { |
276 | return global_func(ctx); |
277 | } |
278 | |
279 | SEC("?tc" ) |
280 | __exception_cb(exception_cb1) |
281 | __failure __msg("cannot call exception cb directly" ) |
282 | int reject_exception_cb_call_static_func(struct __sk_buff *ctx) |
283 | { |
284 | return static_func(ctx); |
285 | } |
286 | |
287 | SEC("?tc" ) |
288 | __exception_cb(exception_cb1) |
289 | __exception_cb(exception_cb2) |
290 | __failure __msg("multiple exception callback tags for main subprog" ) |
291 | int 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 | |
302 | SEC("?fentry/bpf_check" ) |
303 | __exception_cb(exception_cb_bad_ret) |
304 | __failure __msg("At program exit the register R0 has unknown scalar value should" ) |
305 | int reject_set_exception_cb_bad_ret1(void *ctx) |
306 | { |
307 | return 0; |
308 | } |
309 | |
310 | SEC("?fentry/bpf_check" ) |
311 | __failure __msg("At program exit the register R1 has smin=64 smax=64 should" ) |
312 | int 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 | |
330 | SEC("?tc" ) |
331 | __failure __msg("cannot be called from callback" ) |
332 | int reject_exception_throw_cb(struct __sk_buff *ctx) |
333 | { |
334 | bpf_loop(5, loop_cb1, NULL, 0); |
335 | return 0; |
336 | } |
337 | |
338 | SEC("?tc" ) |
339 | __failure __msg("cannot be called from callback" ) |
340 | int 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 | |
349 | char _license[] SEC("license" ) = "GPL" ; |
350 | |