1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3
4 #include <vmlinux.h>
5 #include <bpf/bpf_tracing.h>
6 #include <bpf/bpf_helpers.h>
7 #include "bpf_misc.h"
8
9 #include "cpumask_common.h"
10
11 char _license[] SEC("license") = "GPL";
12
13 /* Prototype for all of the program trace events below:
14 *
15 * TRACE_EVENT(task_newtask,
16 * TP_PROTO(struct task_struct *p, u64 clone_flags)
17 */
18
19 SEC("tp_btf/task_newtask")
20 __failure __msg("Unreleased reference")
BPF_PROG(test_alloc_no_release,struct task_struct * task,u64 clone_flags)21 int BPF_PROG(test_alloc_no_release, struct task_struct *task, u64 clone_flags)
22 {
23 struct bpf_cpumask *cpumask;
24
25 cpumask = create_cpumask();
26 __sink(cpumask);
27
28 /* cpumask is never released. */
29 return 0;
30 }
31
32 SEC("tp_btf/task_newtask")
33 __failure __msg("NULL pointer passed to trusted arg0")
BPF_PROG(test_alloc_double_release,struct task_struct * task,u64 clone_flags)34 int BPF_PROG(test_alloc_double_release, struct task_struct *task, u64 clone_flags)
35 {
36 struct bpf_cpumask *cpumask;
37
38 cpumask = create_cpumask();
39
40 /* cpumask is released twice. */
41 bpf_cpumask_release(cpumask);
42 bpf_cpumask_release(cpumask);
43
44 return 0;
45 }
46
47 SEC("tp_btf/task_newtask")
48 __failure __msg("must be referenced")
BPF_PROG(test_acquire_wrong_cpumask,struct task_struct * task,u64 clone_flags)49 int BPF_PROG(test_acquire_wrong_cpumask, struct task_struct *task, u64 clone_flags)
50 {
51 struct bpf_cpumask *cpumask;
52
53 /* Can't acquire a non-struct bpf_cpumask. */
54 cpumask = bpf_cpumask_acquire((struct bpf_cpumask *)task->cpus_ptr);
55 __sink(cpumask);
56
57 return 0;
58 }
59
60 SEC("tp_btf/task_newtask")
61 __failure __msg("bpf_cpumask_set_cpu args#1 expected pointer to STRUCT bpf_cpumask")
BPF_PROG(test_mutate_cpumask,struct task_struct * task,u64 clone_flags)62 int BPF_PROG(test_mutate_cpumask, struct task_struct *task, u64 clone_flags)
63 {
64 /* Can't set the CPU of a non-struct bpf_cpumask. */
65 bpf_cpumask_set_cpu(0, (struct bpf_cpumask *)task->cpus_ptr);
66
67 return 0;
68 }
69
70 SEC("tp_btf/task_newtask")
71 __failure __msg("Unreleased reference")
BPF_PROG(test_insert_remove_no_release,struct task_struct * task,u64 clone_flags)72 int BPF_PROG(test_insert_remove_no_release, struct task_struct *task, u64 clone_flags)
73 {
74 struct bpf_cpumask *cpumask;
75 struct __cpumask_map_value *v;
76
77 cpumask = create_cpumask();
78 if (!cpumask)
79 return 0;
80
81 if (cpumask_map_insert(cpumask))
82 return 0;
83
84 v = cpumask_map_value_lookup();
85 if (!v)
86 return 0;
87
88 cpumask = bpf_kptr_xchg(&v->cpumask, NULL);
89
90 /* cpumask is never released. */
91 return 0;
92 }
93
94 SEC("tp_btf/task_newtask")
95 __failure __msg("NULL pointer passed to trusted arg0")
BPF_PROG(test_cpumask_null,struct task_struct * task,u64 clone_flags)96 int BPF_PROG(test_cpumask_null, struct task_struct *task, u64 clone_flags)
97 {
98 /* NULL passed to KF_TRUSTED_ARGS kfunc. */
99 bpf_cpumask_empty(NULL);
100
101 return 0;
102 }
103
104 SEC("tp_btf/task_newtask")
105 __failure __msg("R2 must be a rcu pointer")
BPF_PROG(test_global_mask_out_of_rcu,struct task_struct * task,u64 clone_flags)106 int BPF_PROG(test_global_mask_out_of_rcu, struct task_struct *task, u64 clone_flags)
107 {
108 struct bpf_cpumask *local, *prev;
109
110 local = create_cpumask();
111 if (!local)
112 return 0;
113
114 prev = bpf_kptr_xchg(&global_mask, local);
115 if (prev) {
116 bpf_cpumask_release(prev);
117 err = 3;
118 return 0;
119 }
120
121 bpf_rcu_read_lock();
122 local = global_mask;
123 if (!local) {
124 err = 4;
125 bpf_rcu_read_unlock();
126 return 0;
127 }
128
129 bpf_rcu_read_unlock();
130
131 /* RCU region is exited before calling KF_RCU kfunc. */
132
133 bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
134
135 return 0;
136 }
137
138 SEC("tp_btf/task_newtask")
139 __failure __msg("NULL pointer passed to trusted arg1")
BPF_PROG(test_global_mask_no_null_check,struct task_struct * task,u64 clone_flags)140 int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone_flags)
141 {
142 struct bpf_cpumask *local, *prev;
143
144 local = create_cpumask();
145 if (!local)
146 return 0;
147
148 prev = bpf_kptr_xchg(&global_mask, local);
149 if (prev) {
150 bpf_cpumask_release(prev);
151 err = 3;
152 return 0;
153 }
154
155 bpf_rcu_read_lock();
156 local = global_mask;
157
158 /* No NULL check is performed on global cpumask kptr. */
159 bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
160
161 bpf_rcu_read_unlock();
162
163 return 0;
164 }
165
166 SEC("tp_btf/task_newtask")
167 __failure __msg("Possibly NULL pointer passed to helper arg2")
BPF_PROG(test_global_mask_rcu_no_null_check,struct task_struct * task,u64 clone_flags)168 int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags)
169 {
170 struct bpf_cpumask *prev, *curr;
171
172 curr = bpf_cpumask_create();
173 if (!curr)
174 return 0;
175
176 prev = bpf_kptr_xchg(&global_mask, curr);
177 if (prev)
178 bpf_cpumask_release(prev);
179
180 bpf_rcu_read_lock();
181 curr = global_mask;
182 /* PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU passed to bpf_kptr_xchg() */
183 prev = bpf_kptr_xchg(&global_mask, curr);
184 bpf_rcu_read_unlock();
185 if (prev)
186 bpf_cpumask_release(prev);
187
188 return 0;
189 }
190