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 #include "bpf_misc.h"
7
8 struct map_value {
9 char buf[8];
10 struct prog_test_ref_kfunc __kptr *unref_ptr;
11 struct prog_test_ref_kfunc __kptr_ref *ref_ptr;
12 struct prog_test_member __kptr_ref *ref_memb_ptr;
13 };
14
15 struct array_map {
16 __uint(type, BPF_MAP_TYPE_ARRAY);
17 __type(key, int);
18 __type(value, struct map_value);
19 __uint(max_entries, 1);
20 } array_map SEC(".maps");
21
22 extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym;
23 extern struct prog_test_ref_kfunc *
24 bpf_kfunc_call_test_kptr_get(struct prog_test_ref_kfunc **p, int a, int b) __ksym;
25
26 SEC("?tc")
27 __failure __msg("kptr access size must be BPF_DW")
size_not_bpf_dw(struct __sk_buff * ctx)28 int size_not_bpf_dw(struct __sk_buff *ctx)
29 {
30 struct map_value *v;
31 int key = 0;
32
33 v = bpf_map_lookup_elem(&array_map, &key);
34 if (!v)
35 return 0;
36
37 *(u32 *)&v->unref_ptr = 0;
38 return 0;
39 }
40
41 SEC("?tc")
42 __failure __msg("kptr access cannot have variable offset")
non_const_var_off(struct __sk_buff * ctx)43 int non_const_var_off(struct __sk_buff *ctx)
44 {
45 struct map_value *v;
46 int key = 0, id;
47
48 v = bpf_map_lookup_elem(&array_map, &key);
49 if (!v)
50 return 0;
51
52 id = ctx->protocol;
53 if (id < 4 || id > 12)
54 return 0;
55 *(u64 *)((void *)v + id) = 0;
56
57 return 0;
58 }
59
60 SEC("?tc")
61 __failure __msg("R1 doesn't have constant offset. kptr has to be")
non_const_var_off_kptr_xchg(struct __sk_buff * ctx)62 int non_const_var_off_kptr_xchg(struct __sk_buff *ctx)
63 {
64 struct map_value *v;
65 int key = 0, id;
66
67 v = bpf_map_lookup_elem(&array_map, &key);
68 if (!v)
69 return 0;
70
71 id = ctx->protocol;
72 if (id < 4 || id > 12)
73 return 0;
74 bpf_kptr_xchg((void *)v + id, NULL);
75
76 return 0;
77 }
78
79 SEC("?tc")
80 __failure __msg("kptr access misaligned expected=8 off=7")
misaligned_access_write(struct __sk_buff * ctx)81 int misaligned_access_write(struct __sk_buff *ctx)
82 {
83 struct map_value *v;
84 int key = 0;
85
86 v = bpf_map_lookup_elem(&array_map, &key);
87 if (!v)
88 return 0;
89
90 *(void **)((void *)v + 7) = NULL;
91
92 return 0;
93 }
94
95 SEC("?tc")
96 __failure __msg("kptr access misaligned expected=8 off=1")
misaligned_access_read(struct __sk_buff * ctx)97 int misaligned_access_read(struct __sk_buff *ctx)
98 {
99 struct map_value *v;
100 int key = 0;
101
102 v = bpf_map_lookup_elem(&array_map, &key);
103 if (!v)
104 return 0;
105
106 return *(u64 *)((void *)v + 1);
107 }
108
109 SEC("?tc")
110 __failure __msg("variable untrusted_ptr_ access var_off=(0x0; 0x1e0)")
reject_var_off_store(struct __sk_buff * ctx)111 int reject_var_off_store(struct __sk_buff *ctx)
112 {
113 struct prog_test_ref_kfunc *unref_ptr;
114 struct map_value *v;
115 int key = 0, id;
116
117 v = bpf_map_lookup_elem(&array_map, &key);
118 if (!v)
119 return 0;
120
121 unref_ptr = v->unref_ptr;
122 if (!unref_ptr)
123 return 0;
124 id = ctx->protocol;
125 if (id < 4 || id > 12)
126 return 0;
127 unref_ptr += id;
128 v->unref_ptr = unref_ptr;
129
130 return 0;
131 }
132
133 SEC("?tc")
134 __failure __msg("invalid kptr access, R1 type=untrusted_ptr_prog_test_ref_kfunc")
reject_bad_type_match(struct __sk_buff * ctx)135 int reject_bad_type_match(struct __sk_buff *ctx)
136 {
137 struct prog_test_ref_kfunc *unref_ptr;
138 struct map_value *v;
139 int key = 0;
140
141 v = bpf_map_lookup_elem(&array_map, &key);
142 if (!v)
143 return 0;
144
145 unref_ptr = v->unref_ptr;
146 if (!unref_ptr)
147 return 0;
148 unref_ptr = (void *)unref_ptr + 4;
149 v->unref_ptr = unref_ptr;
150
151 return 0;
152 }
153
154 SEC("?tc")
155 __failure __msg("R1 type=untrusted_ptr_or_null_ expected=percpu_ptr_")
marked_as_untrusted_or_null(struct __sk_buff * ctx)156 int marked_as_untrusted_or_null(struct __sk_buff *ctx)
157 {
158 struct map_value *v;
159 int key = 0;
160
161 v = bpf_map_lookup_elem(&array_map, &key);
162 if (!v)
163 return 0;
164
165 bpf_this_cpu_ptr(v->unref_ptr);
166 return 0;
167 }
168
169 SEC("?tc")
170 __failure __msg("access beyond struct prog_test_ref_kfunc at off 32 size 4")
correct_btf_id_check_size(struct __sk_buff * ctx)171 int correct_btf_id_check_size(struct __sk_buff *ctx)
172 {
173 struct prog_test_ref_kfunc *p;
174 struct map_value *v;
175 int key = 0;
176
177 v = bpf_map_lookup_elem(&array_map, &key);
178 if (!v)
179 return 0;
180
181 p = v->unref_ptr;
182 if (!p)
183 return 0;
184 return *(int *)((void *)p + bpf_core_type_size(struct prog_test_ref_kfunc));
185 }
186
187 SEC("?tc")
188 __failure __msg("R1 type=untrusted_ptr_ expected=percpu_ptr_")
inherit_untrusted_on_walk(struct __sk_buff * ctx)189 int inherit_untrusted_on_walk(struct __sk_buff *ctx)
190 {
191 struct prog_test_ref_kfunc *unref_ptr;
192 struct map_value *v;
193 int key = 0;
194
195 v = bpf_map_lookup_elem(&array_map, &key);
196 if (!v)
197 return 0;
198
199 unref_ptr = v->unref_ptr;
200 if (!unref_ptr)
201 return 0;
202 unref_ptr = unref_ptr->next;
203 bpf_this_cpu_ptr(unref_ptr);
204 return 0;
205 }
206
207 SEC("?tc")
208 __failure __msg("off=8 kptr isn't referenced kptr")
reject_kptr_xchg_on_unref(struct __sk_buff * ctx)209 int reject_kptr_xchg_on_unref(struct __sk_buff *ctx)
210 {
211 struct map_value *v;
212 int key = 0;
213
214 v = bpf_map_lookup_elem(&array_map, &key);
215 if (!v)
216 return 0;
217
218 bpf_kptr_xchg(&v->unref_ptr, NULL);
219 return 0;
220 }
221
222 SEC("?tc")
223 __failure __msg("arg#0 expected pointer to map value")
reject_kptr_get_no_map_val(struct __sk_buff * ctx)224 int reject_kptr_get_no_map_val(struct __sk_buff *ctx)
225 {
226 bpf_kfunc_call_test_kptr_get((void *)&ctx, 0, 0);
227 return 0;
228 }
229
230 SEC("?tc")
231 __failure __msg("arg#0 expected pointer to map value")
reject_kptr_get_no_null_map_val(struct __sk_buff * ctx)232 int reject_kptr_get_no_null_map_val(struct __sk_buff *ctx)
233 {
234 bpf_kfunc_call_test_kptr_get(bpf_map_lookup_elem(&array_map, &(int){0}), 0, 0);
235 return 0;
236 }
237
238 SEC("?tc")
239 __failure __msg("arg#0 no referenced kptr at map value offset=0")
reject_kptr_get_no_kptr(struct __sk_buff * ctx)240 int reject_kptr_get_no_kptr(struct __sk_buff *ctx)
241 {
242 struct map_value *v;
243 int key = 0;
244
245 v = bpf_map_lookup_elem(&array_map, &key);
246 if (!v)
247 return 0;
248
249 bpf_kfunc_call_test_kptr_get((void *)v, 0, 0);
250 return 0;
251 }
252
253 SEC("?tc")
254 __failure __msg("arg#0 no referenced kptr at map value offset=8")
reject_kptr_get_on_unref(struct __sk_buff * ctx)255 int reject_kptr_get_on_unref(struct __sk_buff *ctx)
256 {
257 struct map_value *v;
258 int key = 0;
259
260 v = bpf_map_lookup_elem(&array_map, &key);
261 if (!v)
262 return 0;
263
264 bpf_kfunc_call_test_kptr_get(&v->unref_ptr, 0, 0);
265 return 0;
266 }
267
268 SEC("?tc")
269 __failure __msg("kernel function bpf_kfunc_call_test_kptr_get args#0")
reject_kptr_get_bad_type_match(struct __sk_buff * ctx)270 int reject_kptr_get_bad_type_match(struct __sk_buff *ctx)
271 {
272 struct map_value *v;
273 int key = 0;
274
275 v = bpf_map_lookup_elem(&array_map, &key);
276 if (!v)
277 return 0;
278
279 bpf_kfunc_call_test_kptr_get((void *)&v->ref_memb_ptr, 0, 0);
280 return 0;
281 }
282
283 SEC("?tc")
284 __failure __msg("R1 type=untrusted_ptr_or_null_ expected=percpu_ptr_")
mark_ref_as_untrusted_or_null(struct __sk_buff * ctx)285 int mark_ref_as_untrusted_or_null(struct __sk_buff *ctx)
286 {
287 struct map_value *v;
288 int key = 0;
289
290 v = bpf_map_lookup_elem(&array_map, &key);
291 if (!v)
292 return 0;
293
294 bpf_this_cpu_ptr(v->ref_ptr);
295 return 0;
296 }
297
298 SEC("?tc")
299 __failure __msg("store to referenced kptr disallowed")
reject_untrusted_store_to_ref(struct __sk_buff * ctx)300 int reject_untrusted_store_to_ref(struct __sk_buff *ctx)
301 {
302 struct prog_test_ref_kfunc *p;
303 struct map_value *v;
304 int key = 0;
305
306 v = bpf_map_lookup_elem(&array_map, &key);
307 if (!v)
308 return 0;
309
310 p = v->ref_ptr;
311 if (!p)
312 return 0;
313 /* Checkmate, clang */
314 *(struct prog_test_ref_kfunc * volatile *)&v->ref_ptr = p;
315 return 0;
316 }
317
318 SEC("?tc")
319 __failure __msg("R2 type=untrusted_ptr_ expected=ptr_")
reject_untrusted_xchg(struct __sk_buff * ctx)320 int reject_untrusted_xchg(struct __sk_buff *ctx)
321 {
322 struct prog_test_ref_kfunc *p;
323 struct map_value *v;
324 int key = 0;
325
326 v = bpf_map_lookup_elem(&array_map, &key);
327 if (!v)
328 return 0;
329
330 p = v->ref_ptr;
331 if (!p)
332 return 0;
333 bpf_kptr_xchg(&v->ref_ptr, p);
334 return 0;
335 }
336
337 SEC("?tc")
338 __failure
339 __msg("invalid kptr access, R2 type=ptr_prog_test_ref_kfunc expected=ptr_prog_test_member")
reject_bad_type_xchg(struct __sk_buff * ctx)340 int reject_bad_type_xchg(struct __sk_buff *ctx)
341 {
342 struct prog_test_ref_kfunc *ref_ptr;
343 struct map_value *v;
344 int key = 0;
345
346 v = bpf_map_lookup_elem(&array_map, &key);
347 if (!v)
348 return 0;
349
350 ref_ptr = bpf_kfunc_call_test_acquire(&(unsigned long){0});
351 if (!ref_ptr)
352 return 0;
353 bpf_kptr_xchg(&v->ref_memb_ptr, ref_ptr);
354 return 0;
355 }
356
357 SEC("?tc")
358 __failure __msg("invalid kptr access, R2 type=ptr_prog_test_ref_kfunc")
reject_member_of_ref_xchg(struct __sk_buff * ctx)359 int reject_member_of_ref_xchg(struct __sk_buff *ctx)
360 {
361 struct prog_test_ref_kfunc *ref_ptr;
362 struct map_value *v;
363 int key = 0;
364
365 v = bpf_map_lookup_elem(&array_map, &key);
366 if (!v)
367 return 0;
368
369 ref_ptr = bpf_kfunc_call_test_acquire(&(unsigned long){0});
370 if (!ref_ptr)
371 return 0;
372 bpf_kptr_xchg(&v->ref_memb_ptr, &ref_ptr->memb);
373 return 0;
374 }
375
376 SEC("?syscall")
377 __failure __msg("kptr cannot be accessed indirectly by helper")
reject_indirect_helper_access(struct __sk_buff * ctx)378 int reject_indirect_helper_access(struct __sk_buff *ctx)
379 {
380 struct map_value *v;
381 int key = 0;
382
383 v = bpf_map_lookup_elem(&array_map, &key);
384 if (!v)
385 return 0;
386
387 bpf_get_current_comm(v, sizeof(v->buf) + 1);
388 return 0;
389 }
390
391 __noinline
write_func(int * p)392 int write_func(int *p)
393 {
394 return p ? *p = 42 : 0;
395 }
396
397 SEC("?tc")
398 __failure __msg("kptr cannot be accessed indirectly by helper")
reject_indirect_global_func_access(struct __sk_buff * ctx)399 int reject_indirect_global_func_access(struct __sk_buff *ctx)
400 {
401 struct map_value *v;
402 int key = 0;
403
404 v = bpf_map_lookup_elem(&array_map, &key);
405 if (!v)
406 return 0;
407
408 return write_func((void *)v + 5);
409 }
410
411 SEC("?tc")
412 __failure __msg("Unreleased reference id=5 alloc_insn=")
kptr_xchg_ref_state(struct __sk_buff * ctx)413 int kptr_xchg_ref_state(struct __sk_buff *ctx)
414 {
415 struct prog_test_ref_kfunc *p;
416 struct map_value *v;
417 int key = 0;
418
419 v = bpf_map_lookup_elem(&array_map, &key);
420 if (!v)
421 return 0;
422
423 p = bpf_kfunc_call_test_acquire(&(unsigned long){0});
424 if (!p)
425 return 0;
426 bpf_kptr_xchg(&v->ref_ptr, p);
427 return 0;
428 }
429
430 SEC("?tc")
431 __failure __msg("Unreleased reference id=3 alloc_insn=")
kptr_get_ref_state(struct __sk_buff * ctx)432 int kptr_get_ref_state(struct __sk_buff *ctx)
433 {
434 struct map_value *v;
435 int key = 0;
436
437 v = bpf_map_lookup_elem(&array_map, &key);
438 if (!v)
439 return 0;
440
441 bpf_kfunc_call_test_kptr_get(&v->ref_ptr, 0, 0);
442 return 0;
443 }
444
445 char _license[] SEC("license") = "GPL";
446