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	/* Can't set the CPU of a non-struct bpf_cpumask. */
65	bpf_cpumask_set_cpu(0, (struct bpf_cpumask *)task->cpus_ptr);
66
67	return 0;
68}
69
70SEC("tp_btf/task_newtask")
71__failure __msg("Unreleased reference")
72int BPF_PROG(test_insert_remove_no_release, struct task_struct *task, u64 clone_flags)
73{
74	struct bpf_cpumask *cpumask;
75	struct __cpumask_map_value *v;
76
77	cpumask = create_cpumask();
78	if (!cpumask)
79		return 0;
80
81	if (cpumask_map_insert(cpumask))
82		return 0;
83
84	v = cpumask_map_value_lookup();
85	if (!v)
86		return 0;
87
88	cpumask = bpf_kptr_xchg(&v->cpumask, NULL);
89
90	/* cpumask is never released. */
91	return 0;
92}
93
94SEC("tp_btf/task_newtask")
95__failure __msg("NULL pointer passed to trusted arg0")
96int BPF_PROG(test_cpumask_null, struct task_struct *task, u64 clone_flags)
97{
98  /* NULL passed to KF_TRUSTED_ARGS kfunc. */
99	bpf_cpumask_empty(NULL);
100
101	return 0;
102}
103
104SEC("tp_btf/task_newtask")
105__failure __msg("R2 must be a rcu pointer")
106int BPF_PROG(test_global_mask_out_of_rcu, struct task_struct *task, u64 clone_flags)
107{
108	struct bpf_cpumask *local, *prev;
109
110	local = create_cpumask();
111	if (!local)
112		return 0;
113
114	prev = bpf_kptr_xchg(&global_mask, local);
115	if (prev) {
116		bpf_cpumask_release(prev);
117		err = 3;
118		return 0;
119	}
120
121	bpf_rcu_read_lock();
122	local = global_mask;
123	if (!local) {
124		err = 4;
125		bpf_rcu_read_unlock();
126		return 0;
127	}
128
129	bpf_rcu_read_unlock();
130
131	/* RCU region is exited before calling KF_RCU kfunc. */
132
133	bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
134
135	return 0;
136}
137
138SEC("tp_btf/task_newtask")
139__failure __msg("NULL pointer passed to trusted arg1")
140int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone_flags)
141{
142	struct bpf_cpumask *local, *prev;
143
144	local = create_cpumask();
145	if (!local)
146		return 0;
147
148	prev = bpf_kptr_xchg(&global_mask, local);
149	if (prev) {
150		bpf_cpumask_release(prev);
151		err = 3;
152		return 0;
153	}
154
155	bpf_rcu_read_lock();
156	local = global_mask;
157
158	/* No NULL check is performed on global cpumask kptr. */
159	bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
160
161	bpf_rcu_read_unlock();
162
163	return 0;
164}
165
166SEC("tp_btf/task_newtask")
167__failure __msg("Possibly NULL pointer passed to helper arg2")
168int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags)
169{
170	struct bpf_cpumask *prev, *curr;
171
172	curr = bpf_cpumask_create();
173	if (!curr)
174		return 0;
175
176	prev = bpf_kptr_xchg(&global_mask, curr);
177	if (prev)
178		bpf_cpumask_release(prev);
179
180	bpf_rcu_read_lock();
181	curr = global_mask;
182	/* PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU passed to bpf_kptr_xchg() */
183	prev = bpf_kptr_xchg(&global_mask, curr);
184	bpf_rcu_read_unlock();
185	if (prev)
186		bpf_cpumask_release(prev);
187
188	return 0;
189}
190