xref: /openbmc/linux/tools/testing/selftests/bpf/progs/task_kfunc_success.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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