1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
3
4 #include <vmlinux.h>
5 #include <bpf/bpf_helpers.h>
6 #include <bpf/bpf_tracing.h>
7 #include <bpf/bpf_core_read.h>
8 #include "bpf_misc.h"
9 #include "xdp_metadata.h"
10 #include "bpf_kfuncs.h"
11
12 extern struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym __weak;
13 extern void bpf_task_release(struct task_struct *p) __ksym __weak;
14
subprog_trusted_task_nullable(struct task_struct * task __arg_trusted __arg_nullable)15 __weak int subprog_trusted_task_nullable(struct task_struct *task __arg_trusted __arg_nullable)
16 {
17 if (!task)
18 return 0;
19 return task->pid + task->tgid;
20 }
21
subprog_trusted_task_nullable_extra_layer(struct task_struct * task __arg_trusted __arg_nullable)22 __weak int subprog_trusted_task_nullable_extra_layer(struct task_struct *task __arg_trusted __arg_nullable)
23 {
24 return subprog_trusted_task_nullable(task) + subprog_trusted_task_nullable(NULL);
25 }
26
27 SEC("?tp_btf/task_newtask")
28 __success __log_level(2)
29 __msg("Validating subprog_trusted_task_nullable() func#1...")
30 __msg(": R1=trusted_ptr_or_null_task_struct(")
trusted_task_arg_nullable(void * ctx)31 int trusted_task_arg_nullable(void *ctx)
32 {
33 struct task_struct *t1 = bpf_get_current_task_btf();
34 struct task_struct *t2 = bpf_task_acquire(t1);
35 int res = 0;
36
37 /* known NULL */
38 res += subprog_trusted_task_nullable(NULL);
39
40 /* known non-NULL */
41 res += subprog_trusted_task_nullable(t1);
42 res += subprog_trusted_task_nullable_extra_layer(t1);
43
44 /* unknown if NULL or not */
45 res += subprog_trusted_task_nullable(t2);
46 res += subprog_trusted_task_nullable_extra_layer(t2);
47
48 if (t2) {
49 /* known non-NULL after explicit NULL check, just in case */
50 res += subprog_trusted_task_nullable(t2);
51 res += subprog_trusted_task_nullable_extra_layer(t2);
52
53 bpf_task_release(t2);
54 }
55
56 return res;
57 }
58
59 /*
60 * Check that the verifier does not use checkpoints created
61 * on path with r1 == 0 to prune path with r1 != 0.
62 */
63 SEC("?tp_btf/task_newtask")
64 __failure
__flag(BPF_F_TEST_STATE_FREQ)65 __flag(BPF_F_TEST_STATE_FREQ)
66 __msg("R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_")
67 __naked int null_btf_id_arg_global_subprog(void)
68 {
69 asm volatile (
70 "call %[bpf_get_prandom_u32];"
71 "r1 = 42;"
72 "if r0 > 42 goto 1f;"
73 "r1 = 0;"
74 "1:"
75 "call subprog_trusted_task_nullable;"
76 "r0 = 0;"
77 "exit;"
78 :
79 : __imm(bpf_get_prandom_u32)
80 : __clobber_all);
81 }
82
subprog_trusted_task_nonnull(struct task_struct * task __arg_trusted)83 __weak int subprog_trusted_task_nonnull(struct task_struct *task __arg_trusted)
84 {
85 return task->pid + task->tgid;
86 }
87
88 SEC("?kprobe")
89 __failure __log_level(2)
90 __msg("R1 type=scalar expected=ptr_, trusted_ptr_, rcu_ptr_")
91 __msg("Caller passes invalid args into func#1 ('subprog_trusted_task_nonnull')")
trusted_task_arg_nonnull_fail1(void * ctx)92 int trusted_task_arg_nonnull_fail1(void *ctx)
93 {
94 return subprog_trusted_task_nonnull(NULL);
95 }
96
97 SEC("?tp_btf/task_newtask")
98 __failure __log_level(2)
99 __msg("R1 type=trusted_ptr_or_null_ expected=ptr_, trusted_ptr_, rcu_ptr_")
100 __msg("Caller passes invalid args into func#1 ('subprog_trusted_task_nonnull')")
trusted_task_arg_nonnull_fail2(void * ctx)101 int trusted_task_arg_nonnull_fail2(void *ctx)
102 {
103 struct task_struct *t = bpf_get_current_task_btf();
104 struct task_struct *nullable;
105 int res;
106
107 nullable = bpf_task_acquire(t);
108
109 /* should fail, PTR_TO_BTF_ID_OR_NULL */
110 res = subprog_trusted_task_nonnull(nullable);
111
112 if (nullable)
113 bpf_task_release(nullable);
114
115 return res;
116 }
117
118 SEC("?kprobe")
119 __success __log_level(2)
120 __msg("Validating subprog_trusted_task_nonnull() func#1...")
121 __msg(": R1=trusted_ptr_task_struct(")
trusted_task_arg_nonnull(void * ctx)122 int trusted_task_arg_nonnull(void *ctx)
123 {
124 struct task_struct *t = bpf_get_current_task_btf();
125
126 return subprog_trusted_task_nonnull(t);
127 }
128
129 struct task_struct___local {} __attribute__((preserve_access_index));
130
subprog_nullable_task_flavor(struct task_struct___local * task __arg_trusted __arg_nullable)131 __weak int subprog_nullable_task_flavor(
132 struct task_struct___local *task __arg_trusted __arg_nullable)
133 {
134 char buf[16];
135
136 if (!task)
137 return 0;
138
139 return bpf_copy_from_user_task(&buf, sizeof(buf), NULL, (void *)task, 0);
140 }
141
142 SEC("?uprobe.s")
143 __success __log_level(2)
144 __msg("Validating subprog_nullable_task_flavor() func#1...")
145 __msg(": R1=trusted_ptr_or_null_task_struct(")
flavor_ptr_nullable(void * ctx)146 int flavor_ptr_nullable(void *ctx)
147 {
148 struct task_struct___local *t = (void *)bpf_get_current_task_btf();
149
150 return subprog_nullable_task_flavor(t);
151 }
152
subprog_nonnull_task_flavor(struct task_struct___local * task __arg_trusted)153 __weak int subprog_nonnull_task_flavor(struct task_struct___local *task __arg_trusted)
154 {
155 char buf[16];
156
157 return bpf_copy_from_user_task(&buf, sizeof(buf), NULL, (void *)task, 0);
158 }
159
160 SEC("?uprobe.s")
161 __success __log_level(2)
162 __msg("Validating subprog_nonnull_task_flavor() func#1...")
163 __msg(": R1=trusted_ptr_task_struct(")
flavor_ptr_nonnull(void * ctx)164 int flavor_ptr_nonnull(void *ctx)
165 {
166 struct task_struct *t = bpf_get_current_task_btf();
167
168 return subprog_nonnull_task_flavor((void *)t);
169 }
170
subprog_trusted_destroy(struct task_struct * task __arg_trusted)171 __weak int subprog_trusted_destroy(struct task_struct *task __arg_trusted)
172 {
173 bpf_task_release(task); /* should be rejected */
174
175 return 0;
176 }
177
178 SEC("?tp_btf/task_newtask")
179 __failure __log_level(2)
180 __msg("release kfunc bpf_task_release expects referenced PTR_TO_BTF_ID passed to R1")
BPF_PROG(trusted_destroy_fail,struct task_struct * task,u64 clone_flags)181 int BPF_PROG(trusted_destroy_fail, struct task_struct *task, u64 clone_flags)
182 {
183 return subprog_trusted_destroy(task);
184 }
185
subprog_trusted_acq_rel(struct task_struct * task __arg_trusted)186 __weak int subprog_trusted_acq_rel(struct task_struct *task __arg_trusted)
187 {
188 struct task_struct *owned;
189
190 owned = bpf_task_acquire(task);
191 if (!owned)
192 return 0;
193
194 bpf_task_release(owned); /* this one is OK, we acquired it locally */
195
196 return 0;
197 }
198
199 SEC("?tp_btf/task_newtask")
200 __success __log_level(2)
BPF_PROG(trusted_acq_rel,struct task_struct * task,u64 clone_flags)201 int BPF_PROG(trusted_acq_rel, struct task_struct *task, u64 clone_flags)
202 {
203 return subprog_trusted_acq_rel(task);
204 }
205
subprog_untrusted_bad_tags(struct task_struct * task __arg_untrusted __arg_nullable)206 __weak int subprog_untrusted_bad_tags(struct task_struct *task __arg_untrusted __arg_nullable)
207 {
208 return task->pid;
209 }
210
211 SEC("tp_btf/sys_enter")
212 __failure
213 __msg("arg#0 untrusted cannot be combined with any other tags")
untrusted_bad_tags(void * ctx)214 int untrusted_bad_tags(void *ctx)
215 {
216 return subprog_untrusted_bad_tags(0);
217 }
218
219 struct local_type_wont_be_accepted {};
220
subprog_untrusted_bad_type(struct local_type_wont_be_accepted * p __arg_untrusted)221 __weak int subprog_untrusted_bad_type(struct local_type_wont_be_accepted *p __arg_untrusted)
222 {
223 return 0;
224 }
225
226 SEC("tp_btf/sys_enter")
227 __failure
228 __msg("arg#0 reference type('STRUCT local_type_wont_be_accepted') has no matches")
untrusted_bad_type(void * ctx)229 int untrusted_bad_type(void *ctx)
230 {
231 return subprog_untrusted_bad_type(bpf_rdonly_cast(0, 0));
232 }
233
subprog_untrusted(const volatile struct task_struct * restrict task __arg_untrusted)234 __weak int subprog_untrusted(const volatile struct task_struct *restrict task __arg_untrusted)
235 {
236 return task->pid;
237 }
238
239 SEC("tp_btf/sys_enter")
240 __success
241 __log_level(2)
242 __msg("r1 = {{.*}}; {{.*}}R1=trusted_ptr_task_struct()")
243 __msg("Func#1 ('subprog_untrusted') is global and assumed valid.")
244 __msg("Validating subprog_untrusted() func#1...")
245 __msg(": R1=untrusted_ptr_task_struct")
trusted_to_untrusted(void * ctx)246 int trusted_to_untrusted(void *ctx)
247 {
248 return subprog_untrusted(bpf_get_current_task_btf());
249 }
250
251 char mem[16];
252 u32 offset;
253
254 SEC("tp_btf/sys_enter")
255 __success
anything_to_untrusted(void * ctx)256 int anything_to_untrusted(void *ctx)
257 {
258 /* untrusted to untrusted */
259 subprog_untrusted(bpf_core_cast(0, struct task_struct));
260 /* wrong type to untrusted */
261 subprog_untrusted((void *)bpf_core_cast(0, struct bpf_verifier_env));
262 /* map value to untrusted */
263 subprog_untrusted((void *)mem);
264 /* scalar to untrusted */
265 subprog_untrusted(0);
266 /* variable offset to untrusted (map) */
267 subprog_untrusted((void *)mem + offset);
268 /* variable offset to untrusted (trusted) */
269 subprog_untrusted((void *)bpf_get_current_task_btf() + offset);
270 return 0;
271 }
272
subprog_untrusted2(struct task_struct * task __arg_untrusted)273 __weak int subprog_untrusted2(struct task_struct *task __arg_untrusted)
274 {
275 return subprog_trusted_task_nullable(task);
276 }
277
278 SEC("tp_btf/sys_enter")
279 __failure
280 __msg("R1 type=untrusted_ptr_ expected=ptr_, trusted_ptr_, rcu_ptr_")
281 __msg("Caller passes invalid args into func#{{.*}} ('subprog_trusted_task_nullable')")
untrusted_to_trusted(void * ctx)282 int untrusted_to_trusted(void *ctx)
283 {
284 return subprog_untrusted2(bpf_get_current_task_btf());
285 }
286
subprog_void_untrusted(void * p __arg_untrusted)287 __weak int subprog_void_untrusted(void *p __arg_untrusted)
288 {
289 return *(int *)p;
290 }
291
subprog_char_untrusted(char * p __arg_untrusted)292 __weak int subprog_char_untrusted(char *p __arg_untrusted)
293 {
294 return *(int *)p;
295 }
296
subprog_enum_untrusted(enum bpf_attach_type * p __arg_untrusted)297 __weak int subprog_enum_untrusted(enum bpf_attach_type *p __arg_untrusted)
298 {
299 return *(int *)p;
300 }
301
302 SEC("tp_btf/sys_enter")
303 __success
304 __log_level(2)
305 __msg("r1 = {{.*}}; {{.*}}R1=trusted_ptr_task_struct()")
306 __msg("Func#1 ('subprog_void_untrusted') is global and assumed valid.")
307 __msg("Validating subprog_void_untrusted() func#1...")
308 __msg(": R1=rdonly_untrusted_mem(sz=0)")
trusted_to_untrusted_mem(void * ctx)309 int trusted_to_untrusted_mem(void *ctx)
310 {
311 return subprog_void_untrusted(bpf_get_current_task_btf());
312 }
313
subprog_write_mem_arg(int * p)314 __weak int subprog_write_mem_arg(int *p)
315 {
316 if (!p)
317 return 0;
318
319 *p = 42;
320 return 0;
321 }
322
323 SEC("?tp_btf/task_newtask")
324 __failure
325 __msg("only read is supported")
trusted_btf_field_to_writable_mem(void * ctx)326 int trusted_btf_field_to_writable_mem(void *ctx)
327 {
328 struct task_struct *task = bpf_get_current_task_btf();
329
330 return subprog_write_mem_arg(&task->prio);
331 }
332
333 SEC("tp_btf/sys_enter")
334 __success
anything_to_untrusted_mem(void * ctx)335 int anything_to_untrusted_mem(void *ctx)
336 {
337 /* untrusted to untrusted mem */
338 subprog_void_untrusted(bpf_core_cast(0, struct task_struct));
339 /* map value to untrusted mem */
340 subprog_void_untrusted(mem);
341 /* scalar to untrusted mem */
342 subprog_void_untrusted(0);
343 /* variable offset to untrusted mem (map) */
344 subprog_void_untrusted((void *)mem + offset);
345 /* variable offset to untrusted mem (trusted) */
346 subprog_void_untrusted(bpf_get_current_task_btf() + offset);
347 /* variable offset to untrusted char/enum (map) */
348 subprog_char_untrusted(mem + offset);
349 subprog_enum_untrusted((void *)mem + offset);
350 return 0;
351 }
352
353 struct pkt_arg {
354 __u64 x;
355 __u8 pad[56];
356 };
357
subprog_pkt_ptr_no_change(struct pkt_arg * p)358 __weak int subprog_pkt_ptr_no_change(struct pkt_arg *p)
359 {
360 if (!p)
361 return 0;
362
363 return p->x;
364 }
365
366 SEC("?tc")
367 __success
pkt_ptr_to_global_mem_arg_no_change(struct __sk_buff * skb)368 int pkt_ptr_to_global_mem_arg_no_change(struct __sk_buff *skb)
369 {
370 void *data = (void *)(long)skb->data;
371 void *data_end = (void *)(long)skb->data_end;
372 struct pkt_arg *p = data;
373
374 if ((void *)(p + 1) > data_end)
375 return 0;
376
377 return subprog_pkt_ptr_no_change(p);
378 }
379
subprog_pkt_ptr_changes_data(struct __sk_buff * skb __arg_ctx,struct pkt_arg * p)380 __weak int subprog_pkt_ptr_changes_data(struct __sk_buff *skb __arg_ctx,
381 struct pkt_arg *p)
382 {
383 if (!p)
384 return 0;
385
386 bpf_skb_pull_data(skb, 0);
387 return p->x;
388 }
389
390 SEC("?tc")
391 __failure __log_level(2)
392 __msg("R2 is a packet pointer, but func#{{[0-9]+}} may change packet data")
393 __msg("Caller passes invalid args into func#{{[0-9]+}} ('subprog_pkt_ptr_changes_data')")
pkt_ptr_to_global_mem_arg_changes_data(struct __sk_buff * skb)394 int pkt_ptr_to_global_mem_arg_changes_data(struct __sk_buff *skb)
395 {
396 void *data = (void *)(long)skb->data;
397 void *data_end = (void *)(long)skb->data_end;
398 struct pkt_arg *p = data;
399
400 if ((void *)(p + 1) > data_end)
401 return 0;
402
403 return subprog_pkt_ptr_changes_data(skb, p);
404 }
405
406 char _license[] SEC("license") = "GPL";
407