Loading...
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
11char _license[] SEC("license") = "GPL";
12
13struct kptr_nested_array_2 {
14 struct bpf_cpumask __kptr * mask;
15};
16
17struct kptr_nested_array_1 {
18 /* Make btf_parse_fields() in map_create() return -E2BIG */
19 struct kptr_nested_array_2 d_2[CPUMASK_KPTR_FIELDS_MAX + 1];
20};
21
22struct kptr_nested_array {
23 struct kptr_nested_array_1 d_1;
24};
25
26private(MASK_NESTED) static struct kptr_nested_array global_mask_nested_arr;
27
28/* Prototype for all of the program trace events below:
29 *
30 * TRACE_EVENT(task_newtask,
31 * TP_PROTO(struct task_struct *p, u64 clone_flags)
32 */
33
34SEC("tp_btf/task_newtask")
35__failure __msg("Unreleased reference")
36int BPF_PROG(test_alloc_no_release, struct task_struct *task, u64 clone_flags)
37{
38 struct bpf_cpumask *cpumask;
39
40 cpumask = create_cpumask();
41 __sink(cpumask);
42
43 /* cpumask is never released. */
44 return 0;
45}
46
47SEC("tp_btf/task_newtask")
48__failure __msg("NULL pointer passed to trusted arg0")
49int BPF_PROG(test_alloc_double_release, struct task_struct *task, u64 clone_flags)
50{
51 struct bpf_cpumask *cpumask;
52
53 cpumask = create_cpumask();
54
55 /* cpumask is released twice. */
56 bpf_cpumask_release(cpumask);
57 bpf_cpumask_release(cpumask);
58
59 return 0;
60}
61
62SEC("tp_btf/task_newtask")
63__failure __msg("must be referenced")
64int BPF_PROG(test_acquire_wrong_cpumask, struct task_struct *task, u64 clone_flags)
65{
66 struct bpf_cpumask *cpumask;
67
68 /* Can't acquire a non-struct bpf_cpumask. */
69 cpumask = bpf_cpumask_acquire((struct bpf_cpumask *)task->cpus_ptr);
70 __sink(cpumask);
71
72 return 0;
73}
74
75SEC("tp_btf/task_newtask")
76__failure __msg("bpf_cpumask_set_cpu args#1 expected pointer to STRUCT bpf_cpumask")
77int BPF_PROG(test_mutate_cpumask, struct task_struct *task, u64 clone_flags)
78{
79 /* Can't set the CPU of a non-struct bpf_cpumask. */
80 bpf_cpumask_set_cpu(0, (struct bpf_cpumask *)task->cpus_ptr);
81
82 return 0;
83}
84
85SEC("tp_btf/task_newtask")
86__failure __msg("Unreleased reference")
87int BPF_PROG(test_insert_remove_no_release, struct task_struct *task, u64 clone_flags)
88{
89 struct bpf_cpumask *cpumask;
90 struct __cpumask_map_value *v;
91
92 cpumask = create_cpumask();
93 if (!cpumask)
94 return 0;
95
96 if (cpumask_map_insert(cpumask))
97 return 0;
98
99 v = cpumask_map_value_lookup();
100 if (!v)
101 return 0;
102
103 cpumask = bpf_kptr_xchg(&v->cpumask, NULL);
104
105 /* cpumask is never released. */
106 return 0;
107}
108
109SEC("tp_btf/task_newtask")
110__failure __msg("NULL pointer passed to trusted arg0")
111int BPF_PROG(test_cpumask_null, struct task_struct *task, u64 clone_flags)
112{
113 /* NULL passed to KF_TRUSTED_ARGS kfunc. */
114 bpf_cpumask_empty(NULL);
115
116 return 0;
117}
118
119SEC("tp_btf/task_newtask")
120__failure __msg("R2 must be a rcu pointer")
121int BPF_PROG(test_global_mask_out_of_rcu, struct task_struct *task, u64 clone_flags)
122{
123 struct bpf_cpumask *local, *prev;
124
125 local = create_cpumask();
126 if (!local)
127 return 0;
128
129 prev = bpf_kptr_xchg(&global_mask, local);
130 if (prev) {
131 bpf_cpumask_release(prev);
132 err = 3;
133 return 0;
134 }
135
136 bpf_rcu_read_lock();
137 local = global_mask;
138 if (!local) {
139 err = 4;
140 bpf_rcu_read_unlock();
141 return 0;
142 }
143
144 bpf_rcu_read_unlock();
145
146 /* RCU region is exited before calling KF_RCU kfunc. */
147
148 bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
149
150 return 0;
151}
152
153SEC("tp_btf/task_newtask")
154__failure __msg("NULL pointer passed to trusted arg1")
155int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone_flags)
156{
157 struct bpf_cpumask *local, *prev;
158
159 local = create_cpumask();
160 if (!local)
161 return 0;
162
163 prev = bpf_kptr_xchg(&global_mask, local);
164 if (prev) {
165 bpf_cpumask_release(prev);
166 err = 3;
167 return 0;
168 }
169
170 bpf_rcu_read_lock();
171 local = global_mask;
172
173 /* No NULL check is performed on global cpumask kptr. */
174 bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
175
176 bpf_rcu_read_unlock();
177
178 return 0;
179}
180
181SEC("tp_btf/task_newtask")
182__failure __msg("Possibly NULL pointer passed to helper arg2")
183int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags)
184{
185 struct bpf_cpumask *prev, *curr;
186
187 curr = bpf_cpumask_create();
188 if (!curr)
189 return 0;
190
191 prev = bpf_kptr_xchg(&global_mask, curr);
192 if (prev)
193 bpf_cpumask_release(prev);
194
195 bpf_rcu_read_lock();
196 curr = global_mask;
197 /* PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU passed to bpf_kptr_xchg() */
198 prev = bpf_kptr_xchg(&global_mask, curr);
199 bpf_rcu_read_unlock();
200 if (prev)
201 bpf_cpumask_release(prev);
202
203 return 0;
204}
205
206SEC("tp_btf/task_newtask")
207__failure __msg("has no valid kptr")
208int BPF_PROG(test_invalid_nested_array, struct task_struct *task, u64 clone_flags)
209{
210 struct bpf_cpumask *local, *prev;
211
212 local = create_cpumask();
213 if (!local)
214 return 0;
215
216 prev = bpf_kptr_xchg(&global_mask_nested_arr.d_1.d_2[CPUMASK_KPTR_FIELDS_MAX].mask, local);
217 if (prev) {
218 bpf_cpumask_release(prev);
219 err = 3;
220 return 0;
221 }
222
223 return 0;
224}
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
11char _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
19SEC("tp_btf/task_newtask")
20__failure __msg("Unreleased reference")
21int 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
32SEC("tp_btf/task_newtask")
33__failure __msg("NULL pointer passed to trusted arg0")
34int 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
47SEC("tp_btf/task_newtask")
48__failure __msg("must be referenced")
49int 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
60SEC("tp_btf/task_newtask")
61__failure __msg("bpf_cpumask_set_cpu args#1 expected pointer to STRUCT bpf_cpumask")
62int BPF_PROG(test_mutate_cpumask, struct task_struct *task, u64 clone_flags)
63{
64 struct bpf_cpumask *cpumask;
65
66 /* Can't set the CPU of a non-struct bpf_cpumask. */
67 bpf_cpumask_set_cpu(0, (struct bpf_cpumask *)task->cpus_ptr);
68 __sink(cpumask);
69
70 return 0;
71}
72
73SEC("tp_btf/task_newtask")
74__failure __msg("Unreleased reference")
75int BPF_PROG(test_insert_remove_no_release, struct task_struct *task, u64 clone_flags)
76{
77 struct bpf_cpumask *cpumask;
78 struct __cpumask_map_value *v;
79
80 cpumask = create_cpumask();
81 if (!cpumask)
82 return 0;
83
84 if (cpumask_map_insert(cpumask))
85 return 0;
86
87 v = cpumask_map_value_lookup();
88 if (!v)
89 return 0;
90
91 cpumask = bpf_kptr_xchg(&v->cpumask, NULL);
92
93 /* cpumask is never released. */
94 return 0;
95}
96
97SEC("tp_btf/task_newtask")
98__failure __msg("NULL pointer passed to trusted arg0")
99int BPF_PROG(test_cpumask_null, struct task_struct *task, u64 clone_flags)
100{
101 /* NULL passed to KF_TRUSTED_ARGS kfunc. */
102 bpf_cpumask_empty(NULL);
103
104 return 0;
105}
106
107SEC("tp_btf/task_newtask")
108__failure __msg("R2 must be a rcu pointer")
109int BPF_PROG(test_global_mask_out_of_rcu, struct task_struct *task, u64 clone_flags)
110{
111 struct bpf_cpumask *local, *prev;
112
113 local = create_cpumask();
114 if (!local)
115 return 0;
116
117 prev = bpf_kptr_xchg(&global_mask, local);
118 if (prev) {
119 bpf_cpumask_release(prev);
120 err = 3;
121 return 0;
122 }
123
124 bpf_rcu_read_lock();
125 local = global_mask;
126 if (!local) {
127 err = 4;
128 bpf_rcu_read_unlock();
129 return 0;
130 }
131
132 bpf_rcu_read_unlock();
133
134 /* RCU region is exited before calling KF_RCU kfunc. */
135
136 bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
137
138 return 0;
139}
140
141SEC("tp_btf/task_newtask")
142__failure __msg("NULL pointer passed to trusted arg1")
143int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone_flags)
144{
145 struct bpf_cpumask *local, *prev;
146
147 local = create_cpumask();
148 if (!local)
149 return 0;
150
151 prev = bpf_kptr_xchg(&global_mask, local);
152 if (prev) {
153 bpf_cpumask_release(prev);
154 err = 3;
155 return 0;
156 }
157
158 bpf_rcu_read_lock();
159 local = global_mask;
160
161 /* No NULL check is performed on global cpumask kptr. */
162 bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
163
164 bpf_rcu_read_unlock();
165
166 return 0;
167}
168
169SEC("tp_btf/task_newtask")
170__failure __msg("Possibly NULL pointer passed to helper arg2")
171int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags)
172{
173 struct bpf_cpumask *prev, *curr;
174
175 curr = bpf_cpumask_create();
176 if (!curr)
177 return 0;
178
179 prev = bpf_kptr_xchg(&global_mask, curr);
180 if (prev)
181 bpf_cpumask_release(prev);
182
183 bpf_rcu_read_lock();
184 curr = global_mask;
185 /* PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU passed to bpf_kptr_xchg() */
186 prev = bpf_kptr_xchg(&global_mask, curr);
187 bpf_rcu_read_unlock();
188 if (prev)
189 bpf_cpumask_release(prev);
190
191 return 0;
192}