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 	struct bpf_cpumask *cpumask;
657b6abcfaSDavid Vernet 
667b6abcfaSDavid Vernet 	/* Can't set the CPU of a non-struct bpf_cpumask. */
677b6abcfaSDavid Vernet 	bpf_cpumask_set_cpu(0, (struct bpf_cpumask *)task->cpus_ptr);
68c8ed6685SAndrii Nakryiko 	__sink(cpumask);
697b6abcfaSDavid Vernet 
707b6abcfaSDavid Vernet 	return 0;
717b6abcfaSDavid Vernet }
727b6abcfaSDavid Vernet 
737b6abcfaSDavid Vernet SEC("tp_btf/task_newtask")
747b6abcfaSDavid Vernet __failure __msg("Unreleased reference")
BPF_PROG(test_insert_remove_no_release,struct task_struct * task,u64 clone_flags)757b6abcfaSDavid Vernet int BPF_PROG(test_insert_remove_no_release, struct task_struct *task, u64 clone_flags)
767b6abcfaSDavid Vernet {
777b6abcfaSDavid Vernet 	struct bpf_cpumask *cpumask;
787b6abcfaSDavid Vernet 	struct __cpumask_map_value *v;
797b6abcfaSDavid Vernet 
807b6abcfaSDavid Vernet 	cpumask = create_cpumask();
817b6abcfaSDavid Vernet 	if (!cpumask)
827b6abcfaSDavid Vernet 		return 0;
837b6abcfaSDavid Vernet 
847b6abcfaSDavid Vernet 	if (cpumask_map_insert(cpumask))
857b6abcfaSDavid Vernet 		return 0;
867b6abcfaSDavid Vernet 
877b6abcfaSDavid Vernet 	v = cpumask_map_value_lookup();
887b6abcfaSDavid Vernet 	if (!v)
897b6abcfaSDavid Vernet 		return 0;
907b6abcfaSDavid Vernet 
917b6abcfaSDavid Vernet 	cpumask = bpf_kptr_xchg(&v->cpumask, NULL);
927b6abcfaSDavid Vernet 
937b6abcfaSDavid Vernet 	/* cpumask is never released. */
947b6abcfaSDavid Vernet 	return 0;
957b6abcfaSDavid Vernet }
967b6abcfaSDavid Vernet 
977b6abcfaSDavid Vernet SEC("tp_btf/task_newtask")
987b6abcfaSDavid Vernet __failure __msg("NULL pointer passed to trusted arg0")
BPF_PROG(test_cpumask_null,struct task_struct * task,u64 clone_flags)997b6abcfaSDavid Vernet int BPF_PROG(test_cpumask_null, struct task_struct *task, u64 clone_flags)
1007b6abcfaSDavid Vernet {
1017b6abcfaSDavid Vernet   /* NULL passed to KF_TRUSTED_ARGS kfunc. */
1027b6abcfaSDavid Vernet 	bpf_cpumask_empty(NULL);
1037b6abcfaSDavid Vernet 
1047b6abcfaSDavid Vernet 	return 0;
1057b6abcfaSDavid Vernet }
106a5a197dfSDavid Vernet 
107a5a197dfSDavid Vernet SEC("tp_btf/task_newtask")
108a5a197dfSDavid Vernet __failure __msg("R2 must be a rcu pointer")
BPF_PROG(test_global_mask_out_of_rcu,struct task_struct * task,u64 clone_flags)109a5a197dfSDavid Vernet int BPF_PROG(test_global_mask_out_of_rcu, struct task_struct *task, u64 clone_flags)
110a5a197dfSDavid Vernet {
111a5a197dfSDavid Vernet 	struct bpf_cpumask *local, *prev;
112a5a197dfSDavid Vernet 
113a5a197dfSDavid Vernet 	local = create_cpumask();
114a5a197dfSDavid Vernet 	if (!local)
115a5a197dfSDavid Vernet 		return 0;
116a5a197dfSDavid Vernet 
117a5a197dfSDavid Vernet 	prev = bpf_kptr_xchg(&global_mask, local);
118a5a197dfSDavid Vernet 	if (prev) {
119a5a197dfSDavid Vernet 		bpf_cpumask_release(prev);
120a5a197dfSDavid Vernet 		err = 3;
121a5a197dfSDavid Vernet 		return 0;
122a5a197dfSDavid Vernet 	}
123a5a197dfSDavid Vernet 
124a5a197dfSDavid Vernet 	bpf_rcu_read_lock();
125a5a197dfSDavid Vernet 	local = global_mask;
126a5a197dfSDavid Vernet 	if (!local) {
127a5a197dfSDavid Vernet 		err = 4;
128a5a197dfSDavid Vernet 		bpf_rcu_read_unlock();
129a5a197dfSDavid Vernet 		return 0;
130a5a197dfSDavid Vernet 	}
131a5a197dfSDavid Vernet 
132a5a197dfSDavid Vernet 	bpf_rcu_read_unlock();
133a5a197dfSDavid Vernet 
134a5a197dfSDavid Vernet 	/* RCU region is exited before calling KF_RCU kfunc. */
135a5a197dfSDavid Vernet 
136a5a197dfSDavid Vernet 	bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
137a5a197dfSDavid Vernet 
138a5a197dfSDavid Vernet 	return 0;
139a5a197dfSDavid Vernet }
140a5a197dfSDavid Vernet 
141a5a197dfSDavid Vernet SEC("tp_btf/task_newtask")
142a5a197dfSDavid Vernet __failure __msg("NULL pointer passed to trusted arg1")
BPF_PROG(test_global_mask_no_null_check,struct task_struct * task,u64 clone_flags)143a5a197dfSDavid Vernet int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone_flags)
144a5a197dfSDavid Vernet {
145a5a197dfSDavid Vernet 	struct bpf_cpumask *local, *prev;
146a5a197dfSDavid Vernet 
147a5a197dfSDavid Vernet 	local = create_cpumask();
148a5a197dfSDavid Vernet 	if (!local)
149a5a197dfSDavid Vernet 		return 0;
150a5a197dfSDavid Vernet 
151a5a197dfSDavid Vernet 	prev = bpf_kptr_xchg(&global_mask, local);
152a5a197dfSDavid Vernet 	if (prev) {
153a5a197dfSDavid Vernet 		bpf_cpumask_release(prev);
154a5a197dfSDavid Vernet 		err = 3;
155a5a197dfSDavid Vernet 		return 0;
156a5a197dfSDavid Vernet 	}
157a5a197dfSDavid Vernet 
158a5a197dfSDavid Vernet 	bpf_rcu_read_lock();
159a5a197dfSDavid Vernet 	local = global_mask;
160a5a197dfSDavid Vernet 
161a5a197dfSDavid Vernet 	/* No NULL check is performed on global cpumask kptr. */
162a5a197dfSDavid Vernet 	bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
163a5a197dfSDavid Vernet 
164a5a197dfSDavid Vernet 	bpf_rcu_read_unlock();
165a5a197dfSDavid Vernet 
166a5a197dfSDavid Vernet 	return 0;
167a5a197dfSDavid Vernet }
168*67efbd57SDavid Vernet 
169*67efbd57SDavid Vernet SEC("tp_btf/task_newtask")
170*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)171*67efbd57SDavid Vernet int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags)
172*67efbd57SDavid Vernet {
173*67efbd57SDavid Vernet 	struct bpf_cpumask *prev, *curr;
174*67efbd57SDavid Vernet 
175*67efbd57SDavid Vernet 	curr = bpf_cpumask_create();
176*67efbd57SDavid Vernet 	if (!curr)
177*67efbd57SDavid Vernet 		return 0;
178*67efbd57SDavid Vernet 
179*67efbd57SDavid Vernet 	prev = bpf_kptr_xchg(&global_mask, curr);
180*67efbd57SDavid Vernet 	if (prev)
181*67efbd57SDavid Vernet 		bpf_cpumask_release(prev);
182*67efbd57SDavid Vernet 
183*67efbd57SDavid Vernet 	bpf_rcu_read_lock();
184*67efbd57SDavid Vernet 	curr = global_mask;
185*67efbd57SDavid Vernet 	/* PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU passed to bpf_kptr_xchg() */
186*67efbd57SDavid Vernet 	prev = bpf_kptr_xchg(&global_mask, curr);
187*67efbd57SDavid Vernet 	bpf_rcu_read_unlock();
188*67efbd57SDavid Vernet 	if (prev)
189*67efbd57SDavid Vernet 		bpf_cpumask_release(prev);
190*67efbd57SDavid Vernet 
191*67efbd57SDavid Vernet 	return 0;
192*67efbd57SDavid Vernet }
193