selftests/bpf: Fix erroneous bitmask operation
[platform/kernel/linux-rpi.git] / tools / testing / selftests / bpf / progs / cpumask_failure.c
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")
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")
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")
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")
62 int 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
73 SEC("tp_btf/task_newtask")
74 __failure __msg("Unreleased reference")
75 int 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
97 SEC("tp_btf/task_newtask")
98 __failure __msg("NULL pointer passed to trusted arg0")
99 int 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
107 SEC("tp_btf/task_newtask")
108 __failure __msg("R2 must be a rcu pointer")
109 int 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
141 SEC("tp_btf/task_newtask")
142 __failure __msg("NULL pointer passed to trusted arg1")
143 int 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
169 SEC("tp_btf/task_newtask")
170 __failure __msg("Possibly NULL pointer passed to helper arg2")
171 int 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 }