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