Merge tag 'xfs-5.13-fixes-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux-2.6-microblaze.git] / tools / testing / selftests / bpf / prog_tests / sockopt_multi.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include "cgroup_helpers.h"
4
5 static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title)
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_title(obj, title);
19         if (!prog) {
20                 log_err("Failed to find %s BPF program", title);
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", title);
28                 return -1;
29         }
30
31         return 0;
32 }
33
34 static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title)
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_title(obj, title);
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
92         err = prog_attach(obj, cg_child, "cgroup/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/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/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
200 detach:
201         prog_detach(obj, cg_child, "cgroup/getsockopt/child");
202         prog_detach(obj, cg_parent, "cgroup/getsockopt/parent");
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
239         err = prog_attach(obj, cg_child, "cgroup/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");
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:
292         prog_detach(obj, cg_child, "cgroup/setsockopt");
293         prog_detach(obj, cg_parent, "cgroup/setsockopt");
294
295         return err;
296 }
297
298 void test_sockopt_multi(void)
299 {
300         struct bpf_prog_load_attr attr = {
301                 .file = "./sockopt_multi.o",
302         };
303         int cg_parent = -1, cg_child = -1;
304         struct bpf_object *obj = NULL;
305         int sock_fd = -1;
306         int err = -1;
307         int ignored;
308
309         cg_parent = test__join_cgroup("/parent");
310         if (CHECK_FAIL(cg_parent < 0))
311                 goto out;
312
313         cg_child = test__join_cgroup("/parent/child");
314         if (CHECK_FAIL(cg_child < 0))
315                 goto out;
316
317         err = bpf_prog_load_xattr(&attr, &obj, &ignored);
318         if (CHECK_FAIL(err))
319                 goto out;
320
321         sock_fd = socket(AF_INET, SOCK_STREAM, 0);
322         if (CHECK_FAIL(sock_fd < 0))
323                 goto out;
324
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));
327
328 out:
329         close(sock_fd);
330         bpf_object__close(obj);
331         close(cg_child);
332         close(cg_parent);
333 }