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