1f583ddf1SDavid Vernet // SPDX-License-Identifier: GPL-2.0
2f583ddf1SDavid Vernet /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3f583ddf1SDavid Vernet 
4f583ddf1SDavid Vernet #include <vmlinux.h>
5f583ddf1SDavid Vernet #include <bpf/bpf_tracing.h>
6f583ddf1SDavid Vernet #include <bpf/bpf_helpers.h>
7f583ddf1SDavid Vernet 
88032cad1SJoanne Koong #include "bpf_misc.h"
9f583ddf1SDavid Vernet #include "cgrp_kfunc_common.h"
10f583ddf1SDavid Vernet 
11f583ddf1SDavid Vernet char _license[] SEC("license") = "GPL";
12f583ddf1SDavid Vernet 
13f583ddf1SDavid Vernet /* Prototype for all of the program trace events below:
14f583ddf1SDavid Vernet  *
15f583ddf1SDavid Vernet  * TRACE_EVENT(cgroup_mkdir,
16f583ddf1SDavid Vernet  *         TP_PROTO(struct cgroup *cgrp, const char *path),
17f583ddf1SDavid Vernet  *         TP_ARGS(cgrp, path)
18f583ddf1SDavid Vernet  */
19f583ddf1SDavid Vernet 
insert_lookup_cgrp(struct cgroup * cgrp)20f583ddf1SDavid Vernet static struct __cgrps_kfunc_map_value *insert_lookup_cgrp(struct cgroup *cgrp)
21f583ddf1SDavid Vernet {
22f583ddf1SDavid Vernet 	int status;
23f583ddf1SDavid Vernet 
24f583ddf1SDavid Vernet 	status = cgrps_kfunc_map_insert(cgrp);
25f583ddf1SDavid Vernet 	if (status)
26f583ddf1SDavid Vernet 		return NULL;
27f583ddf1SDavid Vernet 
28f583ddf1SDavid Vernet 	return cgrps_kfunc_map_value_lookup(cgrp);
29f583ddf1SDavid Vernet }
30f583ddf1SDavid Vernet 
31f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
328032cad1SJoanne Koong __failure __msg("Possibly NULL pointer passed to trusted arg0")
BPF_PROG(cgrp_kfunc_acquire_untrusted,struct cgroup * cgrp,const char * path)33f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_acquire_untrusted, struct cgroup *cgrp, const char *path)
34f583ddf1SDavid Vernet {
35f583ddf1SDavid Vernet 	struct cgroup *acquired;
36f583ddf1SDavid Vernet 	struct __cgrps_kfunc_map_value *v;
37f583ddf1SDavid Vernet 
38f583ddf1SDavid Vernet 	v = insert_lookup_cgrp(cgrp);
39f583ddf1SDavid Vernet 	if (!v)
40f583ddf1SDavid Vernet 		return 0;
41f583ddf1SDavid Vernet 
42f583ddf1SDavid Vernet 	/* Can't invoke bpf_cgroup_acquire() on an untrusted pointer. */
43f583ddf1SDavid Vernet 	acquired = bpf_cgroup_acquire(v->cgrp);
441d712839SDavid Vernet 	if (acquired)
451d712839SDavid Vernet 		bpf_cgroup_release(acquired);
461d712839SDavid Vernet 
471d712839SDavid Vernet 	return 0;
481d712839SDavid Vernet }
491d712839SDavid Vernet 
501d712839SDavid Vernet SEC("tp_btf/cgroup_mkdir")
511d712839SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0")
BPF_PROG(cgrp_kfunc_acquire_no_null_check,struct cgroup * cgrp,const char * path)521d712839SDavid Vernet int BPF_PROG(cgrp_kfunc_acquire_no_null_check, struct cgroup *cgrp, const char *path)
531d712839SDavid Vernet {
541d712839SDavid Vernet 	struct cgroup *acquired;
551d712839SDavid Vernet 
561d712839SDavid Vernet 	acquired = bpf_cgroup_acquire(cgrp);
571d712839SDavid Vernet 	/*
581d712839SDavid Vernet 	 * Can't invoke bpf_cgroup_release() without checking the return value
591d712839SDavid Vernet 	 * of bpf_cgroup_acquire().
601d712839SDavid Vernet 	 */
61f583ddf1SDavid Vernet 	bpf_cgroup_release(acquired);
62f583ddf1SDavid Vernet 
63f583ddf1SDavid Vernet 	return 0;
64f583ddf1SDavid Vernet }
65f583ddf1SDavid Vernet 
66f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
678032cad1SJoanne Koong __failure __msg("arg#0 pointer type STRUCT cgroup must point")
BPF_PROG(cgrp_kfunc_acquire_fp,struct cgroup * cgrp,const char * path)68f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path)
69f583ddf1SDavid Vernet {
70f583ddf1SDavid Vernet 	struct cgroup *acquired, *stack_cgrp = (struct cgroup *)&path;
71f583ddf1SDavid Vernet 
72f583ddf1SDavid Vernet 	/* Can't invoke bpf_cgroup_acquire() on a random frame pointer. */
73f583ddf1SDavid Vernet 	acquired = bpf_cgroup_acquire((struct cgroup *)&stack_cgrp);
741d712839SDavid Vernet 	if (acquired)
75f583ddf1SDavid Vernet 		bpf_cgroup_release(acquired);
76f583ddf1SDavid Vernet 
77f583ddf1SDavid Vernet 	return 0;
78f583ddf1SDavid Vernet }
79f583ddf1SDavid Vernet 
80f583ddf1SDavid Vernet SEC("kretprobe/cgroup_destroy_locked")
818032cad1SJoanne Koong __failure __msg("reg type unsupported for arg#0 function")
BPF_PROG(cgrp_kfunc_acquire_unsafe_kretprobe,struct cgroup * cgrp)82f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_acquire_unsafe_kretprobe, struct cgroup *cgrp)
83f583ddf1SDavid Vernet {
84f583ddf1SDavid Vernet 	struct cgroup *acquired;
85f583ddf1SDavid Vernet 
86f583ddf1SDavid Vernet 	/* Can't acquire an untrusted struct cgroup * pointer. */
87f583ddf1SDavid Vernet 	acquired = bpf_cgroup_acquire(cgrp);
881d712839SDavid Vernet 	if (acquired)
89f583ddf1SDavid Vernet 		bpf_cgroup_release(acquired);
90f583ddf1SDavid Vernet 
91f583ddf1SDavid Vernet 	return 0;
92f583ddf1SDavid Vernet }
93f583ddf1SDavid Vernet 
94f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
958032cad1SJoanne Koong __failure __msg("cgrp_kfunc_acquire_trusted_walked")
BPF_PROG(cgrp_kfunc_acquire_trusted_walked,struct cgroup * cgrp,const char * path)96f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_acquire_trusted_walked, struct cgroup *cgrp, const char *path)
97f583ddf1SDavid Vernet {
98f583ddf1SDavid Vernet 	struct cgroup *acquired;
99f583ddf1SDavid Vernet 
100f583ddf1SDavid Vernet 	/* Can't invoke bpf_cgroup_acquire() on a pointer obtained from walking a trusted cgroup. */
101f583ddf1SDavid Vernet 	acquired = bpf_cgroup_acquire(cgrp->old_dom_cgrp);
1021d712839SDavid Vernet 	if (acquired)
103f583ddf1SDavid Vernet 		bpf_cgroup_release(acquired);
104f583ddf1SDavid Vernet 
105f583ddf1SDavid Vernet 	return 0;
106f583ddf1SDavid Vernet }
107f583ddf1SDavid Vernet 
108f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
1098032cad1SJoanne Koong __failure __msg("Possibly NULL pointer passed to trusted arg0")
BPF_PROG(cgrp_kfunc_acquire_null,struct cgroup * cgrp,const char * path)110f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_acquire_null, struct cgroup *cgrp, const char *path)
111f583ddf1SDavid Vernet {
112f583ddf1SDavid Vernet 	struct cgroup *acquired;
113f583ddf1SDavid Vernet 
114f583ddf1SDavid Vernet 	/* Can't invoke bpf_cgroup_acquire() on a NULL pointer. */
115f583ddf1SDavid Vernet 	acquired = bpf_cgroup_acquire(NULL);
1161d712839SDavid Vernet 	if (acquired)
117f583ddf1SDavid Vernet 		bpf_cgroup_release(acquired);
118f583ddf1SDavid Vernet 
119f583ddf1SDavid Vernet 	return 0;
120f583ddf1SDavid Vernet }
121f583ddf1SDavid Vernet 
122f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
1238032cad1SJoanne Koong __failure __msg("Unreleased reference")
BPF_PROG(cgrp_kfunc_acquire_unreleased,struct cgroup * cgrp,const char * path)124f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_acquire_unreleased, struct cgroup *cgrp, const char *path)
125f583ddf1SDavid Vernet {
126f583ddf1SDavid Vernet 	struct cgroup *acquired;
127f583ddf1SDavid Vernet 
128f583ddf1SDavid Vernet 	acquired = bpf_cgroup_acquire(cgrp);
129f583ddf1SDavid Vernet 
130f583ddf1SDavid Vernet 	/* Acquired cgroup is never released. */
131c8ed6685SAndrii Nakryiko 	__sink(acquired);
132f583ddf1SDavid Vernet 
133f583ddf1SDavid Vernet 	return 0;
134f583ddf1SDavid Vernet }
135f583ddf1SDavid Vernet 
136f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
1378032cad1SJoanne Koong __failure __msg("Unreleased reference")
BPF_PROG(cgrp_kfunc_xchg_unreleased,struct cgroup * cgrp,const char * path)138f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_xchg_unreleased, struct cgroup *cgrp, const char *path)
139f583ddf1SDavid Vernet {
140f583ddf1SDavid Vernet 	struct cgroup *kptr;
141f583ddf1SDavid Vernet 	struct __cgrps_kfunc_map_value *v;
142f583ddf1SDavid Vernet 
143f583ddf1SDavid Vernet 	v = insert_lookup_cgrp(cgrp);
144f583ddf1SDavid Vernet 	if (!v)
145f583ddf1SDavid Vernet 		return 0;
146f583ddf1SDavid Vernet 
147f583ddf1SDavid Vernet 	kptr = bpf_kptr_xchg(&v->cgrp, NULL);
148f583ddf1SDavid Vernet 	if (!kptr)
149f583ddf1SDavid Vernet 		return 0;
150f583ddf1SDavid Vernet 
151f583ddf1SDavid Vernet 	/* Kptr retrieved from map is never released. */
152f583ddf1SDavid Vernet 
153f583ddf1SDavid Vernet 	return 0;
154f583ddf1SDavid Vernet }
155f583ddf1SDavid Vernet 
156f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
157*6499fe6eSDavid Vernet __failure __msg("must be referenced or trusted")
BPF_PROG(cgrp_kfunc_rcu_get_release,struct cgroup * cgrp,const char * path)158*6499fe6eSDavid Vernet int BPF_PROG(cgrp_kfunc_rcu_get_release, struct cgroup *cgrp, const char *path)
159f583ddf1SDavid Vernet {
160f583ddf1SDavid Vernet 	struct cgroup *kptr;
161f583ddf1SDavid Vernet 	struct __cgrps_kfunc_map_value *v;
162f583ddf1SDavid Vernet 
163f583ddf1SDavid Vernet 	v = insert_lookup_cgrp(cgrp);
164f583ddf1SDavid Vernet 	if (!v)
165f583ddf1SDavid Vernet 		return 0;
166f583ddf1SDavid Vernet 
167*6499fe6eSDavid Vernet 	bpf_rcu_read_lock();
168*6499fe6eSDavid Vernet 	kptr = v->cgrp;
169*6499fe6eSDavid Vernet 	if (kptr)
170*6499fe6eSDavid Vernet 		/* Can't release a cgroup kptr stored in a map. */
171*6499fe6eSDavid Vernet 		bpf_cgroup_release(kptr);
172*6499fe6eSDavid Vernet 	bpf_rcu_read_unlock();
173f583ddf1SDavid Vernet 
174f583ddf1SDavid Vernet 	return 0;
175f583ddf1SDavid Vernet }
176f583ddf1SDavid Vernet 
177f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
1786c831c46SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0")
BPF_PROG(cgrp_kfunc_release_untrusted,struct cgroup * cgrp,const char * path)179f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_release_untrusted, struct cgroup *cgrp, const char *path)
180f583ddf1SDavid Vernet {
181f583ddf1SDavid Vernet 	struct __cgrps_kfunc_map_value *v;
182f583ddf1SDavid Vernet 
183f583ddf1SDavid Vernet 	v = insert_lookup_cgrp(cgrp);
184f583ddf1SDavid Vernet 	if (!v)
185f583ddf1SDavid Vernet 		return 0;
186f583ddf1SDavid Vernet 
187f583ddf1SDavid Vernet 	/* Can't invoke bpf_cgroup_release() on an untrusted pointer. */
188f583ddf1SDavid Vernet 	bpf_cgroup_release(v->cgrp);
189f583ddf1SDavid Vernet 
190f583ddf1SDavid Vernet 	return 0;
191f583ddf1SDavid Vernet }
192f583ddf1SDavid Vernet 
193f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
1948032cad1SJoanne Koong __failure __msg("arg#0 pointer type STRUCT cgroup must point")
BPF_PROG(cgrp_kfunc_release_fp,struct cgroup * cgrp,const char * path)195f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_release_fp, struct cgroup *cgrp, const char *path)
196f583ddf1SDavid Vernet {
197f583ddf1SDavid Vernet 	struct cgroup *acquired = (struct cgroup *)&path;
198f583ddf1SDavid Vernet 
199f583ddf1SDavid Vernet 	/* Cannot release random frame pointer. */
200f583ddf1SDavid Vernet 	bpf_cgroup_release(acquired);
201f583ddf1SDavid Vernet 
202f583ddf1SDavid Vernet 	return 0;
203f583ddf1SDavid Vernet }
204f583ddf1SDavid Vernet 
205f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
2066c831c46SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0")
BPF_PROG(cgrp_kfunc_release_null,struct cgroup * cgrp,const char * path)207f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_release_null, struct cgroup *cgrp, const char *path)
208f583ddf1SDavid Vernet {
209f583ddf1SDavid Vernet 	struct __cgrps_kfunc_map_value local, *v;
210f583ddf1SDavid Vernet 	long status;
211f583ddf1SDavid Vernet 	struct cgroup *acquired, *old;
212f583ddf1SDavid Vernet 	s32 id;
213f583ddf1SDavid Vernet 
214f583ddf1SDavid Vernet 	status = bpf_probe_read_kernel(&id, sizeof(id), &cgrp->self.id);
215f583ddf1SDavid Vernet 	if (status)
216f583ddf1SDavid Vernet 		return 0;
217f583ddf1SDavid Vernet 
218f583ddf1SDavid Vernet 	local.cgrp = NULL;
219f583ddf1SDavid Vernet 	status = bpf_map_update_elem(&__cgrps_kfunc_map, &id, &local, BPF_NOEXIST);
220f583ddf1SDavid Vernet 	if (status)
221f583ddf1SDavid Vernet 		return status;
222f583ddf1SDavid Vernet 
223f583ddf1SDavid Vernet 	v = bpf_map_lookup_elem(&__cgrps_kfunc_map, &id);
224f583ddf1SDavid Vernet 	if (!v)
225f583ddf1SDavid Vernet 		return -ENOENT;
226f583ddf1SDavid Vernet 
227f583ddf1SDavid Vernet 	acquired = bpf_cgroup_acquire(cgrp);
2281d712839SDavid Vernet 	if (!acquired)
2291d712839SDavid Vernet 		return -ENOENT;
230f583ddf1SDavid Vernet 
231f583ddf1SDavid Vernet 	old = bpf_kptr_xchg(&v->cgrp, acquired);
232f583ddf1SDavid Vernet 
233f583ddf1SDavid Vernet 	/* old cannot be passed to bpf_cgroup_release() without a NULL check. */
234f583ddf1SDavid Vernet 	bpf_cgroup_release(old);
235f583ddf1SDavid Vernet 
236f583ddf1SDavid Vernet 	return 0;
237f583ddf1SDavid Vernet }
238f583ddf1SDavid Vernet 
239f583ddf1SDavid Vernet SEC("tp_btf/cgroup_mkdir")
2408032cad1SJoanne Koong __failure __msg("release kernel function bpf_cgroup_release expects")
BPF_PROG(cgrp_kfunc_release_unacquired,struct cgroup * cgrp,const char * path)241f583ddf1SDavid Vernet int BPF_PROG(cgrp_kfunc_release_unacquired, struct cgroup *cgrp, const char *path)
242f583ddf1SDavid Vernet {
243f583ddf1SDavid Vernet 	/* Cannot release trusted cgroup pointer which was not acquired. */
244f583ddf1SDavid Vernet 	bpf_cgroup_release(cgrp);
245f583ddf1SDavid Vernet 
246f583ddf1SDavid Vernet 	return 0;
247f583ddf1SDavid Vernet }
248