17b6abcfaSDavid Vernet // SPDX-License-Identifier: GPL-2.0
27b6abcfaSDavid Vernet /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
37b6abcfaSDavid Vernet
47b6abcfaSDavid Vernet #include <vmlinux.h>
57b6abcfaSDavid Vernet #include <bpf/bpf_tracing.h>
67b6abcfaSDavid Vernet #include <bpf/bpf_helpers.h>
77b6abcfaSDavid Vernet #include "bpf_misc.h"
87b6abcfaSDavid Vernet
97b6abcfaSDavid Vernet #include "cpumask_common.h"
107b6abcfaSDavid Vernet
117b6abcfaSDavid Vernet char _license[] SEC("license") = "GPL";
127b6abcfaSDavid Vernet
137b6abcfaSDavid Vernet /* Prototype for all of the program trace events below:
147b6abcfaSDavid Vernet *
157b6abcfaSDavid Vernet * TRACE_EVENT(task_newtask,
167b6abcfaSDavid Vernet * TP_PROTO(struct task_struct *p, u64 clone_flags)
177b6abcfaSDavid Vernet */
187b6abcfaSDavid Vernet
197b6abcfaSDavid Vernet SEC("tp_btf/task_newtask")
207b6abcfaSDavid Vernet __failure __msg("Unreleased reference")
BPF_PROG(test_alloc_no_release,struct task_struct * task,u64 clone_flags)217b6abcfaSDavid Vernet int BPF_PROG(test_alloc_no_release, struct task_struct *task, u64 clone_flags)
227b6abcfaSDavid Vernet {
237b6abcfaSDavid Vernet struct bpf_cpumask *cpumask;
247b6abcfaSDavid Vernet
257b6abcfaSDavid Vernet cpumask = create_cpumask();
26c8ed6685SAndrii Nakryiko __sink(cpumask);
277b6abcfaSDavid Vernet
287b6abcfaSDavid Vernet /* cpumask is never released. */
297b6abcfaSDavid Vernet return 0;
307b6abcfaSDavid Vernet }
317b6abcfaSDavid Vernet
327b6abcfaSDavid Vernet SEC("tp_btf/task_newtask")
337b6abcfaSDavid Vernet __failure __msg("NULL pointer passed to trusted arg0")
BPF_PROG(test_alloc_double_release,struct task_struct * task,u64 clone_flags)347b6abcfaSDavid Vernet int BPF_PROG(test_alloc_double_release, struct task_struct *task, u64 clone_flags)
357b6abcfaSDavid Vernet {
367b6abcfaSDavid Vernet struct bpf_cpumask *cpumask;
377b6abcfaSDavid Vernet
387b6abcfaSDavid Vernet cpumask = create_cpumask();
397b6abcfaSDavid Vernet
407b6abcfaSDavid Vernet /* cpumask is released twice. */
417b6abcfaSDavid Vernet bpf_cpumask_release(cpumask);
427b6abcfaSDavid Vernet bpf_cpumask_release(cpumask);
437b6abcfaSDavid Vernet
447b6abcfaSDavid Vernet return 0;
457b6abcfaSDavid Vernet }
467b6abcfaSDavid Vernet
477b6abcfaSDavid Vernet SEC("tp_btf/task_newtask")
486fcd486bSAlexei Starovoitov __failure __msg("must be referenced")
BPF_PROG(test_acquire_wrong_cpumask,struct task_struct * task,u64 clone_flags)497b6abcfaSDavid Vernet int BPF_PROG(test_acquire_wrong_cpumask, struct task_struct *task, u64 clone_flags)
507b6abcfaSDavid Vernet {
517b6abcfaSDavid Vernet struct bpf_cpumask *cpumask;
527b6abcfaSDavid Vernet
537b6abcfaSDavid Vernet /* Can't acquire a non-struct bpf_cpumask. */
547b6abcfaSDavid Vernet cpumask = bpf_cpumask_acquire((struct bpf_cpumask *)task->cpus_ptr);
55c8ed6685SAndrii Nakryiko __sink(cpumask);
567b6abcfaSDavid Vernet
577b6abcfaSDavid Vernet return 0;
587b6abcfaSDavid Vernet }
597b6abcfaSDavid Vernet
607b6abcfaSDavid Vernet SEC("tp_btf/task_newtask")
617b6abcfaSDavid Vernet __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)627b6abcfaSDavid Vernet int BPF_PROG(test_mutate_cpumask, struct task_struct *task, u64 clone_flags)
637b6abcfaSDavid Vernet {
647b6abcfaSDavid Vernet /* Can't set the CPU of a non-struct bpf_cpumask. */
657b6abcfaSDavid Vernet bpf_cpumask_set_cpu(0, (struct bpf_cpumask *)task->cpus_ptr);
667b6abcfaSDavid Vernet
677b6abcfaSDavid Vernet return 0;
687b6abcfaSDavid Vernet }
697b6abcfaSDavid Vernet
707b6abcfaSDavid Vernet SEC("tp_btf/task_newtask")
717b6abcfaSDavid Vernet __failure __msg("Unreleased reference")
BPF_PROG(test_insert_remove_no_release,struct task_struct * task,u64 clone_flags)727b6abcfaSDavid Vernet int BPF_PROG(test_insert_remove_no_release, struct task_struct *task, u64 clone_flags)
737b6abcfaSDavid Vernet {
747b6abcfaSDavid Vernet struct bpf_cpumask *cpumask;
757b6abcfaSDavid Vernet struct __cpumask_map_value *v;
767b6abcfaSDavid Vernet
777b6abcfaSDavid Vernet cpumask = create_cpumask();
787b6abcfaSDavid Vernet if (!cpumask)
797b6abcfaSDavid Vernet return 0;
807b6abcfaSDavid Vernet
817b6abcfaSDavid Vernet if (cpumask_map_insert(cpumask))
827b6abcfaSDavid Vernet return 0;
837b6abcfaSDavid Vernet
847b6abcfaSDavid Vernet v = cpumask_map_value_lookup();
857b6abcfaSDavid Vernet if (!v)
867b6abcfaSDavid Vernet return 0;
877b6abcfaSDavid Vernet
887b6abcfaSDavid Vernet cpumask = bpf_kptr_xchg(&v->cpumask, NULL);
897b6abcfaSDavid Vernet
907b6abcfaSDavid Vernet /* cpumask is never released. */
917b6abcfaSDavid Vernet return 0;
927b6abcfaSDavid Vernet }
937b6abcfaSDavid Vernet
947b6abcfaSDavid Vernet SEC("tp_btf/task_newtask")
957b6abcfaSDavid Vernet __failure __msg("NULL pointer passed to trusted arg0")
BPF_PROG(test_cpumask_null,struct task_struct * task,u64 clone_flags)967b6abcfaSDavid Vernet int BPF_PROG(test_cpumask_null, struct task_struct *task, u64 clone_flags)
977b6abcfaSDavid Vernet {
987b6abcfaSDavid Vernet /* NULL passed to KF_TRUSTED_ARGS kfunc. */
997b6abcfaSDavid Vernet bpf_cpumask_empty(NULL);
1007b6abcfaSDavid Vernet
1017b6abcfaSDavid Vernet return 0;
1027b6abcfaSDavid Vernet }
103a5a197dfSDavid Vernet
104a5a197dfSDavid Vernet SEC("tp_btf/task_newtask")
105a5a197dfSDavid Vernet __failure __msg("R2 must be a rcu pointer")
BPF_PROG(test_global_mask_out_of_rcu,struct task_struct * task,u64 clone_flags)106a5a197dfSDavid Vernet int BPF_PROG(test_global_mask_out_of_rcu, struct task_struct *task, u64 clone_flags)
107a5a197dfSDavid Vernet {
108a5a197dfSDavid Vernet struct bpf_cpumask *local, *prev;
109a5a197dfSDavid Vernet
110a5a197dfSDavid Vernet local = create_cpumask();
111a5a197dfSDavid Vernet if (!local)
112a5a197dfSDavid Vernet return 0;
113a5a197dfSDavid Vernet
114a5a197dfSDavid Vernet prev = bpf_kptr_xchg(&global_mask, local);
115a5a197dfSDavid Vernet if (prev) {
116a5a197dfSDavid Vernet bpf_cpumask_release(prev);
117a5a197dfSDavid Vernet err = 3;
118a5a197dfSDavid Vernet return 0;
119a5a197dfSDavid Vernet }
120a5a197dfSDavid Vernet
121a5a197dfSDavid Vernet bpf_rcu_read_lock();
122a5a197dfSDavid Vernet local = global_mask;
123a5a197dfSDavid Vernet if (!local) {
124a5a197dfSDavid Vernet err = 4;
125a5a197dfSDavid Vernet bpf_rcu_read_unlock();
126a5a197dfSDavid Vernet return 0;
127a5a197dfSDavid Vernet }
128a5a197dfSDavid Vernet
129a5a197dfSDavid Vernet bpf_rcu_read_unlock();
130a5a197dfSDavid Vernet
131a5a197dfSDavid Vernet /* RCU region is exited before calling KF_RCU kfunc. */
132a5a197dfSDavid Vernet
133a5a197dfSDavid Vernet bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
134a5a197dfSDavid Vernet
135a5a197dfSDavid Vernet return 0;
136a5a197dfSDavid Vernet }
137a5a197dfSDavid Vernet
138a5a197dfSDavid Vernet SEC("tp_btf/task_newtask")
139a5a197dfSDavid Vernet __failure __msg("NULL pointer passed to trusted arg1")
BPF_PROG(test_global_mask_no_null_check,struct task_struct * task,u64 clone_flags)140a5a197dfSDavid Vernet int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone_flags)
141a5a197dfSDavid Vernet {
142a5a197dfSDavid Vernet struct bpf_cpumask *local, *prev;
143a5a197dfSDavid Vernet
144a5a197dfSDavid Vernet local = create_cpumask();
145a5a197dfSDavid Vernet if (!local)
146a5a197dfSDavid Vernet return 0;
147a5a197dfSDavid Vernet
148a5a197dfSDavid Vernet prev = bpf_kptr_xchg(&global_mask, local);
149a5a197dfSDavid Vernet if (prev) {
150a5a197dfSDavid Vernet bpf_cpumask_release(prev);
151a5a197dfSDavid Vernet err = 3;
152a5a197dfSDavid Vernet return 0;
153a5a197dfSDavid Vernet }
154a5a197dfSDavid Vernet
155a5a197dfSDavid Vernet bpf_rcu_read_lock();
156a5a197dfSDavid Vernet local = global_mask;
157a5a197dfSDavid Vernet
158a5a197dfSDavid Vernet /* No NULL check is performed on global cpumask kptr. */
159a5a197dfSDavid Vernet bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
160a5a197dfSDavid Vernet
161a5a197dfSDavid Vernet bpf_rcu_read_unlock();
162a5a197dfSDavid Vernet
163a5a197dfSDavid Vernet return 0;
164a5a197dfSDavid Vernet }
165*67efbd57SDavid Vernet
166*67efbd57SDavid Vernet SEC("tp_btf/task_newtask")
167*67efbd57SDavid Vernet __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*67efbd57SDavid Vernet int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags)
169*67efbd57SDavid Vernet {
170*67efbd57SDavid Vernet struct bpf_cpumask *prev, *curr;
171*67efbd57SDavid Vernet
172*67efbd57SDavid Vernet curr = bpf_cpumask_create();
173*67efbd57SDavid Vernet if (!curr)
174*67efbd57SDavid Vernet return 0;
175*67efbd57SDavid Vernet
176*67efbd57SDavid Vernet prev = bpf_kptr_xchg(&global_mask, curr);
177*67efbd57SDavid Vernet if (prev)
178*67efbd57SDavid Vernet bpf_cpumask_release(prev);
179*67efbd57SDavid Vernet
180*67efbd57SDavid Vernet bpf_rcu_read_lock();
181*67efbd57SDavid Vernet curr = global_mask;
182*67efbd57SDavid Vernet /* PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU passed to bpf_kptr_xchg() */
183*67efbd57SDavid Vernet prev = bpf_kptr_xchg(&global_mask, curr);
184*67efbd57SDavid Vernet bpf_rcu_read_unlock();
185*67efbd57SDavid Vernet if (prev)
186*67efbd57SDavid Vernet bpf_cpumask_release(prev);
187*67efbd57SDavid Vernet
188*67efbd57SDavid Vernet return 0;
189*67efbd57SDavid Vernet }
190