]> Git Repo - linux.git/blob - tools/testing/selftests/bpf/test_sock.c
scsi: zfcp: Trace when request remove fails after qdio send fails
[linux.git] / tools / testing / selftests / bpf / test_sock.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018 Facebook
3
4 #include <stdio.h>
5 #include <unistd.h>
6
7 #include <arpa/inet.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10
11 #include <linux/filter.h>
12
13 #include <bpf/bpf.h>
14
15 #include "cgroup_helpers.h"
16 #include <bpf/bpf_endian.h>
17 #include "bpf_util.h"
18
19 #define CG_PATH         "/foo"
20 #define MAX_INSNS       512
21
22 char bpf_log_buf[BPF_LOG_BUF_SIZE];
23 static bool verbose = false;
24
25 struct sock_test {
26         const char *descr;
27         /* BPF prog properties */
28         struct bpf_insn insns[MAX_INSNS];
29         enum bpf_attach_type expected_attach_type;
30         enum bpf_attach_type attach_type;
31         /* Socket properties */
32         int domain;
33         int type;
34         /* Endpoint to bind() to */
35         const char *ip;
36         unsigned short port;
37         unsigned short port_retry;
38         /* Expected test result */
39         enum {
40                 LOAD_REJECT,
41                 ATTACH_REJECT,
42                 BIND_REJECT,
43                 SUCCESS,
44                 RETRY_SUCCESS,
45                 RETRY_REJECT
46         } result;
47 };
48
49 static struct sock_test tests[] = {
50         {
51                 .descr = "bind4 load with invalid access: src_ip6",
52                 .insns = {
53                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
54                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
55                                     offsetof(struct bpf_sock, src_ip6[0])),
56                         BPF_MOV64_IMM(BPF_REG_0, 1),
57                         BPF_EXIT_INSN(),
58                 },
59                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
60                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
61                 .result = LOAD_REJECT,
62         },
63         {
64                 .descr = "bind4 load with invalid access: mark",
65                 .insns = {
66                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
67                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
68                                     offsetof(struct bpf_sock, mark)),
69                         BPF_MOV64_IMM(BPF_REG_0, 1),
70                         BPF_EXIT_INSN(),
71                 },
72                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
73                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
74                 .result = LOAD_REJECT,
75         },
76         {
77                 .descr = "bind6 load with invalid access: src_ip4",
78                 .insns = {
79                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
80                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
81                                     offsetof(struct bpf_sock, src_ip4)),
82                         BPF_MOV64_IMM(BPF_REG_0, 1),
83                         BPF_EXIT_INSN(),
84                 },
85                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
86                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
87                 .result = LOAD_REJECT,
88         },
89         {
90                 .descr = "sock_create load with invalid access: src_port",
91                 .insns = {
92                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
93                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
94                                     offsetof(struct bpf_sock, src_port)),
95                         BPF_MOV64_IMM(BPF_REG_0, 1),
96                         BPF_EXIT_INSN(),
97                 },
98                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
99                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
100                 .result = LOAD_REJECT,
101         },
102         {
103                 .descr = "sock_create load w/o expected_attach_type (compat mode)",
104                 .insns = {
105                         BPF_MOV64_IMM(BPF_REG_0, 1),
106                         BPF_EXIT_INSN(),
107                 },
108                 .expected_attach_type = 0,
109                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
110                 .domain = AF_INET,
111                 .type = SOCK_STREAM,
112                 .ip = "127.0.0.1",
113                 .port = 8097,
114                 .result = SUCCESS,
115         },
116         {
117                 .descr = "sock_create load w/ expected_attach_type",
118                 .insns = {
119                         BPF_MOV64_IMM(BPF_REG_0, 1),
120                         BPF_EXIT_INSN(),
121                 },
122                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
123                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
124                 .domain = AF_INET,
125                 .type = SOCK_STREAM,
126                 .ip = "127.0.0.1",
127                 .port = 8097,
128                 .result = SUCCESS,
129         },
130         {
131                 .descr = "attach type mismatch bind4 vs bind6",
132                 .insns = {
133                         BPF_MOV64_IMM(BPF_REG_0, 1),
134                         BPF_EXIT_INSN(),
135                 },
136                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
137                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
138                 .result = ATTACH_REJECT,
139         },
140         {
141                 .descr = "attach type mismatch bind6 vs bind4",
142                 .insns = {
143                         BPF_MOV64_IMM(BPF_REG_0, 1),
144                         BPF_EXIT_INSN(),
145                 },
146                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
147                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
148                 .result = ATTACH_REJECT,
149         },
150         {
151                 .descr = "attach type mismatch default vs bind4",
152                 .insns = {
153                         BPF_MOV64_IMM(BPF_REG_0, 1),
154                         BPF_EXIT_INSN(),
155                 },
156                 .expected_attach_type = 0,
157                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
158                 .result = ATTACH_REJECT,
159         },
160         {
161                 .descr = "attach type mismatch bind6 vs sock_create",
162                 .insns = {
163                         BPF_MOV64_IMM(BPF_REG_0, 1),
164                         BPF_EXIT_INSN(),
165                 },
166                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
167                 .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
168                 .result = ATTACH_REJECT,
169         },
170         {
171                 .descr = "bind4 reject all",
172                 .insns = {
173                         BPF_MOV64_IMM(BPF_REG_0, 0),
174                         BPF_EXIT_INSN(),
175                 },
176                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
177                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
178                 .domain = AF_INET,
179                 .type = SOCK_STREAM,
180                 .ip = "0.0.0.0",
181                 .result = BIND_REJECT,
182         },
183         {
184                 .descr = "bind6 reject all",
185                 .insns = {
186                         BPF_MOV64_IMM(BPF_REG_0, 0),
187                         BPF_EXIT_INSN(),
188                 },
189                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
190                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
191                 .domain = AF_INET6,
192                 .type = SOCK_STREAM,
193                 .ip = "::",
194                 .result = BIND_REJECT,
195         },
196         {
197                 .descr = "bind6 deny specific IP & port",
198                 .insns = {
199                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
200
201                         /* if (ip == expected && port == expected) */
202                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
203                                     offsetof(struct bpf_sock, src_ip6[3])),
204                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
205                                     __bpf_constant_ntohl(0x00000001), 4),
206                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
207                                     offsetof(struct bpf_sock, src_port)),
208                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2),
209
210                         /* return DENY; */
211                         BPF_MOV64_IMM(BPF_REG_0, 0),
212                         BPF_JMP_A(1),
213
214                         /* else return ALLOW; */
215                         BPF_MOV64_IMM(BPF_REG_0, 1),
216                         BPF_EXIT_INSN(),
217                 },
218                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
219                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
220                 .domain = AF_INET6,
221                 .type = SOCK_STREAM,
222                 .ip = "::1",
223                 .port = 8193,
224                 .result = BIND_REJECT,
225         },
226         {
227                 .descr = "bind4 allow specific IP & port",
228                 .insns = {
229                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
230
231                         /* if (ip == expected && port == expected) */
232                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
233                                     offsetof(struct bpf_sock, src_ip4)),
234                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
235                                     __bpf_constant_ntohl(0x7F000001), 4),
236                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
237                                     offsetof(struct bpf_sock, src_port)),
238                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
239
240                         /* return ALLOW; */
241                         BPF_MOV64_IMM(BPF_REG_0, 1),
242                         BPF_JMP_A(1),
243
244                         /* else return DENY; */
245                         BPF_MOV64_IMM(BPF_REG_0, 0),
246                         BPF_EXIT_INSN(),
247                 },
248                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
249                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
250                 .domain = AF_INET,
251                 .type = SOCK_STREAM,
252                 .ip = "127.0.0.1",
253                 .port = 4098,
254                 .result = SUCCESS,
255         },
256         {
257                 .descr = "bind4 deny specific IP & port of TCP, and retry",
258                 .insns = {
259                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
260
261                         /* if (ip == expected && port == expected) */
262                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
263                                     offsetof(struct bpf_sock, src_ip4)),
264                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
265                                     __bpf_constant_ntohl(0x7F000001), 4),
266                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
267                                     offsetof(struct bpf_sock, src_port)),
268                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
269
270                         /* return DENY; */
271                         BPF_MOV64_IMM(BPF_REG_0, 0),
272                         BPF_JMP_A(1),
273
274                         /* else return ALLOW; */
275                         BPF_MOV64_IMM(BPF_REG_0, 1),
276                         BPF_EXIT_INSN(),
277                 },
278                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
279                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
280                 .domain = AF_INET,
281                 .type = SOCK_STREAM,
282                 .ip = "127.0.0.1",
283                 .port = 4098,
284                 .port_retry = 5000,
285                 .result = RETRY_SUCCESS,
286         },
287         {
288                 .descr = "bind4 deny specific IP & port of UDP, and retry",
289                 .insns = {
290                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
291
292                         /* if (ip == expected && port == expected) */
293                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
294                                     offsetof(struct bpf_sock, src_ip4)),
295                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
296                                     __bpf_constant_ntohl(0x7F000001), 4),
297                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
298                                     offsetof(struct bpf_sock, src_port)),
299                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
300
301                         /* return DENY; */
302                         BPF_MOV64_IMM(BPF_REG_0, 0),
303                         BPF_JMP_A(1),
304
305                         /* else return ALLOW; */
306                         BPF_MOV64_IMM(BPF_REG_0, 1),
307                         BPF_EXIT_INSN(),
308                 },
309                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
310                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
311                 .domain = AF_INET,
312                 .type = SOCK_DGRAM,
313                 .ip = "127.0.0.1",
314                 .port = 4098,
315                 .port_retry = 5000,
316                 .result = RETRY_SUCCESS,
317         },
318         {
319                 .descr = "bind6 deny specific IP & port, and retry",
320                 .insns = {
321                         BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
322
323                         /* if (ip == expected && port == expected) */
324                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
325                                     offsetof(struct bpf_sock, src_ip6[3])),
326                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
327                                     __bpf_constant_ntohl(0x00000001), 4),
328                         BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
329                                     offsetof(struct bpf_sock, src_port)),
330                         BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2),
331
332                         /* return DENY; */
333                         BPF_MOV64_IMM(BPF_REG_0, 0),
334                         BPF_JMP_A(1),
335
336                         /* else return ALLOW; */
337                         BPF_MOV64_IMM(BPF_REG_0, 1),
338                         BPF_EXIT_INSN(),
339                 },
340                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
341                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
342                 .domain = AF_INET6,
343                 .type = SOCK_STREAM,
344                 .ip = "::1",
345                 .port = 8193,
346                 .port_retry = 9000,
347                 .result = RETRY_SUCCESS,
348         },
349         {
350                 .descr = "bind4 allow all",
351                 .insns = {
352                         BPF_MOV64_IMM(BPF_REG_0, 1),
353                         BPF_EXIT_INSN(),
354                 },
355                 .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
356                 .attach_type = BPF_CGROUP_INET4_POST_BIND,
357                 .domain = AF_INET,
358                 .type = SOCK_STREAM,
359                 .ip = "0.0.0.0",
360                 .result = SUCCESS,
361         },
362         {
363                 .descr = "bind6 allow all",
364                 .insns = {
365                         BPF_MOV64_IMM(BPF_REG_0, 1),
366                         BPF_EXIT_INSN(),
367                 },
368                 .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
369                 .attach_type = BPF_CGROUP_INET6_POST_BIND,
370                 .domain = AF_INET6,
371                 .type = SOCK_STREAM,
372                 .ip = "::",
373                 .result = SUCCESS,
374         },
375 };
376
377 static size_t probe_prog_length(const struct bpf_insn *fp)
378 {
379         size_t len;
380
381         for (len = MAX_INSNS - 1; len > 0; --len)
382                 if (fp[len].code != 0 || fp[len].imm != 0)
383                         break;
384         return len + 1;
385 }
386
387 static int load_sock_prog(const struct bpf_insn *prog,
388                           enum bpf_attach_type attach_type)
389 {
390         LIBBPF_OPTS(bpf_prog_load_opts, opts);
391         int ret, insn_cnt;
392
393         insn_cnt = probe_prog_length(prog);
394
395         opts.expected_attach_type = attach_type;
396         opts.log_buf = bpf_log_buf;
397         opts.log_size = BPF_LOG_BUF_SIZE;
398         opts.log_level = 2;
399
400         ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", prog, insn_cnt, &opts);
401         if (verbose && ret < 0)
402                 fprintf(stderr, "%s\n", bpf_log_buf);
403
404         return ret;
405 }
406
407 static int attach_sock_prog(int cgfd, int progfd,
408                             enum bpf_attach_type attach_type)
409 {
410         return bpf_prog_attach(progfd, cgfd, attach_type, BPF_F_ALLOW_OVERRIDE);
411 }
412
413 static int bind_sock(int domain, int type, const char *ip,
414                      unsigned short port, unsigned short port_retry)
415 {
416         struct sockaddr_storage addr;
417         struct sockaddr_in6 *addr6;
418         struct sockaddr_in *addr4;
419         int sockfd = -1;
420         socklen_t len;
421         int res = SUCCESS;
422
423         sockfd = socket(domain, type, 0);
424         if (sockfd < 0)
425                 goto err;
426
427         memset(&addr, 0, sizeof(addr));
428
429         if (domain == AF_INET) {
430                 len = sizeof(struct sockaddr_in);
431                 addr4 = (struct sockaddr_in *)&addr;
432                 addr4->sin_family = domain;
433                 addr4->sin_port = htons(port);
434                 if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1)
435                         goto err;
436         } else if (domain == AF_INET6) {
437                 len = sizeof(struct sockaddr_in6);
438                 addr6 = (struct sockaddr_in6 *)&addr;
439                 addr6->sin6_family = domain;
440                 addr6->sin6_port = htons(port);
441                 if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1)
442                         goto err;
443         } else {
444                 goto err;
445         }
446
447         if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) {
448                 /* sys_bind() may fail for different reasons, errno has to be
449                  * checked to confirm that BPF program rejected it.
450                  */
451                 if (errno != EPERM)
452                         goto err;
453                 if (port_retry)
454                         goto retry;
455                 res = BIND_REJECT;
456                 goto out;
457         }
458
459         goto out;
460 retry:
461         if (domain == AF_INET)
462                 addr4->sin_port = htons(port_retry);
463         else
464                 addr6->sin6_port = htons(port_retry);
465         if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) {
466                 if (errno != EPERM)
467                         goto err;
468                 res = RETRY_REJECT;
469         } else {
470                 res = RETRY_SUCCESS;
471         }
472         goto out;
473 err:
474         res = -1;
475 out:
476         close(sockfd);
477         return res;
478 }
479
480 static int run_test_case(int cgfd, const struct sock_test *test)
481 {
482         int progfd = -1;
483         int err = 0;
484         int res;
485
486         printf("Test case: %s .. ", test->descr);
487         progfd = load_sock_prog(test->insns, test->expected_attach_type);
488         if (progfd < 0) {
489                 if (test->result == LOAD_REJECT)
490                         goto out;
491                 else
492                         goto err;
493         }
494
495         if (attach_sock_prog(cgfd, progfd, test->attach_type) < 0) {
496                 if (test->result == ATTACH_REJECT)
497                         goto out;
498                 else
499                         goto err;
500         }
501
502         res = bind_sock(test->domain, test->type, test->ip, test->port,
503                         test->port_retry);
504         if (res > 0 && test->result == res)
505                 goto out;
506
507 err:
508         err = -1;
509 out:
510         /* Detaching w/o checking return code: best effort attempt. */
511         if (progfd != -1)
512                 bpf_prog_detach(cgfd, test->attach_type);
513         close(progfd);
514         printf("[%s]\n", err ? "FAIL" : "PASS");
515         return err;
516 }
517
518 static int run_tests(int cgfd)
519 {
520         int passes = 0;
521         int fails = 0;
522         int i;
523
524         for (i = 0; i < ARRAY_SIZE(tests); ++i) {
525                 if (run_test_case(cgfd, &tests[i]))
526                         ++fails;
527                 else
528                         ++passes;
529         }
530         printf("Summary: %d PASSED, %d FAILED\n", passes, fails);
531         return fails ? -1 : 0;
532 }
533
534 int main(int argc, char **argv)
535 {
536         int cgfd = -1;
537         int err = 0;
538
539         cgfd = cgroup_setup_and_join(CG_PATH);
540         if (cgfd < 0)
541                 goto err;
542
543         /* Use libbpf 1.0 API mode */
544         libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
545
546         if (run_tests(cgfd))
547                 goto err;
548
549         goto out;
550 err:
551         err = -1;
552 out:
553         close(cgfd);
554         cleanup_cgroup_environment();
555         return err;
556 }
This page took 0.0662779999999999 seconds and 4 git commands to generate.