]> Git Repo - J-linux.git/blob - tools/testing/selftests/bpf/prog_tests/sock_post_bind.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / bpf / prog_tests / sock_post_bind.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/bpf.h>
3 #include <test_progs.h>
4 #include "cgroup_helpers.h"
5
6 #define TEST_NS "sock_post_bind"
7
8 static char bpf_log_buf[4096];
9
10 static struct sock_post_bind_test {
11         const char                      *descr;
12         /* BPF prog properties */
13         const struct bpf_insn           insns[64];
14         enum bpf_attach_type            attach_type;
15         enum bpf_attach_type            expected_attach_type;
16         /* Socket properties */
17         int                             domain;
18         int                             type;
19         /* Endpoint to bind() to */
20         const char *ip;
21         unsigned short port;
22         unsigned short port_retry;
23
24         /* Expected test result */
25         enum {
26                 ATTACH_REJECT,
27                 BIND_REJECT,
28                 SUCCESS,
29                 RETRY_SUCCESS,
30                 RETRY_REJECT
31         } result;
32 } tests[] = {
33         {
34                 .descr = "attach type mismatch bind4 vs bind6",
35                 .insns = {
36                         BPF_MOV64_IMM(BPF_REG_0, 1),
37                         BPF_EXIT_INSN(),
38                 },
39                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
40                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
41                 .result = ATTACH_REJECT,
42         },
43         {
44                 .descr = "attach type mismatch bind6 vs bind4",
45                 .insns = {
46                         BPF_MOV64_IMM(BPF_REG_0, 1),
47                         BPF_EXIT_INSN(),
48                 },
49                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
50                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
51                 .result = ATTACH_REJECT,
52         },
53         {
54                 .descr = "attach type mismatch default vs bind4",
55                 .insns = {
56                         BPF_MOV64_IMM(BPF_REG_0, 1),
57                         BPF_EXIT_INSN(),
58                 },
59                 .expected_attach_type = 0,
60                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
61                 .result = ATTACH_REJECT,
62         },
63         {
64                 .descr = "attach type mismatch bind6 vs sock_create",
65                 .insns = {
66                         BPF_MOV64_IMM(BPF_REG_0, 1),
67                         BPF_EXIT_INSN(),
68                 },
69                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
70                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
71                 .result = ATTACH_REJECT,
72         },
73         {
74                 .descr = "bind4 reject all",
75                 .insns = {
76                         BPF_MOV64_IMM(BPF_REG_0, 0),
77                         BPF_EXIT_INSN(),
78                 },
79                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
80                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
81                 .domain = AF_INET,
82                 .type = SOCK_STREAM,
83                 .ip = "0.0.0.0",
84                 .result = BIND_REJECT,
85         },
86         {
87                 .descr = "bind6 reject all",
88                 .insns = {
89                         BPF_MOV64_IMM(BPF_REG_0, 0),
90                         BPF_EXIT_INSN(),
91                 },
92                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
93                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
94                 .domain = AF_INET6,
95                 .type = SOCK_STREAM,
96                 .ip = "::",
97                 .result = BIND_REJECT,
98         },
99         {
100                 .descr = "bind6 deny specific IP & port",
101                 .insns = {
102                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
103
104                         /* if (ip == expected && port == expected) */
105                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
106                                     offsetof(struct bpf_sock, src_ip6[3])),
107                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
108                                     __bpf_constant_ntohl(0x00000001), 4),
109                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
110                                     offsetof(struct bpf_sock, src_port)),
111                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2),
112
113                         /* return DENY; */
114                         BPF_MOV64_IMM(BPF_REG_0, 0),
115                         BPF_JMP_A(1),
116
117                         /* else return ALLOW; */
118                         BPF_MOV64_IMM(BPF_REG_0, 1),
119                         BPF_EXIT_INSN(),
120                 },
121                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
122                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
123                 .domain = AF_INET6,
124                 .type = SOCK_STREAM,
125                 .ip = "::1",
126                 .port = 8193,
127                 .result = BIND_REJECT,
128         },
129         {
130                 .descr = "bind4 allow specific IP & port",
131                 .insns = {
132                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
133
134                         /* if (ip == expected && port == expected) */
135                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
136                                     offsetof(struct bpf_sock, src_ip4)),
137                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
138                                     __bpf_constant_ntohl(0x7F000001), 4),
139                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
140                                     offsetof(struct bpf_sock, src_port)),
141                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
142
143                         /* return ALLOW; */
144                         BPF_MOV64_IMM(BPF_REG_0, 1),
145                         BPF_JMP_A(1),
146
147                         /* else return DENY; */
148                         BPF_MOV64_IMM(BPF_REG_0, 0),
149                         BPF_EXIT_INSN(),
150                 },
151                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
152                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
153                 .domain = AF_INET,
154                 .type = SOCK_STREAM,
155                 .ip = "127.0.0.1",
156                 .port = 4098,
157                 .result = SUCCESS,
158         },
159         {
160                 .descr = "bind4 deny specific IP & port of TCP, and retry",
161                 .insns = {
162                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
163
164                         /* if (ip == expected && port == expected) */
165                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
166                                     offsetof(struct bpf_sock, src_ip4)),
167                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
168                                     __bpf_constant_ntohl(0x7F000001), 4),
169                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
170                                     offsetof(struct bpf_sock, src_port)),
171                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
172
173                         /* return DENY; */
174                         BPF_MOV64_IMM(BPF_REG_0, 0),
175                         BPF_JMP_A(1),
176
177                         /* else return ALLOW; */
178                         BPF_MOV64_IMM(BPF_REG_0, 1),
179                         BPF_EXIT_INSN(),
180                 },
181                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
182                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
183                 .domain = AF_INET,
184                 .type = SOCK_STREAM,
185                 .ip = "127.0.0.1",
186                 .port = 4098,
187                 .port_retry = 5000,
188                 .result = RETRY_SUCCESS,
189         },
190         {
191                 .descr = "bind4 deny specific IP & port of UDP, and retry",
192                 .insns = {
193                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
194
195                         /* if (ip == expected && port == expected) */
196                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
197                                     offsetof(struct bpf_sock, src_ip4)),
198                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
199                                     __bpf_constant_ntohl(0x7F000001), 4),
200                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
201                                     offsetof(struct bpf_sock, src_port)),
202                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
203
204                         /* return DENY; */
205                         BPF_MOV64_IMM(BPF_REG_0, 0),
206                         BPF_JMP_A(1),
207
208                         /* else return ALLOW; */
209                         BPF_MOV64_IMM(BPF_REG_0, 1),
210                         BPF_EXIT_INSN(),
211                 },
212                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
213                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
214                 .domain = AF_INET,
215                 .type = SOCK_DGRAM,
216                 .ip = "127.0.0.1",
217                 .port = 4098,
218                 .port_retry = 5000,
219                 .result = RETRY_SUCCESS,
220         },
221         {
222                 .descr = "bind6 deny specific IP & port, and retry",
223                 .insns = {
224                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
225
226                         /* if (ip == expected && port == expected) */
227                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
228                                     offsetof(struct bpf_sock, src_ip6[3])),
229                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
230                                     __bpf_constant_ntohl(0x00000001), 4),
231                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
232                                     offsetof(struct bpf_sock, src_port)),
233                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2),
234
235                         /* return DENY; */
236                         BPF_MOV64_IMM(BPF_REG_0, 0),
237                         BPF_JMP_A(1),
238
239                         /* else return ALLOW; */
240                         BPF_MOV64_IMM(BPF_REG_0, 1),
241                         BPF_EXIT_INSN(),
242                 },
243                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
244                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
245                 .domain = AF_INET6,
246                 .type = SOCK_STREAM,
247                 .ip = "::1",
248                 .port = 8193,
249                 .port_retry = 9000,
250                 .result = RETRY_SUCCESS,
251         },
252         {
253                 .descr = "bind4 allow all",
254                 .insns = {
255                         BPF_MOV64_IMM(BPF_REG_0, 1),
256                         BPF_EXIT_INSN(),
257                 },
258                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
259                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
260                 .domain = AF_INET,
261                 .type = SOCK_STREAM,
262                 .ip = "0.0.0.0",
263                 .result = SUCCESS,
264         },
265         {
266                 .descr = "bind6 allow all",
267                 .insns = {
268                         BPF_MOV64_IMM(BPF_REG_0, 1),
269                         BPF_EXIT_INSN(),
270                 },
271                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
272                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
273                 .domain = AF_INET6,
274                 .type = SOCK_STREAM,
275                 .ip = "::",
276                 .result = SUCCESS,
277         },
278 };
279
280 static int load_prog(const struct bpf_insn *insns,
281                      enum bpf_attach_type expected_attach_type)
282 {
283         LIBBPF_OPTS(bpf_prog_load_opts, opts,
284                     .expected_attach_type = expected_attach_type,
285                     .log_level = 2,
286                     .log_buf = bpf_log_buf,
287                     .log_size = sizeof(bpf_log_buf),
288         );
289         int fd, insns_cnt = 0;
290
291         for (;
292              insns[insns_cnt].code != (BPF_JMP | BPF_EXIT);
293              insns_cnt++) {
294         }
295         insns_cnt++;
296
297         fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns,
298                            insns_cnt, &opts);
299         if (fd < 0)
300                 fprintf(stderr, "%s\n", bpf_log_buf);
301
302         return fd;
303 }
304
305 static int bind_sock(int domain, int type, const char *ip,
306                      unsigned short port, unsigned short port_retry)
307 {
308         struct sockaddr_storage addr;
309         struct sockaddr_in6 *addr6;
310         struct sockaddr_in *addr4;
311         int sockfd = -1;
312         socklen_t len;
313         int res = SUCCESS;
314
315         sockfd = socket(domain, type, 0);
316         if (sockfd < 0)
317                 goto err;
318
319         memset(&addr, 0, sizeof(addr));
320
321         if (domain == AF_INET) {
322                 len = sizeof(struct sockaddr_in);
323                 addr4 = (struct sockaddr_in *)&addr;
324                 addr4->sin_family = domain;
325                 addr4->sin_port = htons(port);
326                 if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1)
327                         goto err;
328         } else if (domain == AF_INET6) {
329                 len = sizeof(struct sockaddr_in6);
330                 addr6 = (struct sockaddr_in6 *)&addr;
331                 addr6->sin6_family = domain;
332                 addr6->sin6_port = htons(port);
333                 if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1)
334                         goto err;
335         } else {
336                 goto err;
337         }
338
339         if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) {
340                 /* sys_bind() may fail for different reasons, errno has to be
341                  * checked to confirm that BPF program rejected it.
342                  */
343                 if (errno != EPERM)
344                         goto err;
345                 if (port_retry)
346                         goto retry;
347                 res = BIND_REJECT;
348                 goto out;
349         }
350
351         goto out;
352 retry:
353         if (domain == AF_INET)
354                 addr4->sin_port = htons(port_retry);
355         else
356                 addr6->sin6_port = htons(port_retry);
357         if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) {
358                 if (errno != EPERM)
359                         goto err;
360                 res = RETRY_REJECT;
361         } else {
362                 res = RETRY_SUCCESS;
363         }
364         goto out;
365 err:
366         res = -1;
367 out:
368         close(sockfd);
369         return res;
370 }
371
372 static int run_test(int cgroup_fd, struct sock_post_bind_test *test)
373 {
374         int err, prog_fd, res, ret = 0;
375
376         prog_fd = load_prog(test->insns, test->expected_attach_type);
377         if (prog_fd < 0)
378                 goto err;
379
380         err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);
381         if (err < 0) {
382                 if (test->result == ATTACH_REJECT)
383                         goto out;
384                 else
385                         goto err;
386         }
387
388         res = bind_sock(test->domain, test->type, test->ip, test->port,
389                         test->port_retry);
390         if (res > 0 && test->result == res)
391                 goto out;
392 err:
393         ret = -1;
394 out:
395         /* Detaching w/o checking return code: best effort attempt. */
396         if (prog_fd != -1)
397                 bpf_prog_detach(cgroup_fd, test->attach_type);
398         close(prog_fd);
399         return ret;
400 }
401
402 void test_sock_post_bind(void)
403 {
404         struct netns_obj *ns;
405         int cgroup_fd;
406         int i;
407
408         cgroup_fd = test__join_cgroup("/post_bind");
409         if (!ASSERT_OK_FD(cgroup_fd, "join_cgroup"))
410                 return;
411
412         ns = netns_new(TEST_NS, true);
413         if (!ASSERT_OK_PTR(ns, "netns_new"))
414                 goto cleanup;
415
416         for (i = 0; i < ARRAY_SIZE(tests); i++) {
417                 if (!test__start_subtest(tests[i].descr))
418                         continue;
419
420                 ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr);
421         }
422
423 cleanup:
424         netns_free(ns);
425         close(cgroup_fd);
426 }
This page took 0.05124 seconds and 4 git commands to generate.