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_tracing.h> |
6 | #include <bpf/bpf_helpers.h> |
7 | |
8 | #include "bpf_misc.h" |
9 | #include "cgrp_kfunc_common.h" |
10 | |
11 | char _license[] SEC("license" ) = "GPL" ; |
12 | |
13 | /* Prototype for all of the program trace events below: |
14 | * |
15 | * TRACE_EVENT(cgroup_mkdir, |
16 | * TP_PROTO(struct cgroup *cgrp, const char *path), |
17 | * TP_ARGS(cgrp, path) |
18 | */ |
19 | |
20 | static struct __cgrps_kfunc_map_value *insert_lookup_cgrp(struct cgroup *cgrp) |
21 | { |
22 | int status; |
23 | |
24 | status = cgrps_kfunc_map_insert(cgrp); |
25 | if (status) |
26 | return NULL; |
27 | |
28 | return cgrps_kfunc_map_value_lookup(cgrp); |
29 | } |
30 | |
31 | SEC("tp_btf/cgroup_mkdir" ) |
32 | __failure __msg("Possibly NULL pointer passed to trusted arg0" ) |
33 | int BPF_PROG(cgrp_kfunc_acquire_untrusted, struct cgroup *cgrp, const char *path) |
34 | { |
35 | struct cgroup *acquired; |
36 | struct __cgrps_kfunc_map_value *v; |
37 | |
38 | v = insert_lookup_cgrp(cgrp: cgrp); |
39 | if (!v) |
40 | return 0; |
41 | |
42 | /* Can't invoke bpf_cgroup_acquire() on an untrusted pointer. */ |
43 | acquired = bpf_cgroup_acquire(v->cgrp); |
44 | if (acquired) |
45 | bpf_cgroup_release(acquired); |
46 | |
47 | return 0; |
48 | } |
49 | |
50 | SEC("tp_btf/cgroup_mkdir" ) |
51 | __failure __msg("Possibly NULL pointer passed to trusted arg0" ) |
52 | int BPF_PROG(cgrp_kfunc_acquire_no_null_check, struct cgroup *cgrp, const char *path) |
53 | { |
54 | struct cgroup *acquired; |
55 | |
56 | acquired = bpf_cgroup_acquire(cgrp); |
57 | /* |
58 | * Can't invoke bpf_cgroup_release() without checking the return value |
59 | * of bpf_cgroup_acquire(). |
60 | */ |
61 | bpf_cgroup_release(acquired); |
62 | |
63 | return 0; |
64 | } |
65 | |
66 | SEC("tp_btf/cgroup_mkdir" ) |
67 | __failure __msg("arg#0 pointer type STRUCT cgroup must point" ) |
68 | int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path) |
69 | { |
70 | struct cgroup *acquired, *stack_cgrp = (struct cgroup *)&path; |
71 | |
72 | /* Can't invoke bpf_cgroup_acquire() on a random frame pointer. */ |
73 | acquired = bpf_cgroup_acquire((struct cgroup *)&stack_cgrp); |
74 | if (acquired) |
75 | bpf_cgroup_release(acquired); |
76 | |
77 | return 0; |
78 | } |
79 | |
80 | SEC("kretprobe/cgroup_destroy_locked" ) |
81 | __failure __msg("calling kernel function bpf_cgroup_acquire is not allowed" ) |
82 | int BPF_PROG(cgrp_kfunc_acquire_unsafe_kretprobe, struct cgroup *cgrp) |
83 | { |
84 | struct cgroup *acquired; |
85 | |
86 | /* Can't acquire an untrusted struct cgroup * pointer. */ |
87 | acquired = bpf_cgroup_acquire(cgrp); |
88 | if (acquired) |
89 | bpf_cgroup_release(acquired); |
90 | |
91 | return 0; |
92 | } |
93 | |
94 | SEC("tp_btf/cgroup_mkdir" ) |
95 | __failure __msg("cgrp_kfunc_acquire_trusted_walked" ) |
96 | int BPF_PROG(cgrp_kfunc_acquire_trusted_walked, struct cgroup *cgrp, const char *path) |
97 | { |
98 | struct cgroup *acquired; |
99 | |
100 | /* Can't invoke bpf_cgroup_acquire() on a pointer obtained from walking a trusted cgroup. */ |
101 | acquired = bpf_cgroup_acquire(cgrp->old_dom_cgrp); |
102 | if (acquired) |
103 | bpf_cgroup_release(acquired); |
104 | |
105 | return 0; |
106 | } |
107 | |
108 | SEC("tp_btf/cgroup_mkdir" ) |
109 | __failure __msg("Possibly NULL pointer passed to trusted arg0" ) |
110 | int BPF_PROG(cgrp_kfunc_acquire_null, struct cgroup *cgrp, const char *path) |
111 | { |
112 | struct cgroup *acquired; |
113 | |
114 | /* Can't invoke bpf_cgroup_acquire() on a NULL pointer. */ |
115 | acquired = bpf_cgroup_acquire(NULL); |
116 | if (acquired) |
117 | bpf_cgroup_release(acquired); |
118 | |
119 | return 0; |
120 | } |
121 | |
122 | SEC("tp_btf/cgroup_mkdir" ) |
123 | __failure __msg("Unreleased reference" ) |
124 | int BPF_PROG(cgrp_kfunc_acquire_unreleased, struct cgroup *cgrp, const char *path) |
125 | { |
126 | struct cgroup *acquired; |
127 | |
128 | acquired = bpf_cgroup_acquire(cgrp); |
129 | |
130 | /* Acquired cgroup is never released. */ |
131 | __sink(acquired); |
132 | |
133 | return 0; |
134 | } |
135 | |
136 | SEC("tp_btf/cgroup_mkdir" ) |
137 | __failure __msg("Unreleased reference" ) |
138 | int BPF_PROG(cgrp_kfunc_xchg_unreleased, struct cgroup *cgrp, const char *path) |
139 | { |
140 | struct cgroup *kptr; |
141 | struct __cgrps_kfunc_map_value *v; |
142 | |
143 | v = insert_lookup_cgrp(cgrp: cgrp); |
144 | if (!v) |
145 | return 0; |
146 | |
147 | kptr = bpf_kptr_xchg(&v->cgrp, NULL); |
148 | if (!kptr) |
149 | return 0; |
150 | |
151 | /* Kptr retrieved from map is never released. */ |
152 | |
153 | return 0; |
154 | } |
155 | |
156 | SEC("tp_btf/cgroup_mkdir" ) |
157 | __failure __msg("must be referenced or trusted" ) |
158 | int BPF_PROG(cgrp_kfunc_rcu_get_release, struct cgroup *cgrp, const char *path) |
159 | { |
160 | struct cgroup *kptr; |
161 | struct __cgrps_kfunc_map_value *v; |
162 | |
163 | v = insert_lookup_cgrp(cgrp: cgrp); |
164 | if (!v) |
165 | return 0; |
166 | |
167 | bpf_rcu_read_lock(); |
168 | kptr = v->cgrp; |
169 | if (kptr) |
170 | /* Can't release a cgroup kptr stored in a map. */ |
171 | bpf_cgroup_release(kptr); |
172 | bpf_rcu_read_unlock(); |
173 | |
174 | return 0; |
175 | } |
176 | |
177 | SEC("tp_btf/cgroup_mkdir" ) |
178 | __failure __msg("Possibly NULL pointer passed to trusted arg0" ) |
179 | int BPF_PROG(cgrp_kfunc_release_untrusted, struct cgroup *cgrp, const char *path) |
180 | { |
181 | struct __cgrps_kfunc_map_value *v; |
182 | |
183 | v = insert_lookup_cgrp(cgrp: cgrp); |
184 | if (!v) |
185 | return 0; |
186 | |
187 | /* Can't invoke bpf_cgroup_release() on an untrusted pointer. */ |
188 | bpf_cgroup_release(v->cgrp); |
189 | |
190 | return 0; |
191 | } |
192 | |
193 | SEC("tp_btf/cgroup_mkdir" ) |
194 | __failure __msg("arg#0 pointer type STRUCT cgroup must point" ) |
195 | int BPF_PROG(cgrp_kfunc_release_fp, struct cgroup *cgrp, const char *path) |
196 | { |
197 | struct cgroup *acquired = (struct cgroup *)&path; |
198 | |
199 | /* Cannot release random frame pointer. */ |
200 | bpf_cgroup_release(acquired); |
201 | |
202 | return 0; |
203 | } |
204 | |
205 | SEC("tp_btf/cgroup_mkdir" ) |
206 | __failure __msg("Possibly NULL pointer passed to trusted arg0" ) |
207 | int BPF_PROG(cgrp_kfunc_release_null, struct cgroup *cgrp, const char *path) |
208 | { |
209 | struct __cgrps_kfunc_map_value local, *v; |
210 | long status; |
211 | struct cgroup *acquired, *old; |
212 | s32 id; |
213 | |
214 | status = bpf_probe_read_kernel(&id, sizeof(id), &cgrp->self.id); |
215 | if (status) |
216 | return 0; |
217 | |
218 | local.cgrp = NULL; |
219 | status = bpf_map_update_elem(&__cgrps_kfunc_map, &id, &local, BPF_NOEXIST); |
220 | if (status) |
221 | return status; |
222 | |
223 | v = bpf_map_lookup_elem(&__cgrps_kfunc_map, &id); |
224 | if (!v) |
225 | return -ENOENT; |
226 | |
227 | acquired = bpf_cgroup_acquire(cgrp); |
228 | if (!acquired) |
229 | return -ENOENT; |
230 | |
231 | old = bpf_kptr_xchg(&v->cgrp, acquired); |
232 | |
233 | /* old cannot be passed to bpf_cgroup_release() without a NULL check. */ |
234 | bpf_cgroup_release(old); |
235 | |
236 | return 0; |
237 | } |
238 | |
239 | SEC("tp_btf/cgroup_mkdir" ) |
240 | __failure __msg("release kernel function bpf_cgroup_release expects" ) |
241 | int BPF_PROG(cgrp_kfunc_release_unacquired, struct cgroup *cgrp, const char *path) |
242 | { |
243 | /* Cannot release trusted cgroup pointer which was not acquired. */ |
244 | bpf_cgroup_release(cgrp); |
245 | |
246 | return 0; |
247 | } |
248 | |