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 "cgrp_kfunc_common.h"
9 
10 char _license[] SEC("license") = "GPL";
11 
12 int err, pid, invocations;
13 
14 /* Prototype for all of the program trace events below:
15  *
16  * TRACE_EVENT(cgroup_mkdir,
17  *         TP_PROTO(struct cgroup *cgrp, const char *path),
18  *         TP_ARGS(cgrp, path)
19  */
20 
21 static bool is_test_kfunc_task(void)
22 {
23 	int cur_pid = bpf_get_current_pid_tgid() >> 32;
24 	bool same = pid == cur_pid;
25 
26 	if (same)
27 		__sync_fetch_and_add(&invocations, 1);
28 
29 	return same;
30 }
31 
32 SEC("tp_btf/cgroup_mkdir")
33 int BPF_PROG(test_cgrp_acquire_release_argument, struct cgroup *cgrp, const char *path)
34 {
35 	struct cgroup *acquired;
36 
37 	if (!is_test_kfunc_task())
38 		return 0;
39 
40 	acquired = bpf_cgroup_acquire(cgrp);
41 	if (!acquired)
42 		err = 1;
43 	else
44 		bpf_cgroup_release(acquired);
45 
46 	return 0;
47 }
48 
49 SEC("tp_btf/cgroup_mkdir")
50 int BPF_PROG(test_cgrp_acquire_leave_in_map, struct cgroup *cgrp, const char *path)
51 {
52 	long status;
53 
54 	if (!is_test_kfunc_task())
55 		return 0;
56 
57 	status = cgrps_kfunc_map_insert(cgrp);
58 	if (status)
59 		err = 1;
60 
61 	return 0;
62 }
63 
64 SEC("tp_btf/cgroup_mkdir")
65 int BPF_PROG(test_cgrp_xchg_release, struct cgroup *cgrp, const char *path)
66 {
67 	struct cgroup *kptr, *cg;
68 	struct __cgrps_kfunc_map_value *v;
69 	long status;
70 
71 	if (!is_test_kfunc_task())
72 		return 0;
73 
74 	status = cgrps_kfunc_map_insert(cgrp);
75 	if (status) {
76 		err = 1;
77 		return 0;
78 	}
79 
80 	v = cgrps_kfunc_map_value_lookup(cgrp);
81 	if (!v) {
82 		err = 2;
83 		return 0;
84 	}
85 
86 	kptr = v->cgrp;
87 	if (!kptr) {
88 		err = 4;
89 		return 0;
90 	}
91 
92 	cg = bpf_cgroup_ancestor(kptr, 1);
93 	if (cg)	/* verifier only check */
94 		bpf_cgroup_release(cg);
95 
96 	kptr = bpf_kptr_xchg(&v->cgrp, NULL);
97 	if (!kptr) {
98 		err = 3;
99 		return 0;
100 	}
101 
102 	bpf_cgroup_release(kptr);
103 
104 	return 0;
105 }
106 
107 SEC("tp_btf/cgroup_mkdir")
108 int BPF_PROG(test_cgrp_get_release, struct cgroup *cgrp, const char *path)
109 {
110 	struct cgroup *kptr;
111 	struct __cgrps_kfunc_map_value *v;
112 	long status;
113 
114 	if (!is_test_kfunc_task())
115 		return 0;
116 
117 	status = cgrps_kfunc_map_insert(cgrp);
118 	if (status) {
119 		err = 1;
120 		return 0;
121 	}
122 
123 	v = cgrps_kfunc_map_value_lookup(cgrp);
124 	if (!v) {
125 		err = 2;
126 		return 0;
127 	}
128 
129 	bpf_rcu_read_lock();
130 	kptr = v->cgrp;
131 	if (!kptr)
132 		err = 3;
133 	bpf_rcu_read_unlock();
134 
135 	return 0;
136 }
137 
138 SEC("tp_btf/cgroup_mkdir")
139 int BPF_PROG(test_cgrp_get_ancestors, struct cgroup *cgrp, const char *path)
140 {
141 	struct cgroup *self, *ancestor1, *invalid;
142 
143 	if (!is_test_kfunc_task())
144 		return 0;
145 
146 	self = bpf_cgroup_ancestor(cgrp, cgrp->level);
147 	if (!self) {
148 		err = 1;
149 		return 0;
150 	}
151 
152 	if (self->self.id != cgrp->self.id) {
153 		bpf_cgroup_release(self);
154 		err = 2;
155 		return 0;
156 	}
157 	bpf_cgroup_release(self);
158 
159 	ancestor1 = bpf_cgroup_ancestor(cgrp, cgrp->level - 1);
160 	if (!ancestor1) {
161 		err = 3;
162 		return 0;
163 	}
164 	bpf_cgroup_release(ancestor1);
165 
166 	invalid = bpf_cgroup_ancestor(cgrp, 10000);
167 	if (invalid) {
168 		bpf_cgroup_release(invalid);
169 		err = 4;
170 		return 0;
171 	}
172 
173 	invalid = bpf_cgroup_ancestor(cgrp, -1);
174 	if (invalid) {
175 		bpf_cgroup_release(invalid);
176 		err = 5;
177 		return 0;
178 	}
179 
180 	return 0;
181 }
182 
183 SEC("tp_btf/cgroup_mkdir")
184 int BPF_PROG(test_cgrp_from_id, struct cgroup *cgrp, const char *path)
185 {
186 	struct cgroup *parent, *res;
187 	u64 parent_cgid;
188 
189 	if (!is_test_kfunc_task())
190 		return 0;
191 
192 	/* @cgrp's ID is not visible yet, let's test with the parent */
193 	parent = bpf_cgroup_ancestor(cgrp, cgrp->level - 1);
194 	if (!parent) {
195 		err = 1;
196 		return 0;
197 	}
198 
199 	parent_cgid = parent->kn->id;
200 	bpf_cgroup_release(parent);
201 
202 	res = bpf_cgroup_from_id(parent_cgid);
203 	if (!res) {
204 		err = 2;
205 		return 0;
206 	}
207 
208 	bpf_cgroup_release(res);
209 
210 	if (res != parent) {
211 		err = 3;
212 		return 0;
213 	}
214 
215 	res = bpf_cgroup_from_id((u64)-1);
216 	if (res) {
217 		bpf_cgroup_release(res);
218 		err = 4;
219 		return 0;
220 	}
221 
222 	return 0;
223 }
224