Linux Audio

Check our new training course

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