]>
Commit | Line | Data |
---|---|---|
65b4414a | 1 | // SPDX-License-Identifier: GPL-2.0 |
3886bd7c | 2 | #include <test_progs.h> |
65b4414a SF |
3 | #include "cgroup_helpers.h" |
4 | ||
15669e1d | 5 | static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title, const char *name) |
65b4414a SF |
6 | { |
7 | enum bpf_attach_type attach_type; | |
8 | enum bpf_prog_type prog_type; | |
9 | struct bpf_program *prog; | |
10 | int err; | |
11 | ||
12 | err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); | |
13 | if (err) { | |
14 | log_err("Failed to deduct types for %s BPF program", title); | |
15 | return -1; | |
16 | } | |
17 | ||
15669e1d | 18 | prog = bpf_object__find_program_by_name(obj, name); |
65b4414a | 19 | if (!prog) { |
15669e1d | 20 | log_err("Failed to find %s BPF program", name); |
65b4414a SF |
21 | return -1; |
22 | } | |
23 | ||
24 | err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, | |
25 | attach_type, BPF_F_ALLOW_MULTI); | |
26 | if (err) { | |
15669e1d | 27 | log_err("Failed to attach %s BPF program", name); |
65b4414a SF |
28 | return -1; |
29 | } | |
30 | ||
31 | return 0; | |
32 | } | |
33 | ||
15669e1d | 34 | static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title, const char *name) |
65b4414a SF |
35 | { |
36 | enum bpf_attach_type attach_type; | |
37 | enum bpf_prog_type prog_type; | |
38 | struct bpf_program *prog; | |
39 | int err; | |
40 | ||
41 | err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); | |
42 | if (err) | |
43 | return -1; | |
44 | ||
15669e1d | 45 | prog = bpf_object__find_program_by_name(obj, name); |
65b4414a SF |
46 | if (!prog) |
47 | return -1; | |
48 | ||
49 | err = bpf_prog_detach2(bpf_program__fd(prog), cgroup_fd, | |
50 | attach_type); | |
51 | if (err) | |
52 | return -1; | |
53 | ||
54 | return 0; | |
55 | } | |
56 | ||
57 | static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, | |
58 | int cg_child, int sock_fd) | |
59 | { | |
60 | socklen_t optlen; | |
61 | __u8 buf; | |
62 | int err; | |
63 | ||
64 | /* Set IP_TOS to the expected value (0x80). */ | |
65 | ||
66 | buf = 0x80; | |
67 | err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); | |
68 | if (err < 0) { | |
69 | log_err("Failed to call setsockopt(IP_TOS)"); | |
70 | goto detach; | |
71 | } | |
72 | ||
73 | buf = 0x00; | |
74 | optlen = 1; | |
75 | err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); | |
76 | if (err) { | |
77 | log_err("Failed to call getsockopt(IP_TOS)"); | |
78 | goto detach; | |
79 | } | |
80 | ||
81 | if (buf != 0x80) { | |
82 | log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf); | |
83 | err = -1; | |
84 | goto detach; | |
85 | } | |
86 | ||
87 | /* Attach child program and make sure it returns new value: | |
88 | * - kernel: -> 0x80 | |
89 | * - child: 0x80 -> 0x90 | |
90 | */ | |
91 | ||
15669e1d | 92 | err = prog_attach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); |
65b4414a SF |
93 | if (err) |
94 | goto detach; | |
95 | ||
96 | buf = 0x00; | |
97 | optlen = 1; | |
98 | err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); | |
99 | if (err) { | |
100 | log_err("Failed to call getsockopt(IP_TOS)"); | |
101 | goto detach; | |
102 | } | |
103 | ||
104 | if (buf != 0x90) { | |
105 | log_err("Unexpected getsockopt 0x%x != 0x90", buf); | |
106 | err = -1; | |
107 | goto detach; | |
108 | } | |
109 | ||
110 | /* Attach parent program and make sure it returns new value: | |
111 | * - kernel: -> 0x80 | |
112 | * - child: 0x80 -> 0x90 | |
113 | * - parent: 0x90 -> 0xA0 | |
114 | */ | |
115 | ||
15669e1d | 116 | err = prog_attach(obj, cg_parent, "cgroup/getsockopt", "_getsockopt_parent"); |
65b4414a SF |
117 | if (err) |
118 | goto detach; | |
119 | ||
120 | buf = 0x00; | |
121 | optlen = 1; | |
122 | err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); | |
123 | if (err) { | |
124 | log_err("Failed to call getsockopt(IP_TOS)"); | |
125 | goto detach; | |
126 | } | |
127 | ||
128 | if (buf != 0xA0) { | |
129 | log_err("Unexpected getsockopt 0x%x != 0xA0", buf); | |
130 | err = -1; | |
131 | goto detach; | |
132 | } | |
133 | ||
134 | /* Setting unexpected initial sockopt should return EPERM: | |
135 | * - kernel: -> 0x40 | |
136 | * - child: unexpected 0x40, EPERM | |
137 | * - parent: unexpected 0x40, EPERM | |
138 | */ | |
139 | ||
140 | buf = 0x40; | |
2acc3c1b WH |
141 | err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); |
142 | if (err < 0) { | |
65b4414a SF |
143 | log_err("Failed to call setsockopt(IP_TOS)"); |
144 | goto detach; | |
145 | } | |
146 | ||
147 | buf = 0x00; | |
148 | optlen = 1; | |
149 | err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); | |
150 | if (!err) { | |
151 | log_err("Unexpected success from getsockopt(IP_TOS)"); | |
152 | goto detach; | |
153 | } | |
154 | ||
155 | /* Detach child program and make sure we still get EPERM: | |
156 | * - kernel: -> 0x40 | |
157 | * - parent: unexpected 0x40, EPERM | |
158 | */ | |
159 | ||
15669e1d | 160 | err = prog_detach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); |
65b4414a SF |
161 | if (err) { |
162 | log_err("Failed to detach child program"); | |
163 | goto detach; | |
164 | } | |
165 | ||
166 | buf = 0x00; | |
167 | optlen = 1; | |
168 | err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); | |
169 | if (!err) { | |
170 | log_err("Unexpected success from getsockopt(IP_TOS)"); | |
171 | goto detach; | |
172 | } | |
173 | ||
174 | /* Set initial value to the one the parent program expects: | |
175 | * - kernel: -> 0x90 | |
176 | * - parent: 0x90 -> 0xA0 | |
177 | */ | |
178 | ||
179 | buf = 0x90; | |
180 | err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); | |
181 | if (err < 0) { | |
182 | log_err("Failed to call setsockopt(IP_TOS)"); | |
183 | goto detach; | |
184 | } | |
185 | ||
186 | buf = 0x00; | |
187 | optlen = 1; | |
188 | err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); | |
189 | if (err) { | |
190 | log_err("Failed to call getsockopt(IP_TOS)"); | |
191 | goto detach; | |
192 | } | |
193 | ||
194 | if (buf != 0xA0) { | |
195 | log_err("Unexpected getsockopt 0x%x != 0xA0", buf); | |
196 | err = -1; | |
197 | goto detach; | |
198 | } | |
199 | ||
200 | detach: | |
15669e1d AN |
201 | prog_detach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); |
202 | prog_detach(obj, cg_parent, "cgroup/getsockopt", "_getsockopt_parent"); | |
65b4414a SF |
203 | |
204 | return err; | |
205 | } | |
206 | ||
207 | static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, | |
208 | int cg_child, int sock_fd) | |
209 | { | |
210 | socklen_t optlen; | |
211 | __u8 buf; | |
212 | int err; | |
213 | ||
214 | /* Set IP_TOS to the expected value (0x80). */ | |
215 | ||
216 | buf = 0x80; | |
217 | err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); | |
218 | if (err < 0) { | |
219 | log_err("Failed to call setsockopt(IP_TOS)"); | |
220 | goto detach; | |
221 | } | |
222 | ||
223 | buf = 0x00; | |
224 | optlen = 1; | |
225 | err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); | |
226 | if (err) { | |
227 | log_err("Failed to call getsockopt(IP_TOS)"); | |
228 | goto detach; | |
229 | } | |
230 | ||
231 | if (buf != 0x80) { | |
232 | log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf); | |
233 | err = -1; | |
234 | goto detach; | |
235 | } | |
236 | ||
237 | /* Attach child program and make sure it adds 0x10. */ | |
238 | ||
15669e1d | 239 | err = prog_attach(obj, cg_child, "cgroup/setsockopt", "_setsockopt"); |
65b4414a SF |
240 | if (err) |
241 | goto detach; | |
242 | ||
243 | buf = 0x80; | |
244 | err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); | |
245 | if (err < 0) { | |
246 | log_err("Failed to call setsockopt(IP_TOS)"); | |
247 | goto detach; | |
248 | } | |
249 | ||
250 | buf = 0x00; | |
251 | optlen = 1; | |
252 | err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); | |
253 | if (err) { | |
254 | log_err("Failed to call getsockopt(IP_TOS)"); | |
255 | goto detach; | |
256 | } | |
257 | ||
258 | if (buf != 0x80 + 0x10) { | |
259 | log_err("Unexpected getsockopt 0x%x != 0x80 + 0x10", buf); | |
260 | err = -1; | |
261 | goto detach; | |
262 | } | |
263 | ||
264 | /* Attach parent program and make sure it adds another 0x10. */ | |
265 | ||
15669e1d | 266 | err = prog_attach(obj, cg_parent, "cgroup/setsockopt", "_setsockopt"); |
65b4414a SF |
267 | if (err) |
268 | goto detach; | |
269 | ||
270 | buf = 0x80; | |
271 | err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); | |
272 | if (err < 0) { | |
273 | log_err("Failed to call setsockopt(IP_TOS)"); | |
274 | goto detach; | |
275 | } | |
276 | ||
277 | buf = 0x00; | |
278 | optlen = 1; | |
279 | err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); | |
280 | if (err) { | |
281 | log_err("Failed to call getsockopt(IP_TOS)"); | |
282 | goto detach; | |
283 | } | |
284 | ||
285 | if (buf != 0x80 + 2 * 0x10) { | |
286 | log_err("Unexpected getsockopt 0x%x != 0x80 + 2 * 0x10", buf); | |
287 | err = -1; | |
288 | goto detach; | |
289 | } | |
290 | ||
291 | detach: | |
15669e1d AN |
292 | prog_detach(obj, cg_child, "cgroup/setsockopt", "_setsockopt"); |
293 | prog_detach(obj, cg_parent, "cgroup/setsockopt", "_setsockopt"); | |
65b4414a SF |
294 | |
295 | return err; | |
296 | } | |
297 | ||
3886bd7c | 298 | void test_sockopt_multi(void) |
65b4414a | 299 | { |
65b4414a SF |
300 | int cg_parent = -1, cg_child = -1; |
301 | struct bpf_object *obj = NULL; | |
302 | int sock_fd = -1; | |
303 | int err = -1; | |
65b4414a | 304 | |
3886bd7c SF |
305 | cg_parent = test__join_cgroup("/parent"); |
306 | if (CHECK_FAIL(cg_parent < 0)) | |
65b4414a | 307 | goto out; |
65b4414a | 308 | |
3886bd7c SF |
309 | cg_child = test__join_cgroup("/parent/child"); |
310 | if (CHECK_FAIL(cg_child < 0)) | |
65b4414a | 311 | goto out; |
65b4414a | 312 | |
afef88e6 | 313 | obj = bpf_object__open_file("sockopt_multi.bpf.o", NULL); |
186d1a86 AN |
314 | if (!ASSERT_OK_PTR(obj, "obj_load")) |
315 | goto out; | |
316 | ||
317 | err = bpf_object__load(obj); | |
318 | if (!ASSERT_OK(err, "obj_load")) | |
65b4414a | 319 | goto out; |
65b4414a SF |
320 | |
321 | sock_fd = socket(AF_INET, SOCK_STREAM, 0); | |
3886bd7c | 322 | if (CHECK_FAIL(sock_fd < 0)) |
65b4414a | 323 | goto out; |
65b4414a | 324 | |
3886bd7c SF |
325 | CHECK_FAIL(run_getsockopt_test(obj, cg_parent, cg_child, sock_fd)); |
326 | CHECK_FAIL(run_setsockopt_test(obj, cg_parent, cg_child, sock_fd)); | |
65b4414a SF |
327 | |
328 | out: | |
329 | close(sock_fd); | |
330 | bpf_object__close(obj); | |
331 | close(cg_child); | |
332 | close(cg_parent); | |
65b4414a | 333 | } |