1268896Sbapt// SPDX-License-Identifier: GPL-2.0
2268896Sbapt/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3268896Sbapt
4268896Sbapt#include "vmlinux.h"
5268896Sbapt#include <bpf/bpf_helpers.h>
6268896Sbapt#include <bpf/bpf_tracing.h>
7268896Sbapt#include "bpf_tracing_net.h"
8268896Sbapt#include "bpf_misc.h"
9268896Sbapt
10268896Sbaptchar _license[] SEC("license") = "GPL";
11268896Sbapt
12268896Sbaptstruct {
13268896Sbapt	__uint(type, BPF_MAP_TYPE_TASK_STORAGE);
14268896Sbapt	__uint(map_flags, BPF_F_NO_PREALLOC);
15268896Sbapt	__type(key, int);
16268896Sbapt	__type(value, long);
17268896Sbapt} map_a SEC(".maps");
18268896Sbapt
19268896Sbapt__u32 user_data, key_serial, target_pid;
20268896Sbapt__u64 flags, task_storage_val, cgroup_id;
21268896Sbapt
22268896Sbaptstruct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym;
23268896Sbaptvoid bpf_key_put(struct bpf_key *key) __ksym;
24268896Sbaptvoid bpf_rcu_read_lock(void) __ksym;
25268896Sbaptvoid bpf_rcu_read_unlock(void) __ksym;
26268896Sbaptstruct task_struct *bpf_task_acquire(struct task_struct *p) __ksym;
27268896Sbaptvoid bpf_task_release(struct task_struct *p) __ksym;
28268896Sbapt
29268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
30268896Sbaptint get_cgroup_id(void *ctx)
31268896Sbapt{
32268896Sbapt	struct task_struct *task;
33268896Sbapt	struct css_set *cgroups;
34268896Sbapt
35268896Sbapt	task = bpf_get_current_task_btf();
36268896Sbapt	if (task->pid != target_pid)
37268896Sbapt		return 0;
38268896Sbapt
39268896Sbapt	/* simulate bpf_get_current_cgroup_id() helper */
40268896Sbapt	bpf_rcu_read_lock();
41268896Sbapt	cgroups = task->cgroups;
42268896Sbapt	if (!cgroups)
43268896Sbapt		goto unlock;
44268896Sbapt	cgroup_id = cgroups->dfl_cgrp->kn->id;
45268896Sbaptunlock:
46268896Sbapt	bpf_rcu_read_unlock();
47268896Sbapt	return 0;
48268896Sbapt}
49268896Sbapt
50268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
51268896Sbaptint task_succ(void *ctx)
52268896Sbapt{
53268896Sbapt	struct task_struct *task, *real_parent;
54268896Sbapt	long init_val = 2;
55268896Sbapt	long *ptr;
56268896Sbapt
57268896Sbapt	task = bpf_get_current_task_btf();
58268896Sbapt	if (task->pid != target_pid)
59268896Sbapt		return 0;
60268896Sbapt
61268896Sbapt	bpf_rcu_read_lock();
62268896Sbapt	/* region including helper using rcu ptr real_parent */
63268896Sbapt	real_parent = task->real_parent;
64268896Sbapt	if (!real_parent)
65268896Sbapt		goto out;
66268896Sbapt	ptr = bpf_task_storage_get(&map_a, real_parent, &init_val,
67268896Sbapt				   BPF_LOCAL_STORAGE_GET_F_CREATE);
68268896Sbapt	if (!ptr)
69268896Sbapt		goto out;
70268896Sbapt	ptr = bpf_task_storage_get(&map_a, real_parent, 0, 0);
71268896Sbapt	if (!ptr)
72268896Sbapt		goto out;
73268896Sbapt	task_storage_val = *ptr;
74268896Sbaptout:
75268896Sbapt	bpf_rcu_read_unlock();
76268896Sbapt	return 0;
77268896Sbapt}
78268896Sbapt
79268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
80268896Sbaptint no_lock(void *ctx)
81268896Sbapt{
82268896Sbapt	struct task_struct *task, *real_parent;
83268896Sbapt
84268896Sbapt	/* old style ptr_to_btf_id is not allowed in sleepable */
85268896Sbapt	task = bpf_get_current_task_btf();
86268896Sbapt	real_parent = task->real_parent;
87268896Sbapt	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
88268896Sbapt	return 0;
89268896Sbapt}
90268896Sbapt
91268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
92268896Sbaptint two_regions(void *ctx)
93268896Sbapt{
94268896Sbapt	struct task_struct *task, *real_parent;
95268896Sbapt
96268896Sbapt	/* two regions */
97268896Sbapt	task = bpf_get_current_task_btf();
98268896Sbapt	bpf_rcu_read_lock();
99268896Sbapt	bpf_rcu_read_unlock();
100268896Sbapt	bpf_rcu_read_lock();
101268896Sbapt	real_parent = task->real_parent;
102268896Sbapt	if (!real_parent)
103268896Sbapt		goto out;
104268896Sbapt	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
105268896Sbaptout:
106268896Sbapt	bpf_rcu_read_unlock();
107268896Sbapt	return 0;
108268896Sbapt}
109268896Sbapt
110268896SbaptSEC("?fentry/" SYS_PREFIX "sys_getpgid")
111268896Sbaptint non_sleepable_1(void *ctx)
112268896Sbapt{
113268896Sbapt	struct task_struct *task, *real_parent;
114268896Sbapt
115268896Sbapt	task = bpf_get_current_task_btf();
116268896Sbapt	bpf_rcu_read_lock();
117268896Sbapt	real_parent = task->real_parent;
118268896Sbapt	if (!real_parent)
119268896Sbapt		goto out;
120268896Sbapt	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
121268896Sbaptout:
122268896Sbapt	bpf_rcu_read_unlock();
123268896Sbapt	return 0;
124268896Sbapt}
125268896Sbapt
126268896SbaptSEC("?fentry/" SYS_PREFIX "sys_getpgid")
127268896Sbaptint non_sleepable_2(void *ctx)
128268896Sbapt{
129268896Sbapt	struct task_struct *task, *real_parent;
130268896Sbapt
131268896Sbapt	bpf_rcu_read_lock();
132268896Sbapt	task = bpf_get_current_task_btf();
133268896Sbapt	bpf_rcu_read_unlock();
134268896Sbapt
135268896Sbapt	bpf_rcu_read_lock();
136268896Sbapt	real_parent = task->real_parent;
137268896Sbapt	if (!real_parent)
138268896Sbapt		goto out;
139268896Sbapt	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
140268896Sbaptout:
141268896Sbapt	bpf_rcu_read_unlock();
142268896Sbapt	return 0;
143268896Sbapt}
144268896Sbapt
145268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
146268896Sbaptint task_acquire(void *ctx)
147268896Sbapt{
148268896Sbapt	struct task_struct *task, *real_parent, *gparent;
149268896Sbapt
150268896Sbapt	task = bpf_get_current_task_btf();
151268896Sbapt	bpf_rcu_read_lock();
152268896Sbapt	real_parent = task->real_parent;
153268896Sbapt	if (!real_parent)
154268896Sbapt		goto out;
155268896Sbapt
156268896Sbapt	/* rcu_ptr->rcu_field */
157268896Sbapt	gparent = real_parent->real_parent;
158268896Sbapt	if (!gparent)
159268896Sbapt		goto out;
160268896Sbapt
161268896Sbapt	/* acquire a reference which can be used outside rcu read lock region */
162268896Sbapt	gparent = bpf_task_acquire(gparent);
163268896Sbapt	if (!gparent)
164268896Sbapt		goto out;
165268896Sbapt
166268896Sbapt	(void)bpf_task_storage_get(&map_a, gparent, 0, 0);
167268896Sbapt	bpf_task_release(gparent);
168268896Sbaptout:
169268896Sbapt	bpf_rcu_read_unlock();
170268896Sbapt	return 0;
171268896Sbapt}
172268896Sbapt
173268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
174268896Sbaptint miss_lock(void *ctx)
175268896Sbapt{
176268896Sbapt	struct task_struct *task;
177268896Sbapt
178268896Sbapt	/* missing bpf_rcu_read_lock() */
179268896Sbapt	task = bpf_get_current_task_btf();
180268896Sbapt	bpf_rcu_read_lock();
181268896Sbapt	(void)bpf_task_storage_get(&map_a, task, 0, 0);
182268896Sbapt	bpf_rcu_read_unlock();
183268896Sbapt	bpf_rcu_read_unlock();
184268896Sbapt	return 0;
185268896Sbapt}
186268896Sbapt
187268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
188268896Sbaptint miss_unlock(void *ctx)
189268896Sbapt{
190268896Sbapt	struct task_struct *task;
191268896Sbapt
192268896Sbapt	/* missing bpf_rcu_read_unlock() */
193268896Sbapt	task = bpf_get_current_task_btf();
194268896Sbapt	bpf_rcu_read_lock();
195268896Sbapt	(void)bpf_task_storage_get(&map_a, task, 0, 0);
196268896Sbapt	return 0;
197268896Sbapt}
198268896Sbapt
199268896SbaptSEC("?fentry/" SYS_PREFIX "sys_getpgid")
200268896Sbaptint non_sleepable_rcu_mismatch(void *ctx)
201268896Sbapt{
202268896Sbapt	struct task_struct *task, *real_parent;
203268896Sbapt
204268896Sbapt	task = bpf_get_current_task_btf();
205268896Sbapt	/* non-sleepable: missing bpf_rcu_read_unlock() in one path */
206268896Sbapt	bpf_rcu_read_lock();
207268896Sbapt	real_parent = task->real_parent;
208268896Sbapt	if (!real_parent)
209268896Sbapt		goto out;
210268896Sbapt	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
211268896Sbapt	if (real_parent)
212268896Sbapt		bpf_rcu_read_unlock();
213268896Sbaptout:
214268896Sbapt	return 0;
215268896Sbapt}
216268896Sbapt
217268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
218268896Sbaptint inproper_sleepable_helper(void *ctx)
219268896Sbapt{
220268896Sbapt	struct task_struct *task, *real_parent;
221268896Sbapt	struct pt_regs *regs;
222268896Sbapt	__u32 value = 0;
223268896Sbapt	void *ptr;
224268896Sbapt
225268896Sbapt	task = bpf_get_current_task_btf();
226268896Sbapt	/* sleepable helper in rcu read lock region */
227268896Sbapt	bpf_rcu_read_lock();
228268896Sbapt	real_parent = task->real_parent;
229268896Sbapt	if (!real_parent)
230268896Sbapt		goto out;
231268896Sbapt	regs = (struct pt_regs *)bpf_task_pt_regs(real_parent);
232268896Sbapt	if (!regs)
233268896Sbapt		goto out;
234268896Sbapt
235268896Sbapt	ptr = (void *)PT_REGS_IP(regs);
236268896Sbapt	(void)bpf_copy_from_user_task(&value, sizeof(uint32_t), ptr, task, 0);
237268896Sbapt	user_data = value;
238268896Sbapt	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
239268896Sbaptout:
240268896Sbapt	bpf_rcu_read_unlock();
241268896Sbapt	return 0;
242268896Sbapt}
243268896Sbapt
244268896SbaptSEC("?lsm.s/bpf")
245268896Sbaptint BPF_PROG(inproper_sleepable_kfunc, int cmd, union bpf_attr *attr, unsigned int size)
246268896Sbapt{
247268896Sbapt	struct bpf_key *bkey;
248268896Sbapt
249268896Sbapt	/* sleepable kfunc in rcu read lock region */
250268896Sbapt	bpf_rcu_read_lock();
251268896Sbapt	bkey = bpf_lookup_user_key(key_serial, flags);
252268896Sbapt	bpf_rcu_read_unlock();
253268896Sbapt	if (!bkey)
254268896Sbapt		return -1;
255268896Sbapt	bpf_key_put(bkey);
256268896Sbapt
257268896Sbapt	return 0;
258268896Sbapt}
259268896Sbapt
260268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
261268896Sbaptint nested_rcu_region(void *ctx)
262268896Sbapt{
263268896Sbapt	struct task_struct *task, *real_parent;
264268896Sbapt
265268896Sbapt	/* nested rcu read lock regions */
266268896Sbapt	task = bpf_get_current_task_btf();
267268896Sbapt	bpf_rcu_read_lock();
268268896Sbapt	bpf_rcu_read_lock();
269268896Sbapt	real_parent = task->real_parent;
270268896Sbapt	if (!real_parent)
271268896Sbapt		goto out;
272268896Sbapt	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
273268896Sbaptout:
274268896Sbapt	bpf_rcu_read_unlock();
275268896Sbapt	bpf_rcu_read_unlock();
276268896Sbapt	return 0;
277268896Sbapt}
278268896Sbapt
279268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
280268896Sbaptint task_trusted_non_rcuptr(void *ctx)
281268896Sbapt{
282268896Sbapt	struct task_struct *task, *group_leader;
283268896Sbapt
284268896Sbapt	task = bpf_get_current_task_btf();
285268896Sbapt	bpf_rcu_read_lock();
286268896Sbapt	/* the pointer group_leader is explicitly marked as trusted */
287268896Sbapt	group_leader = task->real_parent->group_leader;
288268896Sbapt	(void)bpf_task_storage_get(&map_a, group_leader, 0, 0);
289268896Sbapt	bpf_rcu_read_unlock();
290268896Sbapt	return 0;
291268896Sbapt}
292268896Sbapt
293268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
294268896Sbaptint task_untrusted_rcuptr(void *ctx)
295268896Sbapt{
296268896Sbapt	struct task_struct *task, *real_parent;
297268896Sbapt
298268896Sbapt	task = bpf_get_current_task_btf();
299268896Sbapt	bpf_rcu_read_lock();
300268896Sbapt	real_parent = task->real_parent;
301268896Sbapt	bpf_rcu_read_unlock();
302268896Sbapt	/* helper use of rcu ptr outside the rcu read lock region */
303268896Sbapt	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
304268896Sbapt	return 0;
305268896Sbapt}
306268896Sbapt
307268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
308268896Sbaptint cross_rcu_region(void *ctx)
309268896Sbapt{
310268896Sbapt	struct task_struct *task, *real_parent;
311268896Sbapt
312268896Sbapt	/* rcu ptr define/use in different regions */
313268896Sbapt	task = bpf_get_current_task_btf();
314268896Sbapt	bpf_rcu_read_lock();
315268896Sbapt	real_parent = task->real_parent;
316268896Sbapt	bpf_rcu_read_unlock();
317268896Sbapt	bpf_rcu_read_lock();
318268896Sbapt	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
319268896Sbapt	bpf_rcu_read_unlock();
320268896Sbapt	return 0;
321268896Sbapt}
322268896Sbapt
323268896Sbapt__noinline
324268896Sbaptstatic int static_subprog(void *ctx)
325268896Sbapt{
326268896Sbapt	volatile int ret = 0;
327268896Sbapt
328268896Sbapt	if (bpf_get_prandom_u32())
329268896Sbapt		return ret + 42;
330268896Sbapt	return ret + bpf_get_prandom_u32();
331268896Sbapt}
332268896Sbapt
333268896Sbapt__noinline
334268896Sbaptint global_subprog(u64 a)
335268896Sbapt{
336268896Sbapt	volatile int ret = a;
337268896Sbapt
338268896Sbapt	return ret + static_subprog(NULL);
339268896Sbapt}
340268896Sbapt
341268896Sbapt__noinline
342268896Sbaptstatic int static_subprog_lock(void *ctx)
343268896Sbapt{
344268896Sbapt	volatile int ret = 0;
345268896Sbapt
346268896Sbapt	bpf_rcu_read_lock();
347268896Sbapt	if (bpf_get_prandom_u32())
348268896Sbapt		return ret + 42;
349268896Sbapt	return ret + bpf_get_prandom_u32();
350268896Sbapt}
351268896Sbapt
352268896Sbapt__noinline
353268896Sbaptint global_subprog_lock(u64 a)
354268896Sbapt{
355268896Sbapt	volatile int ret = a;
356268896Sbapt
357268896Sbapt	return ret + static_subprog_lock(NULL);
358268896Sbapt}
359268896Sbapt
360268896Sbapt__noinline
361268896Sbaptstatic int static_subprog_unlock(void *ctx)
362268896Sbapt{
363268896Sbapt	volatile int ret = 0;
364268896Sbapt
365268896Sbapt	bpf_rcu_read_unlock();
366268896Sbapt	if (bpf_get_prandom_u32())
367268896Sbapt		return ret + 42;
368268896Sbapt	return ret + bpf_get_prandom_u32();
369268896Sbapt}
370268896Sbapt
371268896Sbapt__noinline
372268896Sbaptint global_subprog_unlock(u64 a)
373268896Sbapt{
374268896Sbapt	volatile int ret = a;
375268896Sbapt
376268896Sbapt	return ret + static_subprog_unlock(NULL);
377268896Sbapt}
378268896Sbapt
379268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
380268896Sbaptint rcu_read_lock_subprog(void *ctx)
381268896Sbapt{
382268896Sbapt	volatile int ret = 0;
383268896Sbapt
384268896Sbapt	bpf_rcu_read_lock();
385268896Sbapt	if (bpf_get_prandom_u32())
386268896Sbapt		ret += static_subprog(ctx);
387268896Sbapt	bpf_rcu_read_unlock();
388268896Sbapt	return 0;
389268896Sbapt}
390268896Sbapt
391268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
392268896Sbaptint rcu_read_lock_global_subprog(void *ctx)
393268896Sbapt{
394268896Sbapt	volatile int ret = 0;
395268896Sbapt
396268896Sbapt	bpf_rcu_read_lock();
397268896Sbapt	if (bpf_get_prandom_u32())
398268896Sbapt		ret += global_subprog(ret);
399268896Sbapt	bpf_rcu_read_unlock();
400268896Sbapt	return 0;
401268896Sbapt}
402268896Sbapt
403268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
404268896Sbaptint rcu_read_lock_subprog_lock(void *ctx)
405268896Sbapt{
406268896Sbapt	volatile int ret = 0;
407268896Sbapt
408268896Sbapt	ret += static_subprog_lock(ctx);
409268896Sbapt	bpf_rcu_read_unlock();
410268896Sbapt	return 0;
411268896Sbapt}
412268896Sbapt
413268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
414268896Sbaptint rcu_read_lock_global_subprog_lock(void *ctx)
415268896Sbapt{
416268896Sbapt	volatile int ret = 0;
417268896Sbapt
418268896Sbapt	ret += global_subprog_lock(ret);
419268896Sbapt	bpf_rcu_read_unlock();
420268896Sbapt	return 0;
421268896Sbapt}
422268896Sbapt
423268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
424268896Sbaptint rcu_read_lock_subprog_unlock(void *ctx)
425268896Sbapt{
426268896Sbapt	volatile int ret = 0;
427268896Sbapt
428268896Sbapt	bpf_rcu_read_lock();
429268896Sbapt	ret += static_subprog_unlock(ctx);
430268896Sbapt	return 0;
431268896Sbapt}
432268896Sbapt
433268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
434268896Sbaptint rcu_read_lock_global_subprog_unlock(void *ctx)
435268896Sbapt{
436268896Sbapt	volatile int ret = 0;
437268896Sbapt
438268896Sbapt	bpf_rcu_read_lock();
439268896Sbapt	ret += global_subprog_unlock(ret);
440268896Sbapt	return 0;
441268896Sbapt}
442268896Sbapt