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