xref: /linux/tools/testing/selftests/bpf/progs/cpumask_failure.c (revision 3d5ad2d4eca337e80f38df77de89614aa5aaceb9)
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 struct kptr_nested_array_2 {
14 	struct bpf_cpumask __kptr * mask;
15 };
16 
17 struct 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 
22 struct kptr_nested_array {
23 	struct kptr_nested_array_1 d_1;
24 };
25 
26 private(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 
34 SEC("tp_btf/task_newtask")
35 __failure __msg("Unreleased reference")
BPF_PROG(test_alloc_no_release,struct task_struct * task,u64 clone_flags)36 int 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 
47 SEC("tp_btf/task_newtask")
48 __failure __msg("NULL pointer passed to trusted arg0")
BPF_PROG(test_alloc_double_release,struct task_struct * task,u64 clone_flags)49 int 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 
62 SEC("tp_btf/task_newtask")
63 __failure __msg("must be referenced")
BPF_PROG(test_acquire_wrong_cpumask,struct task_struct * task,u64 clone_flags)64 int 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 
75 SEC("tp_btf/task_newtask")
76 __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)77 int 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 
85 SEC("tp_btf/task_newtask")
86 __failure __msg("Unreleased reference")
BPF_PROG(test_insert_remove_no_release,struct task_struct * task,u64 clone_flags)87 int 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 
109 SEC("tp_btf/task_newtask")
110 __failure __msg("NULL pointer passed to trusted arg0")
BPF_PROG(test_cpumask_null,struct task_struct * task,u64 clone_flags)111 int 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 
119 SEC("tp_btf/task_newtask")
120 __failure __msg("R2 must be a rcu pointer")
BPF_PROG(test_global_mask_out_of_rcu,struct task_struct * task,u64 clone_flags)121 int 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 
153 SEC("tp_btf/task_newtask")
154 __failure __msg("NULL pointer passed to trusted arg1")
BPF_PROG(test_global_mask_no_null_check,struct task_struct * task,u64 clone_flags)155 int 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 
181 SEC("tp_btf/task_newtask")
182 __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)183 int 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 
206 SEC("tp_btf/task_newtask")
207 __failure __msg("has no valid kptr")
BPF_PROG(test_invalid_nested_array,struct task_struct * task,u64 clone_flags)208 int 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 }
225