Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / tools / testing / selftests / bpf / test_sockopt_multi.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <error.h>
4 #include <errno.h>
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10
11 #include <linux/filter.h>
12 #include <bpf/bpf.h>
13 #include <bpf/libbpf.h>
14
15 #include "bpf_rlimit.h"
16 #include "bpf_util.h"
17 #include "cgroup_helpers.h"
18
19 static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title)
20 {
21         enum bpf_attach_type attach_type;
22         enum bpf_prog_type prog_type;
23         struct bpf_program *prog;
24         int err;
25
26         err = libbpf_prog_type_by_name(title, &prog_type, &attach_type);
27         if (err) {
28                 log_err("Failed to deduct types for %s BPF program", title);
29                 return -1;
30         }
31
32         prog = bpf_object__find_program_by_title(obj, title);
33         if (!prog) {
34                 log_err("Failed to find %s BPF program", title);
35                 return -1;
36         }
37
38         err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd,
39                               attach_type, BPF_F_ALLOW_MULTI);
40         if (err) {
41                 log_err("Failed to attach %s BPF program", title);
42                 return -1;
43         }
44
45         return 0;
46 }
47
48 static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title)
49 {
50         enum bpf_attach_type attach_type;
51         enum bpf_prog_type prog_type;
52         struct bpf_program *prog;
53         int err;
54
55         err = libbpf_prog_type_by_name(title, &prog_type, &attach_type);
56         if (err)
57                 return -1;
58
59         prog = bpf_object__find_program_by_title(obj, title);
60         if (!prog)
61                 return -1;
62
63         err = bpf_prog_detach2(bpf_program__fd(prog), cgroup_fd,
64                                attach_type);
65         if (err)
66                 return -1;
67
68         return 0;
69 }
70
71 static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
72                                int cg_child, int sock_fd)
73 {
74         socklen_t optlen;
75         __u8 buf;
76         int err;
77
78         /* Set IP_TOS to the expected value (0x80). */
79
80         buf = 0x80;
81         err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
82         if (err < 0) {
83                 log_err("Failed to call setsockopt(IP_TOS)");
84                 goto detach;
85         }
86
87         buf = 0x00;
88         optlen = 1;
89         err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
90         if (err) {
91                 log_err("Failed to call getsockopt(IP_TOS)");
92                 goto detach;
93         }
94
95         if (buf != 0x80) {
96                 log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf);
97                 err = -1;
98                 goto detach;
99         }
100
101         /* Attach child program and make sure it returns new value:
102          * - kernel:      -> 0x80
103          * - child:  0x80 -> 0x90
104          */
105
106         err = prog_attach(obj, cg_child, "cgroup/getsockopt/child");
107         if (err)
108                 goto detach;
109
110         buf = 0x00;
111         optlen = 1;
112         err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
113         if (err) {
114                 log_err("Failed to call getsockopt(IP_TOS)");
115                 goto detach;
116         }
117
118         if (buf != 0x90) {
119                 log_err("Unexpected getsockopt 0x%x != 0x90", buf);
120                 err = -1;
121                 goto detach;
122         }
123
124         /* Attach parent program and make sure it returns new value:
125          * - kernel:      -> 0x80
126          * - child:  0x80 -> 0x90
127          * - parent: 0x90 -> 0xA0
128          */
129
130         err = prog_attach(obj, cg_parent, "cgroup/getsockopt/parent");
131         if (err)
132                 goto detach;
133
134         buf = 0x00;
135         optlen = 1;
136         err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
137         if (err) {
138                 log_err("Failed to call getsockopt(IP_TOS)");
139                 goto detach;
140         }
141
142         if (buf != 0xA0) {
143                 log_err("Unexpected getsockopt 0x%x != 0xA0", buf);
144                 err = -1;
145                 goto detach;
146         }
147
148         /* Setting unexpected initial sockopt should return EPERM:
149          * - kernel: -> 0x40
150          * - child:  unexpected 0x40, EPERM
151          * - parent: unexpected 0x40, EPERM
152          */
153
154         buf = 0x40;
155         if (setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1) < 0) {
156                 log_err("Failed to call setsockopt(IP_TOS)");
157                 goto detach;
158         }
159
160         buf = 0x00;
161         optlen = 1;
162         err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
163         if (!err) {
164                 log_err("Unexpected success from getsockopt(IP_TOS)");
165                 goto detach;
166         }
167
168         /* Detach child program and make sure we still get EPERM:
169          * - kernel: -> 0x40
170          * - parent: unexpected 0x40, EPERM
171          */
172
173         err = prog_detach(obj, cg_child, "cgroup/getsockopt/child");
174         if (err) {
175                 log_err("Failed to detach child program");
176                 goto detach;
177         }
178
179         buf = 0x00;
180         optlen = 1;
181         err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
182         if (!err) {
183                 log_err("Unexpected success from getsockopt(IP_TOS)");
184                 goto detach;
185         }
186
187         /* Set initial value to the one the parent program expects:
188          * - kernel:      -> 0x90
189          * - parent: 0x90 -> 0xA0
190          */
191
192         buf = 0x90;
193         err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
194         if (err < 0) {
195                 log_err("Failed to call setsockopt(IP_TOS)");
196                 goto detach;
197         }
198
199         buf = 0x00;
200         optlen = 1;
201         err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
202         if (err) {
203                 log_err("Failed to call getsockopt(IP_TOS)");
204                 goto detach;
205         }
206
207         if (buf != 0xA0) {
208                 log_err("Unexpected getsockopt 0x%x != 0xA0", buf);
209                 err = -1;
210                 goto detach;
211         }
212
213 detach:
214         prog_detach(obj, cg_child, "cgroup/getsockopt/child");
215         prog_detach(obj, cg_parent, "cgroup/getsockopt/parent");
216
217         return err;
218 }
219
220 static int run_setsockopt_test(struct bpf_object *obj, int cg_parent,
221                                int cg_child, int sock_fd)
222 {
223         socklen_t optlen;
224         __u8 buf;
225         int err;
226
227         /* Set IP_TOS to the expected value (0x80). */
228
229         buf = 0x80;
230         err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
231         if (err < 0) {
232                 log_err("Failed to call setsockopt(IP_TOS)");
233                 goto detach;
234         }
235
236         buf = 0x00;
237         optlen = 1;
238         err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
239         if (err) {
240                 log_err("Failed to call getsockopt(IP_TOS)");
241                 goto detach;
242         }
243
244         if (buf != 0x80) {
245                 log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf);
246                 err = -1;
247                 goto detach;
248         }
249
250         /* Attach child program and make sure it adds 0x10. */
251
252         err = prog_attach(obj, cg_child, "cgroup/setsockopt");
253         if (err)
254                 goto detach;
255
256         buf = 0x80;
257         err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
258         if (err < 0) {
259                 log_err("Failed to call setsockopt(IP_TOS)");
260                 goto detach;
261         }
262
263         buf = 0x00;
264         optlen = 1;
265         err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
266         if (err) {
267                 log_err("Failed to call getsockopt(IP_TOS)");
268                 goto detach;
269         }
270
271         if (buf != 0x80 + 0x10) {
272                 log_err("Unexpected getsockopt 0x%x != 0x80 + 0x10", buf);
273                 err = -1;
274                 goto detach;
275         }
276
277         /* Attach parent program and make sure it adds another 0x10. */
278
279         err = prog_attach(obj, cg_parent, "cgroup/setsockopt");
280         if (err)
281                 goto detach;
282
283         buf = 0x80;
284         err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
285         if (err < 0) {
286                 log_err("Failed to call setsockopt(IP_TOS)");
287                 goto detach;
288         }
289
290         buf = 0x00;
291         optlen = 1;
292         err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
293         if (err) {
294                 log_err("Failed to call getsockopt(IP_TOS)");
295                 goto detach;
296         }
297
298         if (buf != 0x80 + 2 * 0x10) {
299                 log_err("Unexpected getsockopt 0x%x != 0x80 + 2 * 0x10", buf);
300                 err = -1;
301                 goto detach;
302         }
303
304 detach:
305         prog_detach(obj, cg_child, "cgroup/setsockopt");
306         prog_detach(obj, cg_parent, "cgroup/setsockopt");
307
308         return err;
309 }
310
311 int main(int argc, char **argv)
312 {
313         struct bpf_prog_load_attr attr = {
314                 .file = "./sockopt_multi.o",
315         };
316         int cg_parent = -1, cg_child = -1;
317         struct bpf_object *obj = NULL;
318         int sock_fd = -1;
319         int err = -1;
320         int ignored;
321
322         if (setup_cgroup_environment()) {
323                 log_err("Failed to setup cgroup environment\n");
324                 goto out;
325         }
326
327         cg_parent = create_and_get_cgroup("/parent");
328         if (cg_parent < 0) {
329                 log_err("Failed to create cgroup /parent\n");
330                 goto out;
331         }
332
333         cg_child = create_and_get_cgroup("/parent/child");
334         if (cg_child < 0) {
335                 log_err("Failed to create cgroup /parent/child\n");
336                 goto out;
337         }
338
339         if (join_cgroup("/parent/child")) {
340                 log_err("Failed to join cgroup /parent/child\n");
341                 goto out;
342         }
343
344         err = bpf_prog_load_xattr(&attr, &obj, &ignored);
345         if (err) {
346                 log_err("Failed to load BPF object");
347                 goto out;
348         }
349
350         sock_fd = socket(AF_INET, SOCK_STREAM, 0);
351         if (sock_fd < 0) {
352                 log_err("Failed to create socket");
353                 goto out;
354         }
355
356         if (run_getsockopt_test(obj, cg_parent, cg_child, sock_fd))
357                 err = -1;
358         printf("test_sockopt_multi: getsockopt %s\n",
359                err ? "FAILED" : "PASSED");
360
361         if (run_setsockopt_test(obj, cg_parent, cg_child, sock_fd))
362                 err = -1;
363         printf("test_sockopt_multi: setsockopt %s\n",
364                err ? "FAILED" : "PASSED");
365
366 out:
367         close(sock_fd);
368         bpf_object__close(obj);
369         close(cg_child);
370         close(cg_parent);
371
372         printf("test_sockopt_multi: %s\n", err ? "FAILED" : "PASSED");
373         return err ? EXIT_FAILURE : EXIT_SUCCESS;
374 }