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
8fe147956SDavid Vernet #include "task_kfunc_common.h"
9fe147956SDavid Vernet
10fe147956SDavid Vernet char _license[] SEC("license") = "GPL";
11fe147956SDavid Vernet
12fe147956SDavid Vernet int err, pid;
13fe147956SDavid Vernet
14fe147956SDavid Vernet /* Prototype for all of the program trace events below:
15fe147956SDavid Vernet *
16fe147956SDavid Vernet * TRACE_EVENT(task_newtask,
17fe147956SDavid Vernet * TP_PROTO(struct task_struct *p, u64 clone_flags)
18fe147956SDavid Vernet */
19fe147956SDavid Vernet
2095fdf6e3SAlexei Starovoitov struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym __weak;
21*63ae8eb2SDave Marchevsky
22*63ae8eb2SDave Marchevsky struct task_struct *bpf_task_acquire___one(struct task_struct *task) __ksym __weak;
23*63ae8eb2SDave Marchevsky /* The two-param bpf_task_acquire doesn't exist */
24*63ae8eb2SDave Marchevsky struct task_struct *bpf_task_acquire___two(struct task_struct *p, void *ctx) __ksym __weak;
25*63ae8eb2SDave Marchevsky /* Incorrect type for first param */
26*63ae8eb2SDave Marchevsky struct task_struct *bpf_task_acquire___three(void *ctx) __ksym __weak;
27*63ae8eb2SDave Marchevsky
2895fdf6e3SAlexei Starovoitov void invalid_kfunc(void) __ksym __weak;
2995fdf6e3SAlexei Starovoitov void bpf_testmod_test_mod_kfunc(int i) __ksym __weak;
3095fdf6e3SAlexei Starovoitov
is_test_kfunc_task(void)31fe147956SDavid Vernet static bool is_test_kfunc_task(void)
32fe147956SDavid Vernet {
33fe147956SDavid Vernet int cur_pid = bpf_get_current_pid_tgid() >> 32;
34fe147956SDavid Vernet
35fe147956SDavid Vernet return pid == cur_pid;
36fe147956SDavid Vernet }
37fe147956SDavid Vernet
test_acquire_release(struct task_struct * task)38fe147956SDavid Vernet static int test_acquire_release(struct task_struct *task)
39fe147956SDavid Vernet {
4095fdf6e3SAlexei Starovoitov struct task_struct *acquired = NULL;
4195fdf6e3SAlexei Starovoitov
4295fdf6e3SAlexei Starovoitov if (!bpf_ksym_exists(bpf_task_acquire)) {
4395fdf6e3SAlexei Starovoitov err = 3;
4495fdf6e3SAlexei Starovoitov return 0;
4595fdf6e3SAlexei Starovoitov }
4695fdf6e3SAlexei Starovoitov if (!bpf_ksym_exists(bpf_testmod_test_mod_kfunc)) {
4795fdf6e3SAlexei Starovoitov err = 4;
4895fdf6e3SAlexei Starovoitov return 0;
4995fdf6e3SAlexei Starovoitov }
5095fdf6e3SAlexei Starovoitov if (bpf_ksym_exists(invalid_kfunc)) {
5195fdf6e3SAlexei Starovoitov /* the verifier's dead code elimination should remove this */
5295fdf6e3SAlexei Starovoitov err = 5;
5395fdf6e3SAlexei Starovoitov asm volatile ("goto -1"); /* for (;;); */
5495fdf6e3SAlexei Starovoitov }
55fe147956SDavid Vernet
56fe147956SDavid Vernet acquired = bpf_task_acquire(task);
57d02c48faSDavid Vernet if (acquired)
58fe147956SDavid Vernet bpf_task_release(acquired);
59d02c48faSDavid Vernet else
60d02c48faSDavid Vernet err = 6;
61fe147956SDavid Vernet
62fe147956SDavid Vernet return 0;
63fe147956SDavid Vernet }
64fe147956SDavid Vernet
65fe147956SDavid Vernet SEC("tp_btf/task_newtask")
BPF_PROG(test_task_kfunc_flavor_relo,struct task_struct * task,u64 clone_flags)66*63ae8eb2SDave Marchevsky int BPF_PROG(test_task_kfunc_flavor_relo, struct task_struct *task, u64 clone_flags)
67*63ae8eb2SDave Marchevsky {
68*63ae8eb2SDave Marchevsky struct task_struct *acquired = NULL;
69*63ae8eb2SDave Marchevsky int fake_ctx = 42;
70*63ae8eb2SDave Marchevsky
71*63ae8eb2SDave Marchevsky if (bpf_ksym_exists(bpf_task_acquire___one)) {
72*63ae8eb2SDave Marchevsky acquired = bpf_task_acquire___one(task);
73*63ae8eb2SDave Marchevsky } else if (bpf_ksym_exists(bpf_task_acquire___two)) {
74*63ae8eb2SDave Marchevsky /* Here, bpf_object__resolve_ksym_func_btf_id's find_ksym_btf_id
75*63ae8eb2SDave Marchevsky * call will find vmlinux's bpf_task_acquire, but subsequent
76*63ae8eb2SDave Marchevsky * bpf_core_types_are_compat will fail
77*63ae8eb2SDave Marchevsky */
78*63ae8eb2SDave Marchevsky acquired = bpf_task_acquire___two(task, &fake_ctx);
79*63ae8eb2SDave Marchevsky err = 3;
80*63ae8eb2SDave Marchevsky return 0;
81*63ae8eb2SDave Marchevsky } else if (bpf_ksym_exists(bpf_task_acquire___three)) {
82*63ae8eb2SDave Marchevsky /* bpf_core_types_are_compat will fail similarly to above case */
83*63ae8eb2SDave Marchevsky acquired = bpf_task_acquire___three(&fake_ctx);
84*63ae8eb2SDave Marchevsky err = 4;
85*63ae8eb2SDave Marchevsky return 0;
86*63ae8eb2SDave Marchevsky }
87*63ae8eb2SDave Marchevsky
88*63ae8eb2SDave Marchevsky if (acquired)
89*63ae8eb2SDave Marchevsky bpf_task_release(acquired);
90*63ae8eb2SDave Marchevsky else
91*63ae8eb2SDave Marchevsky err = 5;
92*63ae8eb2SDave Marchevsky return 0;
93*63ae8eb2SDave Marchevsky }
94*63ae8eb2SDave Marchevsky
95*63ae8eb2SDave Marchevsky SEC("tp_btf/task_newtask")
BPF_PROG(test_task_kfunc_flavor_relo_not_found,struct task_struct * task,u64 clone_flags)96*63ae8eb2SDave Marchevsky int BPF_PROG(test_task_kfunc_flavor_relo_not_found, struct task_struct *task, u64 clone_flags)
97*63ae8eb2SDave Marchevsky {
98*63ae8eb2SDave Marchevsky /* Neither symbol should successfully resolve.
99*63ae8eb2SDave Marchevsky * Success or failure of one ___flavor should not affect others
100*63ae8eb2SDave Marchevsky */
101*63ae8eb2SDave Marchevsky if (bpf_ksym_exists(bpf_task_acquire___two))
102*63ae8eb2SDave Marchevsky err = 1;
103*63ae8eb2SDave Marchevsky else if (bpf_ksym_exists(bpf_task_acquire___three))
104*63ae8eb2SDave Marchevsky err = 2;
105*63ae8eb2SDave Marchevsky
106*63ae8eb2SDave Marchevsky return 0;
107*63ae8eb2SDave Marchevsky }
108*63ae8eb2SDave Marchevsky
109*63ae8eb2SDave Marchevsky SEC("tp_btf/task_newtask")
BPF_PROG(test_task_acquire_release_argument,struct task_struct * task,u64 clone_flags)110fe147956SDavid Vernet int BPF_PROG(test_task_acquire_release_argument, struct task_struct *task, u64 clone_flags)
111fe147956SDavid Vernet {
112fe147956SDavid Vernet if (!is_test_kfunc_task())
113fe147956SDavid Vernet return 0;
114fe147956SDavid Vernet
115fe147956SDavid Vernet return test_acquire_release(task);
116fe147956SDavid Vernet }
117fe147956SDavid Vernet
118fe147956SDavid Vernet SEC("tp_btf/task_newtask")
BPF_PROG(test_task_acquire_release_current,struct task_struct * task,u64 clone_flags)119fe147956SDavid Vernet int BPF_PROG(test_task_acquire_release_current, struct task_struct *task, u64 clone_flags)
120fe147956SDavid Vernet {
121fe147956SDavid Vernet if (!is_test_kfunc_task())
122fe147956SDavid Vernet return 0;
123fe147956SDavid Vernet
124fe147956SDavid Vernet return test_acquire_release(bpf_get_current_task_btf());
125fe147956SDavid Vernet }
126fe147956SDavid Vernet
127fe147956SDavid Vernet SEC("tp_btf/task_newtask")
BPF_PROG(test_task_acquire_leave_in_map,struct task_struct * task,u64 clone_flags)128fe147956SDavid Vernet int BPF_PROG(test_task_acquire_leave_in_map, struct task_struct *task, u64 clone_flags)
129fe147956SDavid Vernet {
130fe147956SDavid Vernet long status;
131fe147956SDavid Vernet
132fe147956SDavid Vernet if (!is_test_kfunc_task())
133fe147956SDavid Vernet return 0;
134fe147956SDavid Vernet
135fe147956SDavid Vernet status = tasks_kfunc_map_insert(task);
136fe147956SDavid Vernet if (status)
137fe147956SDavid Vernet err = 1;
138fe147956SDavid Vernet
139fe147956SDavid Vernet return 0;
140fe147956SDavid Vernet }
141fe147956SDavid Vernet
142fe147956SDavid Vernet SEC("tp_btf/task_newtask")
BPF_PROG(test_task_xchg_release,struct task_struct * task,u64 clone_flags)143fe147956SDavid Vernet int BPF_PROG(test_task_xchg_release, struct task_struct *task, u64 clone_flags)
144fe147956SDavid Vernet {
145fe147956SDavid Vernet struct task_struct *kptr;
146fe147956SDavid Vernet struct __tasks_kfunc_map_value *v;
147fe147956SDavid Vernet long status;
148fe147956SDavid Vernet
149fe147956SDavid Vernet if (!is_test_kfunc_task())
150fe147956SDavid Vernet return 0;
151fe147956SDavid Vernet
152fe147956SDavid Vernet status = tasks_kfunc_map_insert(task);
153fe147956SDavid Vernet if (status) {
154fe147956SDavid Vernet err = 1;
155fe147956SDavid Vernet return 0;
156fe147956SDavid Vernet }
157fe147956SDavid Vernet
158fe147956SDavid Vernet v = tasks_kfunc_map_value_lookup(task);
159fe147956SDavid Vernet if (!v) {
160fe147956SDavid Vernet err = 2;
161fe147956SDavid Vernet return 0;
162fe147956SDavid Vernet }
163fe147956SDavid Vernet
164fe147956SDavid Vernet kptr = bpf_kptr_xchg(&v->task, NULL);
165fe147956SDavid Vernet if (!kptr) {
166fe147956SDavid Vernet err = 3;
167fe147956SDavid Vernet return 0;
168fe147956SDavid Vernet }
169fe147956SDavid Vernet
170fe147956SDavid Vernet bpf_task_release(kptr);
171fe147956SDavid Vernet
172fe147956SDavid Vernet return 0;
173fe147956SDavid Vernet }
174fe147956SDavid Vernet
175fe147956SDavid Vernet SEC("tp_btf/task_newtask")
BPF_PROG(test_task_map_acquire_release,struct task_struct * task,u64 clone_flags)176f85671c6SDavid Vernet int BPF_PROG(test_task_map_acquire_release, struct task_struct *task, u64 clone_flags)
177fe147956SDavid Vernet {
178fe147956SDavid Vernet struct task_struct *kptr;
179fe147956SDavid Vernet struct __tasks_kfunc_map_value *v;
180fe147956SDavid Vernet long status;
181fe147956SDavid Vernet
182fe147956SDavid Vernet if (!is_test_kfunc_task())
183fe147956SDavid Vernet return 0;
184fe147956SDavid Vernet
185fe147956SDavid Vernet status = tasks_kfunc_map_insert(task);
186fe147956SDavid Vernet if (status) {
187fe147956SDavid Vernet err = 1;
188fe147956SDavid Vernet return 0;
189fe147956SDavid Vernet }
190fe147956SDavid Vernet
191fe147956SDavid Vernet v = tasks_kfunc_map_value_lookup(task);
192fe147956SDavid Vernet if (!v) {
193fe147956SDavid Vernet err = 2;
194fe147956SDavid Vernet return 0;
195fe147956SDavid Vernet }
196fe147956SDavid Vernet
197f85671c6SDavid Vernet bpf_rcu_read_lock();
198f85671c6SDavid Vernet kptr = v->task;
199f85671c6SDavid Vernet if (!kptr) {
200fe147956SDavid Vernet err = 3;
201f85671c6SDavid Vernet } else {
202f85671c6SDavid Vernet kptr = bpf_task_acquire(kptr);
203f85671c6SDavid Vernet if (!kptr)
204f85671c6SDavid Vernet err = 4;
205f85671c6SDavid Vernet else
206f85671c6SDavid Vernet bpf_task_release(kptr);
207fe147956SDavid Vernet }
208f85671c6SDavid Vernet bpf_rcu_read_unlock();
209fe147956SDavid Vernet
210fe147956SDavid Vernet return 0;
211fe147956SDavid Vernet }
212fe147956SDavid Vernet
213fe147956SDavid Vernet SEC("tp_btf/task_newtask")
BPF_PROG(test_task_current_acquire_release,struct task_struct * task,u64 clone_flags)214fe147956SDavid Vernet int BPF_PROG(test_task_current_acquire_release, struct task_struct *task, u64 clone_flags)
215fe147956SDavid Vernet {
216fe147956SDavid Vernet struct task_struct *current, *acquired;
217fe147956SDavid Vernet
218fe147956SDavid Vernet if (!is_test_kfunc_task())
219fe147956SDavid Vernet return 0;
220fe147956SDavid Vernet
221fe147956SDavid Vernet current = bpf_get_current_task_btf();
222fe147956SDavid Vernet acquired = bpf_task_acquire(current);
223d02c48faSDavid Vernet if (acquired)
224fe147956SDavid Vernet bpf_task_release(acquired);
225d02c48faSDavid Vernet else
226d02c48faSDavid Vernet err = 1;
227fe147956SDavid Vernet
228fe147956SDavid Vernet return 0;
229fe147956SDavid Vernet }
230f471748bSDavid Vernet
lookup_compare_pid(const struct task_struct * p)231f471748bSDavid Vernet static void lookup_compare_pid(const struct task_struct *p)
232f471748bSDavid Vernet {
233f471748bSDavid Vernet struct task_struct *acquired;
234f471748bSDavid Vernet
235f471748bSDavid Vernet acquired = bpf_task_from_pid(p->pid);
236f471748bSDavid Vernet if (!acquired) {
237f471748bSDavid Vernet err = 1;
238f471748bSDavid Vernet return;
239f471748bSDavid Vernet }
240f471748bSDavid Vernet
241f471748bSDavid Vernet if (acquired->pid != p->pid)
242f471748bSDavid Vernet err = 2;
243f471748bSDavid Vernet bpf_task_release(acquired);
244f471748bSDavid Vernet }
245f471748bSDavid Vernet
246f471748bSDavid Vernet SEC("tp_btf/task_newtask")
BPF_PROG(test_task_from_pid_arg,struct task_struct * task,u64 clone_flags)247f471748bSDavid Vernet int BPF_PROG(test_task_from_pid_arg, struct task_struct *task, u64 clone_flags)
248f471748bSDavid Vernet {
249f471748bSDavid Vernet if (!is_test_kfunc_task())
250f471748bSDavid Vernet return 0;
251f471748bSDavid Vernet
252f471748bSDavid Vernet lookup_compare_pid(task);
253f471748bSDavid Vernet return 0;
254f471748bSDavid Vernet }
255f471748bSDavid Vernet
256f471748bSDavid Vernet SEC("tp_btf/task_newtask")
BPF_PROG(test_task_from_pid_current,struct task_struct * task,u64 clone_flags)257f471748bSDavid Vernet int BPF_PROG(test_task_from_pid_current, struct task_struct *task, u64 clone_flags)
258f471748bSDavid Vernet {
259f471748bSDavid Vernet if (!is_test_kfunc_task())
260f471748bSDavid Vernet return 0;
261f471748bSDavid Vernet
262f471748bSDavid Vernet lookup_compare_pid(bpf_get_current_task_btf());
263f471748bSDavid Vernet return 0;
264f471748bSDavid Vernet }
265f471748bSDavid Vernet
is_pid_lookup_valid(s32 pid)266f471748bSDavid Vernet static int is_pid_lookup_valid(s32 pid)
267f471748bSDavid Vernet {
268f471748bSDavid Vernet struct task_struct *acquired;
269f471748bSDavid Vernet
270f471748bSDavid Vernet acquired = bpf_task_from_pid(pid);
271f471748bSDavid Vernet if (acquired) {
272f471748bSDavid Vernet bpf_task_release(acquired);
273f471748bSDavid Vernet return 1;
274f471748bSDavid Vernet }
275f471748bSDavid Vernet
276f471748bSDavid Vernet return 0;
277f471748bSDavid Vernet }
278f471748bSDavid Vernet
279f471748bSDavid Vernet SEC("tp_btf/task_newtask")
BPF_PROG(test_task_from_pid_invalid,struct task_struct * task,u64 clone_flags)280f471748bSDavid Vernet int BPF_PROG(test_task_from_pid_invalid, struct task_struct *task, u64 clone_flags)
281f471748bSDavid Vernet {
282f471748bSDavid Vernet if (!is_test_kfunc_task())
283f471748bSDavid Vernet return 0;
284f471748bSDavid Vernet
285f25fd608SAlexei Starovoitov bpf_strncmp(task->comm, 12, "foo");
286f25fd608SAlexei Starovoitov bpf_strncmp(task->comm, 16, "foo");
287f25fd608SAlexei Starovoitov bpf_strncmp(&task->comm[8], 4, "foo");
288f25fd608SAlexei Starovoitov
289f471748bSDavid Vernet if (is_pid_lookup_valid(-1)) {
290f471748bSDavid Vernet err = 1;
291f471748bSDavid Vernet return 0;
292f471748bSDavid Vernet }
293f471748bSDavid Vernet
294f471748bSDavid Vernet if (is_pid_lookup_valid(0xcafef00d)) {
295f471748bSDavid Vernet err = 2;
296f471748bSDavid Vernet return 0;
297f471748bSDavid Vernet }
298f471748bSDavid Vernet
299f471748bSDavid Vernet return 0;
300f471748bSDavid Vernet }
301d02c48faSDavid Vernet
302d02c48faSDavid Vernet SEC("tp_btf/task_newtask")
BPF_PROG(task_kfunc_acquire_trusted_walked,struct task_struct * task,u64 clone_flags)303d02c48faSDavid Vernet int BPF_PROG(task_kfunc_acquire_trusted_walked, struct task_struct *task, u64 clone_flags)
304d02c48faSDavid Vernet {
305d02c48faSDavid Vernet struct task_struct *acquired;
306d02c48faSDavid Vernet
307d02c48faSDavid Vernet /* task->group_leader is listed as a trusted, non-NULL field of task struct. */
308d02c48faSDavid Vernet acquired = bpf_task_acquire(task->group_leader);
309d02c48faSDavid Vernet if (acquired)
310d02c48faSDavid Vernet bpf_task_release(acquired);
311d02c48faSDavid Vernet else
312d02c48faSDavid Vernet err = 1;
313d02c48faSDavid Vernet
314d02c48faSDavid Vernet
315d02c48faSDavid Vernet return 0;
316d02c48faSDavid Vernet }
317