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