1*48671232SYonghong Song // SPDX-License-Identifier: GPL-2.0
2*48671232SYonghong Song /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3*48671232SYonghong Song 
4*48671232SYonghong Song #include "vmlinux.h"
5*48671232SYonghong Song #include <bpf/bpf_helpers.h>
6*48671232SYonghong Song #include <bpf/bpf_tracing.h>
7*48671232SYonghong Song #include "bpf_tracing_net.h"
8*48671232SYonghong Song #include "bpf_misc.h"
9*48671232SYonghong Song 
10*48671232SYonghong Song char _license[] SEC("license") = "GPL";
11*48671232SYonghong Song 
12*48671232SYonghong Song struct {
13*48671232SYonghong Song 	__uint(type, BPF_MAP_TYPE_TASK_STORAGE);
14*48671232SYonghong Song 	__uint(map_flags, BPF_F_NO_PREALLOC);
15*48671232SYonghong Song 	__type(key, int);
16*48671232SYonghong Song 	__type(value, long);
17*48671232SYonghong Song } map_a SEC(".maps");
18*48671232SYonghong Song 
19*48671232SYonghong Song __u32 user_data, key_serial, target_pid;
20*48671232SYonghong Song __u64 flags, task_storage_val, cgroup_id;
21*48671232SYonghong Song 
22*48671232SYonghong Song struct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym;
23*48671232SYonghong Song void bpf_key_put(struct bpf_key *key) __ksym;
24*48671232SYonghong Song void bpf_rcu_read_lock(void) __ksym;
25*48671232SYonghong Song void bpf_rcu_read_unlock(void) __ksym;
26*48671232SYonghong Song struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym;
27*48671232SYonghong Song void bpf_task_release(struct task_struct *p) __ksym;
28*48671232SYonghong Song 
29*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
30*48671232SYonghong Song int get_cgroup_id(void *ctx)
31*48671232SYonghong Song {
32*48671232SYonghong Song 	struct task_struct *task;
33*48671232SYonghong Song 
34*48671232SYonghong Song 	task = bpf_get_current_task_btf();
35*48671232SYonghong Song 	if (task->pid != target_pid)
36*48671232SYonghong Song 		return 0;
37*48671232SYonghong Song 
38*48671232SYonghong Song 	/* simulate bpf_get_current_cgroup_id() helper */
39*48671232SYonghong Song 	bpf_rcu_read_lock();
40*48671232SYonghong Song 	cgroup_id = task->cgroups->dfl_cgrp->kn->id;
41*48671232SYonghong Song 	bpf_rcu_read_unlock();
42*48671232SYonghong Song 	return 0;
43*48671232SYonghong Song }
44*48671232SYonghong Song 
45*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
46*48671232SYonghong Song int task_succ(void *ctx)
47*48671232SYonghong Song {
48*48671232SYonghong Song 	struct task_struct *task, *real_parent;
49*48671232SYonghong Song 	long init_val = 2;
50*48671232SYonghong Song 	long *ptr;
51*48671232SYonghong Song 
52*48671232SYonghong Song 	task = bpf_get_current_task_btf();
53*48671232SYonghong Song 	if (task->pid != target_pid)
54*48671232SYonghong Song 		return 0;
55*48671232SYonghong Song 
56*48671232SYonghong Song 	bpf_rcu_read_lock();
57*48671232SYonghong Song 	/* region including helper using rcu ptr real_parent */
58*48671232SYonghong Song 	real_parent = task->real_parent;
59*48671232SYonghong Song 	ptr = bpf_task_storage_get(&map_a, real_parent, &init_val,
60*48671232SYonghong Song 				   BPF_LOCAL_STORAGE_GET_F_CREATE);
61*48671232SYonghong Song 	if (!ptr)
62*48671232SYonghong Song 		goto out;
63*48671232SYonghong Song 	ptr = bpf_task_storage_get(&map_a, real_parent, 0, 0);
64*48671232SYonghong Song 	if (!ptr)
65*48671232SYonghong Song 		goto out;
66*48671232SYonghong Song 	task_storage_val = *ptr;
67*48671232SYonghong Song out:
68*48671232SYonghong Song 	bpf_rcu_read_unlock();
69*48671232SYonghong Song 	return 0;
70*48671232SYonghong Song }
71*48671232SYonghong Song 
72*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
73*48671232SYonghong Song int no_lock(void *ctx)
74*48671232SYonghong Song {
75*48671232SYonghong Song 	struct task_struct *task, *real_parent;
76*48671232SYonghong Song 
77*48671232SYonghong Song 	/* no bpf_rcu_read_lock(), old code still works */
78*48671232SYonghong Song 	task = bpf_get_current_task_btf();
79*48671232SYonghong Song 	real_parent = task->real_parent;
80*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
81*48671232SYonghong Song 	return 0;
82*48671232SYonghong Song }
83*48671232SYonghong Song 
84*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
85*48671232SYonghong Song int two_regions(void *ctx)
86*48671232SYonghong Song {
87*48671232SYonghong Song 	struct task_struct *task, *real_parent;
88*48671232SYonghong Song 
89*48671232SYonghong Song 	/* two regions */
90*48671232SYonghong Song 	task = bpf_get_current_task_btf();
91*48671232SYonghong Song 	bpf_rcu_read_lock();
92*48671232SYonghong Song 	bpf_rcu_read_unlock();
93*48671232SYonghong Song 	bpf_rcu_read_lock();
94*48671232SYonghong Song 	real_parent = task->real_parent;
95*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
96*48671232SYonghong Song 	bpf_rcu_read_unlock();
97*48671232SYonghong Song 	return 0;
98*48671232SYonghong Song }
99*48671232SYonghong Song 
100*48671232SYonghong Song SEC("?fentry/" SYS_PREFIX "sys_getpgid")
101*48671232SYonghong Song int non_sleepable_1(void *ctx)
102*48671232SYonghong Song {
103*48671232SYonghong Song 	struct task_struct *task, *real_parent;
104*48671232SYonghong Song 
105*48671232SYonghong Song 	task = bpf_get_current_task_btf();
106*48671232SYonghong Song 	bpf_rcu_read_lock();
107*48671232SYonghong Song 	real_parent = task->real_parent;
108*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
109*48671232SYonghong Song 	bpf_rcu_read_unlock();
110*48671232SYonghong Song 	return 0;
111*48671232SYonghong Song }
112*48671232SYonghong Song 
113*48671232SYonghong Song SEC("?fentry/" SYS_PREFIX "sys_getpgid")
114*48671232SYonghong Song int non_sleepable_2(void *ctx)
115*48671232SYonghong Song {
116*48671232SYonghong Song 	struct task_struct *task, *real_parent;
117*48671232SYonghong Song 
118*48671232SYonghong Song 	bpf_rcu_read_lock();
119*48671232SYonghong Song 	task = bpf_get_current_task_btf();
120*48671232SYonghong Song 	bpf_rcu_read_unlock();
121*48671232SYonghong Song 
122*48671232SYonghong Song 	bpf_rcu_read_lock();
123*48671232SYonghong Song 	real_parent = task->real_parent;
124*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
125*48671232SYonghong Song 	bpf_rcu_read_unlock();
126*48671232SYonghong Song 	return 0;
127*48671232SYonghong Song }
128*48671232SYonghong Song 
129*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
130*48671232SYonghong Song int task_acquire(void *ctx)
131*48671232SYonghong Song {
132*48671232SYonghong Song 	struct task_struct *task, *real_parent;
133*48671232SYonghong Song 
134*48671232SYonghong Song 	task = bpf_get_current_task_btf();
135*48671232SYonghong Song 	bpf_rcu_read_lock();
136*48671232SYonghong Song 	real_parent = task->real_parent;
137*48671232SYonghong Song 	/* acquire a reference which can be used outside rcu read lock region */
138*48671232SYonghong Song 	real_parent = bpf_task_acquire(real_parent);
139*48671232SYonghong Song 	bpf_rcu_read_unlock();
140*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
141*48671232SYonghong Song 	bpf_task_release(real_parent);
142*48671232SYonghong Song 	return 0;
143*48671232SYonghong Song }
144*48671232SYonghong Song 
145*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
146*48671232SYonghong Song int miss_lock(void *ctx)
147*48671232SYonghong Song {
148*48671232SYonghong Song 	struct task_struct *task;
149*48671232SYonghong Song 	struct css_set *cgroups;
150*48671232SYonghong Song 	struct cgroup *dfl_cgrp;
151*48671232SYonghong Song 
152*48671232SYonghong Song 	/* missing bpf_rcu_read_lock() */
153*48671232SYonghong Song 	task = bpf_get_current_task_btf();
154*48671232SYonghong Song 	bpf_rcu_read_lock();
155*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, task, 0, 0);
156*48671232SYonghong Song 	bpf_rcu_read_unlock();
157*48671232SYonghong Song 	bpf_rcu_read_unlock();
158*48671232SYonghong Song 	return 0;
159*48671232SYonghong Song }
160*48671232SYonghong Song 
161*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
162*48671232SYonghong Song int miss_unlock(void *ctx)
163*48671232SYonghong Song {
164*48671232SYonghong Song 	struct task_struct *task;
165*48671232SYonghong Song 	struct css_set *cgroups;
166*48671232SYonghong Song 	struct cgroup *dfl_cgrp;
167*48671232SYonghong Song 
168*48671232SYonghong Song 	/* missing bpf_rcu_read_unlock() */
169*48671232SYonghong Song 	task = bpf_get_current_task_btf();
170*48671232SYonghong Song 	bpf_rcu_read_lock();
171*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, task, 0, 0);
172*48671232SYonghong Song 	return 0;
173*48671232SYonghong Song }
174*48671232SYonghong Song 
175*48671232SYonghong Song SEC("?fentry/" SYS_PREFIX "sys_getpgid")
176*48671232SYonghong Song int non_sleepable_rcu_mismatch(void *ctx)
177*48671232SYonghong Song {
178*48671232SYonghong Song 	struct task_struct *task, *real_parent;
179*48671232SYonghong Song 
180*48671232SYonghong Song 	task = bpf_get_current_task_btf();
181*48671232SYonghong Song 	/* non-sleepable: missing bpf_rcu_read_unlock() in one path */
182*48671232SYonghong Song 	bpf_rcu_read_lock();
183*48671232SYonghong Song 	real_parent = task->real_parent;
184*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
185*48671232SYonghong Song 	if (real_parent)
186*48671232SYonghong Song 		bpf_rcu_read_unlock();
187*48671232SYonghong Song 	return 0;
188*48671232SYonghong Song }
189*48671232SYonghong Song 
190*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
191*48671232SYonghong Song int inproper_sleepable_helper(void *ctx)
192*48671232SYonghong Song {
193*48671232SYonghong Song 	struct task_struct *task, *real_parent;
194*48671232SYonghong Song 	struct pt_regs *regs;
195*48671232SYonghong Song 	__u32 value = 0;
196*48671232SYonghong Song 	void *ptr;
197*48671232SYonghong Song 
198*48671232SYonghong Song 	task = bpf_get_current_task_btf();
199*48671232SYonghong Song 	/* sleepable helper in rcu read lock region */
200*48671232SYonghong Song 	bpf_rcu_read_lock();
201*48671232SYonghong Song 	real_parent = task->real_parent;
202*48671232SYonghong Song 	regs = (struct pt_regs *)bpf_task_pt_regs(real_parent);
203*48671232SYonghong Song 	if (!regs) {
204*48671232SYonghong Song 		bpf_rcu_read_unlock();
205*48671232SYonghong Song 		return 0;
206*48671232SYonghong Song 	}
207*48671232SYonghong Song 
208*48671232SYonghong Song 	ptr = (void *)PT_REGS_IP(regs);
209*48671232SYonghong Song 	(void)bpf_copy_from_user_task(&value, sizeof(uint32_t), ptr, task, 0);
210*48671232SYonghong Song 	user_data = value;
211*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
212*48671232SYonghong Song 	bpf_rcu_read_unlock();
213*48671232SYonghong Song 	return 0;
214*48671232SYonghong Song }
215*48671232SYonghong Song 
216*48671232SYonghong Song SEC("?lsm.s/bpf")
217*48671232SYonghong Song int BPF_PROG(inproper_sleepable_kfunc, int cmd, union bpf_attr *attr, unsigned int size)
218*48671232SYonghong Song {
219*48671232SYonghong Song 	struct bpf_key *bkey;
220*48671232SYonghong Song 
221*48671232SYonghong Song 	/* sleepable kfunc in rcu read lock region */
222*48671232SYonghong Song 	bpf_rcu_read_lock();
223*48671232SYonghong Song 	bkey = bpf_lookup_user_key(key_serial, flags);
224*48671232SYonghong Song 	bpf_rcu_read_unlock();
225*48671232SYonghong Song 	if (!bkey)
226*48671232SYonghong Song 		return -1;
227*48671232SYonghong Song 	bpf_key_put(bkey);
228*48671232SYonghong Song 
229*48671232SYonghong Song 	return 0;
230*48671232SYonghong Song }
231*48671232SYonghong Song 
232*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
233*48671232SYonghong Song int nested_rcu_region(void *ctx)
234*48671232SYonghong Song {
235*48671232SYonghong Song 	struct task_struct *task, *real_parent;
236*48671232SYonghong Song 
237*48671232SYonghong Song 	/* nested rcu read lock regions */
238*48671232SYonghong Song 	task = bpf_get_current_task_btf();
239*48671232SYonghong Song 	bpf_rcu_read_lock();
240*48671232SYonghong Song 	bpf_rcu_read_lock();
241*48671232SYonghong Song 	real_parent = task->real_parent;
242*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
243*48671232SYonghong Song 	bpf_rcu_read_unlock();
244*48671232SYonghong Song 	bpf_rcu_read_unlock();
245*48671232SYonghong Song 	return 0;
246*48671232SYonghong Song }
247*48671232SYonghong Song 
248*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
249*48671232SYonghong Song int task_untrusted_non_rcuptr(void *ctx)
250*48671232SYonghong Song {
251*48671232SYonghong Song 	struct task_struct *task, *last_wakee;
252*48671232SYonghong Song 
253*48671232SYonghong Song 	task = bpf_get_current_task_btf();
254*48671232SYonghong Song 	bpf_rcu_read_lock();
255*48671232SYonghong Song 	/* the pointer last_wakee marked as untrusted */
256*48671232SYonghong Song 	last_wakee = task->real_parent->last_wakee;
257*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, last_wakee, 0, 0);
258*48671232SYonghong Song 	bpf_rcu_read_unlock();
259*48671232SYonghong Song 	return 0;
260*48671232SYonghong Song }
261*48671232SYonghong Song 
262*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
263*48671232SYonghong Song int task_untrusted_rcuptr(void *ctx)
264*48671232SYonghong Song {
265*48671232SYonghong Song 	struct task_struct *task, *real_parent;
266*48671232SYonghong Song 
267*48671232SYonghong Song 	task = bpf_get_current_task_btf();
268*48671232SYonghong Song 	bpf_rcu_read_lock();
269*48671232SYonghong Song 	real_parent = task->real_parent;
270*48671232SYonghong Song 	bpf_rcu_read_unlock();
271*48671232SYonghong Song 	/* helper use of rcu ptr outside the rcu read lock region */
272*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
273*48671232SYonghong Song 	return 0;
274*48671232SYonghong Song }
275*48671232SYonghong Song 
276*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep")
277*48671232SYonghong Song int cross_rcu_region(void *ctx)
278*48671232SYonghong Song {
279*48671232SYonghong Song 	struct task_struct *task, *real_parent;
280*48671232SYonghong Song 
281*48671232SYonghong Song 	/* rcu ptr define/use in different regions */
282*48671232SYonghong Song 	task = bpf_get_current_task_btf();
283*48671232SYonghong Song 	bpf_rcu_read_lock();
284*48671232SYonghong Song 	real_parent = task->real_parent;
285*48671232SYonghong Song 	bpf_rcu_read_unlock();
286*48671232SYonghong Song 	bpf_rcu_read_lock();
287*48671232SYonghong Song 	(void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
288*48671232SYonghong Song 	bpf_rcu_read_unlock();
289*48671232SYonghong Song 	return 0;
290*48671232SYonghong Song }
291