1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3
4#include <vmlinux.h>
5#include <bpf/bpf_tracing.h>
6#include <bpf/bpf_helpers.h>
7
8#include "bpf_misc.h"
9#include "task_kfunc_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
19static struct __tasks_kfunc_map_value *insert_lookup_task(struct task_struct *task)
20{
21	int status;
22
23	status = tasks_kfunc_map_insert(task);
24	if (status)
25		return NULL;
26
27	return tasks_kfunc_map_value_lookup(task);
28}
29
30SEC("tp_btf/task_newtask")
31__failure __msg("Possibly NULL pointer passed to trusted arg0")
32int BPF_PROG(task_kfunc_acquire_untrusted, struct task_struct *task, u64 clone_flags)
33{
34	struct task_struct *acquired;
35	struct __tasks_kfunc_map_value *v;
36
37	v = insert_lookup_task(task);
38	if (!v)
39		return 0;
40
41	/* Can't invoke bpf_task_acquire() on an untrusted pointer. */
42	acquired = bpf_task_acquire(v->task);
43	if (!acquired)
44		return 0;
45
46	bpf_task_release(acquired);
47
48	return 0;
49}
50
51SEC("tp_btf/task_newtask")
52__failure __msg("arg#0 pointer type STRUCT task_struct must point")
53int BPF_PROG(task_kfunc_acquire_fp, struct task_struct *task, u64 clone_flags)
54{
55	struct task_struct *acquired, *stack_task = (struct task_struct *)&clone_flags;
56
57	/* Can't invoke bpf_task_acquire() on a random frame pointer. */
58	acquired = bpf_task_acquire((struct task_struct *)&stack_task);
59	if (!acquired)
60		return 0;
61
62	bpf_task_release(acquired);
63
64	return 0;
65}
66
67SEC("kretprobe/free_task")
68__failure __msg("calling kernel function bpf_task_acquire is not allowed")
69int BPF_PROG(task_kfunc_acquire_unsafe_kretprobe, struct task_struct *task, u64 clone_flags)
70{
71	struct task_struct *acquired;
72
73	/* Can't call bpf_task_acquire() or bpf_task_release() in an untrusted prog. */
74	acquired = bpf_task_acquire(task);
75	if (!acquired)
76		return 0;
77	bpf_task_release(acquired);
78
79	return 0;
80}
81
82SEC("kretprobe/free_task")
83__failure __msg("calling kernel function bpf_task_acquire is not allowed")
84int BPF_PROG(task_kfunc_acquire_unsafe_kretprobe_rcu, struct task_struct *task, u64 clone_flags)
85{
86	struct task_struct *acquired;
87
88	bpf_rcu_read_lock();
89	if (!task) {
90		bpf_rcu_read_unlock();
91		return 0;
92	}
93	/* Can't call bpf_task_acquire() or bpf_task_release() in an untrusted prog. */
94	acquired = bpf_task_acquire(task);
95	if (acquired)
96		bpf_task_release(acquired);
97	bpf_rcu_read_unlock();
98
99	return 0;
100}
101
102SEC("tp_btf/task_newtask")
103__failure __msg("Possibly NULL pointer passed to trusted arg0")
104int BPF_PROG(task_kfunc_acquire_null, struct task_struct *task, u64 clone_flags)
105{
106	struct task_struct *acquired;
107
108	/* Can't invoke bpf_task_acquire() on a NULL pointer. */
109	acquired = bpf_task_acquire(NULL);
110	if (!acquired)
111		return 0;
112	bpf_task_release(acquired);
113
114	return 0;
115}
116
117SEC("tp_btf/task_newtask")
118__failure __msg("Unreleased reference")
119int BPF_PROG(task_kfunc_acquire_unreleased, struct task_struct *task, u64 clone_flags)
120{
121	struct task_struct *acquired;
122
123	acquired = bpf_task_acquire(task);
124
125	/* Acquired task is never released. */
126	__sink(acquired);
127
128	return 0;
129}
130
131SEC("tp_btf/task_newtask")
132__failure __msg("Unreleased reference")
133int BPF_PROG(task_kfunc_xchg_unreleased, struct task_struct *task, u64 clone_flags)
134{
135	struct task_struct *kptr;
136	struct __tasks_kfunc_map_value *v;
137
138	v = insert_lookup_task(task);
139	if (!v)
140		return 0;
141
142	kptr = bpf_kptr_xchg(&v->task, NULL);
143	if (!kptr)
144		return 0;
145
146	/* Kptr retrieved from map is never released. */
147
148	return 0;
149}
150
151SEC("tp_btf/task_newtask")
152__failure __msg("Possibly NULL pointer passed to trusted arg0")
153int BPF_PROG(task_kfunc_acquire_release_no_null_check, struct task_struct *task, u64 clone_flags)
154{
155	struct task_struct *acquired;
156
157	acquired = bpf_task_acquire(task);
158	/* Can't invoke bpf_task_release() on an acquired task without a NULL check. */
159	bpf_task_release(acquired);
160
161	return 0;
162}
163
164SEC("tp_btf/task_newtask")
165__failure __msg("Possibly NULL pointer passed to trusted arg0")
166int BPF_PROG(task_kfunc_release_untrusted, struct task_struct *task, u64 clone_flags)
167{
168	struct __tasks_kfunc_map_value *v;
169
170	v = insert_lookup_task(task);
171	if (!v)
172		return 0;
173
174	/* Can't invoke bpf_task_release() on an untrusted pointer. */
175	bpf_task_release(v->task);
176
177	return 0;
178}
179
180SEC("tp_btf/task_newtask")
181__failure __msg("arg#0 pointer type STRUCT task_struct must point")
182int BPF_PROG(task_kfunc_release_fp, struct task_struct *task, u64 clone_flags)
183{
184	struct task_struct *acquired = (struct task_struct *)&clone_flags;
185
186	/* Cannot release random frame pointer. */
187	bpf_task_release(acquired);
188
189	return 0;
190}
191
192SEC("tp_btf/task_newtask")
193__failure __msg("Possibly NULL pointer passed to trusted arg0")
194int BPF_PROG(task_kfunc_release_null, struct task_struct *task, u64 clone_flags)
195{
196	struct __tasks_kfunc_map_value local, *v;
197	long status;
198	struct task_struct *acquired, *old;
199	s32 pid;
200
201	status = bpf_probe_read_kernel(&pid, sizeof(pid), &task->pid);
202	if (status)
203		return 0;
204
205	local.task = NULL;
206	status = bpf_map_update_elem(&__tasks_kfunc_map, &pid, &local, BPF_NOEXIST);
207	if (status)
208		return status;
209
210	v = bpf_map_lookup_elem(&__tasks_kfunc_map, &pid);
211	if (!v)
212		return -ENOENT;
213
214	acquired = bpf_task_acquire(task);
215	if (!acquired)
216		return -EEXIST;
217
218	old = bpf_kptr_xchg(&v->task, acquired);
219
220	/* old cannot be passed to bpf_task_release() without a NULL check. */
221	bpf_task_release(old);
222
223	return 0;
224}
225
226SEC("tp_btf/task_newtask")
227__failure __msg("release kernel function bpf_task_release expects")
228int BPF_PROG(task_kfunc_release_unacquired, struct task_struct *task, u64 clone_flags)
229{
230	/* Cannot release trusted task pointer which was not acquired. */
231	bpf_task_release(task);
232
233	return 0;
234}
235
236SEC("tp_btf/task_newtask")
237__failure __msg("Possibly NULL pointer passed to trusted arg0")
238int BPF_PROG(task_kfunc_from_pid_no_null_check, struct task_struct *task, u64 clone_flags)
239{
240	struct task_struct *acquired;
241
242	acquired = bpf_task_from_pid(task->pid);
243
244	/* Releasing bpf_task_from_pid() lookup without a NULL check. */
245	bpf_task_release(acquired);
246
247	return 0;
248}
249
250SEC("lsm/task_free")
251__failure __msg("R1 must be a rcu pointer")
252int BPF_PROG(task_kfunc_from_lsm_task_free, struct task_struct *task)
253{
254	struct task_struct *acquired;
255
256	/* the argument of lsm task_free hook is untrusted. */
257	acquired = bpf_task_acquire(task);
258	if (!acquired)
259		return 0;
260
261	bpf_task_release(acquired);
262	return 0;
263}
264
265SEC("tp_btf/task_newtask")
266__failure __msg("access beyond the end of member comm")
267int BPF_PROG(task_access_comm1, struct task_struct *task, u64 clone_flags)
268{
269	bpf_strncmp(task->comm, 17, "foo");
270	return 0;
271}
272
273SEC("tp_btf/task_newtask")
274__failure __msg("access beyond the end of member comm")
275int BPF_PROG(task_access_comm2, struct task_struct *task, u64 clone_flags)
276{
277	bpf_strncmp(task->comm + 1, 16, "foo");
278	return 0;
279}
280
281SEC("tp_btf/task_newtask")
282__failure __msg("write into memory")
283int BPF_PROG(task_access_comm3, struct task_struct *task, u64 clone_flags)
284{
285	bpf_probe_read_kernel(task->comm, 16, task->comm);
286	return 0;
287}
288
289SEC("fentry/__set_task_comm")
290__failure __msg("R1 type=ptr_ expected")
291int BPF_PROG(task_access_comm4, struct task_struct *task, const char *buf, bool exec)
292{
293	/*
294	 * task->comm is a legacy ptr_to_btf_id. The verifier cannot guarantee
295	 * its safety. Hence it cannot be accessed with normal load insns.
296	 */
297	bpf_strncmp(task->comm, 16, "foo");
298	return 0;
299}
300
301SEC("tp_btf/task_newtask")
302__failure __msg("R1 must be referenced or trusted")
303int BPF_PROG(task_kfunc_release_in_map, struct task_struct *task, u64 clone_flags)
304{
305	struct task_struct *local;
306	struct __tasks_kfunc_map_value *v;
307
308	if (tasks_kfunc_map_insert(task))
309		return 0;
310
311	v = tasks_kfunc_map_value_lookup(task);
312	if (!v)
313		return 0;
314
315	bpf_rcu_read_lock();
316	local = v->task;
317	if (!local) {
318		bpf_rcu_read_unlock();
319		return 0;
320	}
321	/* Can't release a kptr that's still stored in a map. */
322	bpf_task_release(local);
323	bpf_rcu_read_unlock();
324
325	return 0;
326}
327