1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2018 Facebook 3 4 #define _GNU_SOURCE 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <unistd.h> 9 10 #include <arpa/inet.h> 11 #include <netinet/in.h> 12 #include <sys/types.h> 13 #include <sys/select.h> 14 #include <sys/socket.h> 15 16 #include <linux/filter.h> 17 18 #include <bpf/bpf.h> 19 #include <bpf/libbpf.h> 20 21 #include "cgroup_helpers.h" 22 #include "bpf_util.h" 23 24 #ifndef ENOTSUPP 25 # define ENOTSUPP 524 26 #endif 27 28 #define CG_PATH "/foo" 29 #define CONNECT4_PROG_PATH "./connect4_prog.bpf.o" 30 #define CONNECT6_PROG_PATH "./connect6_prog.bpf.o" 31 #define SENDMSG4_PROG_PATH "./sendmsg4_prog.bpf.o" 32 #define SENDMSG6_PROG_PATH "./sendmsg6_prog.bpf.o" 33 #define RECVMSG4_PROG_PATH "./recvmsg4_prog.bpf.o" 34 #define RECVMSG6_PROG_PATH "./recvmsg6_prog.bpf.o" 35 #define BIND4_PROG_PATH "./bind4_prog.bpf.o" 36 #define BIND6_PROG_PATH "./bind6_prog.bpf.o" 37 38 #define SERV4_IP "192.168.1.254" 39 #define SERV4_REWRITE_IP "127.0.0.1" 40 #define SRC4_IP "172.16.0.1" 41 #define SRC4_REWRITE_IP "127.0.0.4" 42 #define SERV4_PORT 4040 43 #define SERV4_REWRITE_PORT 4444 44 45 #define SERV6_IP "face:b00c:1234:5678::abcd" 46 #define SERV6_REWRITE_IP "::1" 47 #define SERV6_V4MAPPED_IP "::ffff:192.168.0.4" 48 #define SRC6_IP "::1" 49 #define SRC6_REWRITE_IP "::6" 50 #define WILDCARD6_IP "::" 51 #define SERV6_PORT 6060 52 #define SERV6_REWRITE_PORT 6666 53 54 #define INET_NTOP_BUF 40 55 56 struct sock_addr_test; 57 58 typedef int (*load_fn)(const struct sock_addr_test *test); 59 typedef int (*info_fn)(int, struct sockaddr *, socklen_t *); 60 61 char bpf_log_buf[BPF_LOG_BUF_SIZE]; 62 63 struct sock_addr_test { 64 const char *descr; 65 /* BPF prog properties */ 66 load_fn loadfn; 67 enum bpf_attach_type expected_attach_type; 68 enum bpf_attach_type attach_type; 69 /* Socket properties */ 70 int domain; 71 int type; 72 /* IP:port pairs for BPF prog to override */ 73 const char *requested_ip; 74 unsigned short requested_port; 75 const char *expected_ip; 76 unsigned short expected_port; 77 const char *expected_src_ip; 78 /* Expected test result */ 79 enum { 80 LOAD_REJECT, 81 ATTACH_REJECT, 82 ATTACH_OKAY, 83 SYSCALL_EPERM, 84 SYSCALL_ENOTSUPP, 85 SUCCESS, 86 } expected_result; 87 }; 88 89 static int bind4_prog_load(const struct sock_addr_test *test); 90 static int bind6_prog_load(const struct sock_addr_test *test); 91 static int connect4_prog_load(const struct sock_addr_test *test); 92 static int connect6_prog_load(const struct sock_addr_test *test); 93 static int sendmsg_allow_prog_load(const struct sock_addr_test *test); 94 static int sendmsg_deny_prog_load(const struct sock_addr_test *test); 95 static int recvmsg_allow_prog_load(const struct sock_addr_test *test); 96 static int recvmsg_deny_prog_load(const struct sock_addr_test *test); 97 static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test); 98 static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test); 99 static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test); 100 static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test); 101 static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test); 102 static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test); 103 static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test); 104 static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test); 105 106 static struct sock_addr_test tests[] = { 107 /* bind */ 108 { 109 "bind4: load prog with wrong expected attach type", 110 bind4_prog_load, 111 BPF_CGROUP_INET6_BIND, 112 BPF_CGROUP_INET4_BIND, 113 AF_INET, 114 SOCK_STREAM, 115 NULL, 116 0, 117 NULL, 118 0, 119 NULL, 120 LOAD_REJECT, 121 }, 122 { 123 "bind4: attach prog with wrong attach type", 124 bind4_prog_load, 125 BPF_CGROUP_INET4_BIND, 126 BPF_CGROUP_INET6_BIND, 127 AF_INET, 128 SOCK_STREAM, 129 NULL, 130 0, 131 NULL, 132 0, 133 NULL, 134 ATTACH_REJECT, 135 }, 136 { 137 "bind4: rewrite IP & TCP port in", 138 bind4_prog_load, 139 BPF_CGROUP_INET4_BIND, 140 BPF_CGROUP_INET4_BIND, 141 AF_INET, 142 SOCK_STREAM, 143 SERV4_IP, 144 SERV4_PORT, 145 SERV4_REWRITE_IP, 146 SERV4_REWRITE_PORT, 147 NULL, 148 SUCCESS, 149 }, 150 { 151 "bind4: rewrite IP & UDP port in", 152 bind4_prog_load, 153 BPF_CGROUP_INET4_BIND, 154 BPF_CGROUP_INET4_BIND, 155 AF_INET, 156 SOCK_DGRAM, 157 SERV4_IP, 158 SERV4_PORT, 159 SERV4_REWRITE_IP, 160 SERV4_REWRITE_PORT, 161 NULL, 162 SUCCESS, 163 }, 164 { 165 "bind6: load prog with wrong expected attach type", 166 bind6_prog_load, 167 BPF_CGROUP_INET4_BIND, 168 BPF_CGROUP_INET6_BIND, 169 AF_INET6, 170 SOCK_STREAM, 171 NULL, 172 0, 173 NULL, 174 0, 175 NULL, 176 LOAD_REJECT, 177 }, 178 { 179 "bind6: attach prog with wrong attach type", 180 bind6_prog_load, 181 BPF_CGROUP_INET6_BIND, 182 BPF_CGROUP_INET4_BIND, 183 AF_INET, 184 SOCK_STREAM, 185 NULL, 186 0, 187 NULL, 188 0, 189 NULL, 190 ATTACH_REJECT, 191 }, 192 { 193 "bind6: rewrite IP & TCP port in", 194 bind6_prog_load, 195 BPF_CGROUP_INET6_BIND, 196 BPF_CGROUP_INET6_BIND, 197 AF_INET6, 198 SOCK_STREAM, 199 SERV6_IP, 200 SERV6_PORT, 201 SERV6_REWRITE_IP, 202 SERV6_REWRITE_PORT, 203 NULL, 204 SUCCESS, 205 }, 206 { 207 "bind6: rewrite IP & UDP port in", 208 bind6_prog_load, 209 BPF_CGROUP_INET6_BIND, 210 BPF_CGROUP_INET6_BIND, 211 AF_INET6, 212 SOCK_DGRAM, 213 SERV6_IP, 214 SERV6_PORT, 215 SERV6_REWRITE_IP, 216 SERV6_REWRITE_PORT, 217 NULL, 218 SUCCESS, 219 }, 220 221 /* connect */ 222 { 223 "connect4: load prog with wrong expected attach type", 224 connect4_prog_load, 225 BPF_CGROUP_INET6_CONNECT, 226 BPF_CGROUP_INET4_CONNECT, 227 AF_INET, 228 SOCK_STREAM, 229 NULL, 230 0, 231 NULL, 232 0, 233 NULL, 234 LOAD_REJECT, 235 }, 236 { 237 "connect4: attach prog with wrong attach type", 238 connect4_prog_load, 239 BPF_CGROUP_INET4_CONNECT, 240 BPF_CGROUP_INET6_CONNECT, 241 AF_INET, 242 SOCK_STREAM, 243 NULL, 244 0, 245 NULL, 246 0, 247 NULL, 248 ATTACH_REJECT, 249 }, 250 { 251 "connect4: rewrite IP & TCP port", 252 connect4_prog_load, 253 BPF_CGROUP_INET4_CONNECT, 254 BPF_CGROUP_INET4_CONNECT, 255 AF_INET, 256 SOCK_STREAM, 257 SERV4_IP, 258 SERV4_PORT, 259 SERV4_REWRITE_IP, 260 SERV4_REWRITE_PORT, 261 SRC4_REWRITE_IP, 262 SUCCESS, 263 }, 264 { 265 "connect4: rewrite IP & UDP port", 266 connect4_prog_load, 267 BPF_CGROUP_INET4_CONNECT, 268 BPF_CGROUP_INET4_CONNECT, 269 AF_INET, 270 SOCK_DGRAM, 271 SERV4_IP, 272 SERV4_PORT, 273 SERV4_REWRITE_IP, 274 SERV4_REWRITE_PORT, 275 SRC4_REWRITE_IP, 276 SUCCESS, 277 }, 278 { 279 "connect6: load prog with wrong expected attach type", 280 connect6_prog_load, 281 BPF_CGROUP_INET4_CONNECT, 282 BPF_CGROUP_INET6_CONNECT, 283 AF_INET6, 284 SOCK_STREAM, 285 NULL, 286 0, 287 NULL, 288 0, 289 NULL, 290 LOAD_REJECT, 291 }, 292 { 293 "connect6: attach prog with wrong attach type", 294 connect6_prog_load, 295 BPF_CGROUP_INET6_CONNECT, 296 BPF_CGROUP_INET4_CONNECT, 297 AF_INET, 298 SOCK_STREAM, 299 NULL, 300 0, 301 NULL, 302 0, 303 NULL, 304 ATTACH_REJECT, 305 }, 306 { 307 "connect6: rewrite IP & TCP port", 308 connect6_prog_load, 309 BPF_CGROUP_INET6_CONNECT, 310 BPF_CGROUP_INET6_CONNECT, 311 AF_INET6, 312 SOCK_STREAM, 313 SERV6_IP, 314 SERV6_PORT, 315 SERV6_REWRITE_IP, 316 SERV6_REWRITE_PORT, 317 SRC6_REWRITE_IP, 318 SUCCESS, 319 }, 320 { 321 "connect6: rewrite IP & UDP port", 322 connect6_prog_load, 323 BPF_CGROUP_INET6_CONNECT, 324 BPF_CGROUP_INET6_CONNECT, 325 AF_INET6, 326 SOCK_DGRAM, 327 SERV6_IP, 328 SERV6_PORT, 329 SERV6_REWRITE_IP, 330 SERV6_REWRITE_PORT, 331 SRC6_REWRITE_IP, 332 SUCCESS, 333 }, 334 335 /* sendmsg */ 336 { 337 "sendmsg4: load prog with wrong expected attach type", 338 sendmsg4_rw_asm_prog_load, 339 BPF_CGROUP_UDP6_SENDMSG, 340 BPF_CGROUP_UDP4_SENDMSG, 341 AF_INET, 342 SOCK_DGRAM, 343 NULL, 344 0, 345 NULL, 346 0, 347 NULL, 348 LOAD_REJECT, 349 }, 350 { 351 "sendmsg4: attach prog with wrong attach type", 352 sendmsg4_rw_asm_prog_load, 353 BPF_CGROUP_UDP4_SENDMSG, 354 BPF_CGROUP_UDP6_SENDMSG, 355 AF_INET, 356 SOCK_DGRAM, 357 NULL, 358 0, 359 NULL, 360 0, 361 NULL, 362 ATTACH_REJECT, 363 }, 364 { 365 "sendmsg4: rewrite IP & port (asm)", 366 sendmsg4_rw_asm_prog_load, 367 BPF_CGROUP_UDP4_SENDMSG, 368 BPF_CGROUP_UDP4_SENDMSG, 369 AF_INET, 370 SOCK_DGRAM, 371 SERV4_IP, 372 SERV4_PORT, 373 SERV4_REWRITE_IP, 374 SERV4_REWRITE_PORT, 375 SRC4_REWRITE_IP, 376 SUCCESS, 377 }, 378 { 379 "sendmsg4: rewrite IP & port (C)", 380 sendmsg4_rw_c_prog_load, 381 BPF_CGROUP_UDP4_SENDMSG, 382 BPF_CGROUP_UDP4_SENDMSG, 383 AF_INET, 384 SOCK_DGRAM, 385 SERV4_IP, 386 SERV4_PORT, 387 SERV4_REWRITE_IP, 388 SERV4_REWRITE_PORT, 389 SRC4_REWRITE_IP, 390 SUCCESS, 391 }, 392 { 393 "sendmsg4: deny call", 394 sendmsg_deny_prog_load, 395 BPF_CGROUP_UDP4_SENDMSG, 396 BPF_CGROUP_UDP4_SENDMSG, 397 AF_INET, 398 SOCK_DGRAM, 399 SERV4_IP, 400 SERV4_PORT, 401 SERV4_REWRITE_IP, 402 SERV4_REWRITE_PORT, 403 SRC4_REWRITE_IP, 404 SYSCALL_EPERM, 405 }, 406 { 407 "sendmsg6: load prog with wrong expected attach type", 408 sendmsg6_rw_asm_prog_load, 409 BPF_CGROUP_UDP4_SENDMSG, 410 BPF_CGROUP_UDP6_SENDMSG, 411 AF_INET6, 412 SOCK_DGRAM, 413 NULL, 414 0, 415 NULL, 416 0, 417 NULL, 418 LOAD_REJECT, 419 }, 420 { 421 "sendmsg6: attach prog with wrong attach type", 422 sendmsg6_rw_asm_prog_load, 423 BPF_CGROUP_UDP6_SENDMSG, 424 BPF_CGROUP_UDP4_SENDMSG, 425 AF_INET6, 426 SOCK_DGRAM, 427 NULL, 428 0, 429 NULL, 430 0, 431 NULL, 432 ATTACH_REJECT, 433 }, 434 { 435 "sendmsg6: rewrite IP & port (asm)", 436 sendmsg6_rw_asm_prog_load, 437 BPF_CGROUP_UDP6_SENDMSG, 438 BPF_CGROUP_UDP6_SENDMSG, 439 AF_INET6, 440 SOCK_DGRAM, 441 SERV6_IP, 442 SERV6_PORT, 443 SERV6_REWRITE_IP, 444 SERV6_REWRITE_PORT, 445 SRC6_REWRITE_IP, 446 SUCCESS, 447 }, 448 { 449 "sendmsg6: rewrite IP & port (C)", 450 sendmsg6_rw_c_prog_load, 451 BPF_CGROUP_UDP6_SENDMSG, 452 BPF_CGROUP_UDP6_SENDMSG, 453 AF_INET6, 454 SOCK_DGRAM, 455 SERV6_IP, 456 SERV6_PORT, 457 SERV6_REWRITE_IP, 458 SERV6_REWRITE_PORT, 459 SRC6_REWRITE_IP, 460 SUCCESS, 461 }, 462 { 463 "sendmsg6: IPv4-mapped IPv6", 464 sendmsg6_rw_v4mapped_prog_load, 465 BPF_CGROUP_UDP6_SENDMSG, 466 BPF_CGROUP_UDP6_SENDMSG, 467 AF_INET6, 468 SOCK_DGRAM, 469 SERV6_IP, 470 SERV6_PORT, 471 SERV6_REWRITE_IP, 472 SERV6_REWRITE_PORT, 473 SRC6_REWRITE_IP, 474 SYSCALL_ENOTSUPP, 475 }, 476 { 477 "sendmsg6: set dst IP = [::] (BSD'ism)", 478 sendmsg6_rw_wildcard_prog_load, 479 BPF_CGROUP_UDP6_SENDMSG, 480 BPF_CGROUP_UDP6_SENDMSG, 481 AF_INET6, 482 SOCK_DGRAM, 483 SERV6_IP, 484 SERV6_PORT, 485 SERV6_REWRITE_IP, 486 SERV6_REWRITE_PORT, 487 SRC6_REWRITE_IP, 488 SUCCESS, 489 }, 490 { 491 "sendmsg6: preserve dst IP = [::] (BSD'ism)", 492 sendmsg_allow_prog_load, 493 BPF_CGROUP_UDP6_SENDMSG, 494 BPF_CGROUP_UDP6_SENDMSG, 495 AF_INET6, 496 SOCK_DGRAM, 497 WILDCARD6_IP, 498 SERV6_PORT, 499 SERV6_REWRITE_IP, 500 SERV6_PORT, 501 SRC6_IP, 502 SUCCESS, 503 }, 504 { 505 "sendmsg6: deny call", 506 sendmsg_deny_prog_load, 507 BPF_CGROUP_UDP6_SENDMSG, 508 BPF_CGROUP_UDP6_SENDMSG, 509 AF_INET6, 510 SOCK_DGRAM, 511 SERV6_IP, 512 SERV6_PORT, 513 SERV6_REWRITE_IP, 514 SERV6_REWRITE_PORT, 515 SRC6_REWRITE_IP, 516 SYSCALL_EPERM, 517 }, 518 519 /* recvmsg */ 520 { 521 "recvmsg4: return code ok", 522 recvmsg_allow_prog_load, 523 BPF_CGROUP_UDP4_RECVMSG, 524 BPF_CGROUP_UDP4_RECVMSG, 525 AF_INET, 526 SOCK_DGRAM, 527 NULL, 528 0, 529 NULL, 530 0, 531 NULL, 532 ATTACH_OKAY, 533 }, 534 { 535 "recvmsg4: return code !ok", 536 recvmsg_deny_prog_load, 537 BPF_CGROUP_UDP4_RECVMSG, 538 BPF_CGROUP_UDP4_RECVMSG, 539 AF_INET, 540 SOCK_DGRAM, 541 NULL, 542 0, 543 NULL, 544 0, 545 NULL, 546 LOAD_REJECT, 547 }, 548 { 549 "recvmsg6: return code ok", 550 recvmsg_allow_prog_load, 551 BPF_CGROUP_UDP6_RECVMSG, 552 BPF_CGROUP_UDP6_RECVMSG, 553 AF_INET6, 554 SOCK_DGRAM, 555 NULL, 556 0, 557 NULL, 558 0, 559 NULL, 560 ATTACH_OKAY, 561 }, 562 { 563 "recvmsg6: return code !ok", 564 recvmsg_deny_prog_load, 565 BPF_CGROUP_UDP6_RECVMSG, 566 BPF_CGROUP_UDP6_RECVMSG, 567 AF_INET6, 568 SOCK_DGRAM, 569 NULL, 570 0, 571 NULL, 572 0, 573 NULL, 574 LOAD_REJECT, 575 }, 576 { 577 "recvmsg4: rewrite IP & port (C)", 578 recvmsg4_rw_c_prog_load, 579 BPF_CGROUP_UDP4_RECVMSG, 580 BPF_CGROUP_UDP4_RECVMSG, 581 AF_INET, 582 SOCK_DGRAM, 583 SERV4_REWRITE_IP, 584 SERV4_REWRITE_PORT, 585 SERV4_REWRITE_IP, 586 SERV4_REWRITE_PORT, 587 SERV4_IP, 588 SUCCESS, 589 }, 590 { 591 "recvmsg6: rewrite IP & port (C)", 592 recvmsg6_rw_c_prog_load, 593 BPF_CGROUP_UDP6_RECVMSG, 594 BPF_CGROUP_UDP6_RECVMSG, 595 AF_INET6, 596 SOCK_DGRAM, 597 SERV6_REWRITE_IP, 598 SERV6_REWRITE_PORT, 599 SERV6_REWRITE_IP, 600 SERV6_REWRITE_PORT, 601 SERV6_IP, 602 SUCCESS, 603 }, 604 }; 605 606 static int mk_sockaddr(int domain, const char *ip, unsigned short port, 607 struct sockaddr *addr, socklen_t addr_len) 608 { 609 struct sockaddr_in6 *addr6; 610 struct sockaddr_in *addr4; 611 612 if (domain != AF_INET && domain != AF_INET6) { 613 log_err("Unsupported address family"); 614 return -1; 615 } 616 617 memset(addr, 0, addr_len); 618 619 if (domain == AF_INET) { 620 if (addr_len < sizeof(struct sockaddr_in)) 621 return -1; 622 addr4 = (struct sockaddr_in *)addr; 623 addr4->sin_family = domain; 624 addr4->sin_port = htons(port); 625 if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) { 626 log_err("Invalid IPv4: %s", ip); 627 return -1; 628 } 629 } else if (domain == AF_INET6) { 630 if (addr_len < sizeof(struct sockaddr_in6)) 631 return -1; 632 addr6 = (struct sockaddr_in6 *)addr; 633 addr6->sin6_family = domain; 634 addr6->sin6_port = htons(port); 635 if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) { 636 log_err("Invalid IPv6: %s", ip); 637 return -1; 638 } 639 } 640 641 return 0; 642 } 643 644 static int load_insns(const struct sock_addr_test *test, 645 const struct bpf_insn *insns, size_t insns_cnt) 646 { 647 LIBBPF_OPTS(bpf_prog_load_opts, opts); 648 int ret; 649 650 opts.expected_attach_type = test->expected_attach_type; 651 opts.log_buf = bpf_log_buf; 652 opts.log_size = BPF_LOG_BUF_SIZE; 653 654 ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, NULL, "GPL", insns, insns_cnt, &opts); 655 if (ret < 0 && test->expected_result != LOAD_REJECT) { 656 log_err(">>> Loading program error.\n" 657 ">>> Verifier output:\n%s\n-------\n", bpf_log_buf); 658 } 659 660 return ret; 661 } 662 663 static int load_path(const struct sock_addr_test *test, const char *path) 664 { 665 struct bpf_object *obj; 666 struct bpf_program *prog; 667 int err; 668 669 obj = bpf_object__open_file(path, NULL); 670 err = libbpf_get_error(obj); 671 if (err) { 672 log_err(">>> Opening BPF object (%s) error.\n", path); 673 return -1; 674 } 675 676 prog = bpf_object__next_program(obj, NULL); 677 if (!prog) 678 goto err_out; 679 680 bpf_program__set_type(prog, BPF_PROG_TYPE_CGROUP_SOCK_ADDR); 681 bpf_program__set_expected_attach_type(prog, test->expected_attach_type); 682 bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32); 683 684 err = bpf_object__load(obj); 685 if (err) { 686 if (test->expected_result != LOAD_REJECT) 687 log_err(">>> Loading program (%s) error.\n", path); 688 goto err_out; 689 } 690 691 return bpf_program__fd(prog); 692 err_out: 693 bpf_object__close(obj); 694 return -1; 695 } 696 697 static int bind4_prog_load(const struct sock_addr_test *test) 698 { 699 return load_path(test, BIND4_PROG_PATH); 700 } 701 702 static int bind6_prog_load(const struct sock_addr_test *test) 703 { 704 return load_path(test, BIND6_PROG_PATH); 705 } 706 707 static int connect4_prog_load(const struct sock_addr_test *test) 708 { 709 return load_path(test, CONNECT4_PROG_PATH); 710 } 711 712 static int connect6_prog_load(const struct sock_addr_test *test) 713 { 714 return load_path(test, CONNECT6_PROG_PATH); 715 } 716 717 static int xmsg_ret_only_prog_load(const struct sock_addr_test *test, 718 int32_t rc) 719 { 720 struct bpf_insn insns[] = { 721 /* return rc */ 722 BPF_MOV64_IMM(BPF_REG_0, rc), 723 BPF_EXIT_INSN(), 724 }; 725 return load_insns(test, insns, ARRAY_SIZE(insns)); 726 } 727 728 static int sendmsg_allow_prog_load(const struct sock_addr_test *test) 729 { 730 return xmsg_ret_only_prog_load(test, /*rc*/ 1); 731 } 732 733 static int sendmsg_deny_prog_load(const struct sock_addr_test *test) 734 { 735 return xmsg_ret_only_prog_load(test, /*rc*/ 0); 736 } 737 738 static int recvmsg_allow_prog_load(const struct sock_addr_test *test) 739 { 740 return xmsg_ret_only_prog_load(test, /*rc*/ 1); 741 } 742 743 static int recvmsg_deny_prog_load(const struct sock_addr_test *test) 744 { 745 return xmsg_ret_only_prog_load(test, /*rc*/ 0); 746 } 747 748 static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test) 749 { 750 struct sockaddr_in dst4_rw_addr; 751 struct in_addr src4_rw_ip; 752 753 if (inet_pton(AF_INET, SRC4_REWRITE_IP, (void *)&src4_rw_ip) != 1) { 754 log_err("Invalid IPv4: %s", SRC4_REWRITE_IP); 755 return -1; 756 } 757 758 if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT, 759 (struct sockaddr *)&dst4_rw_addr, 760 sizeof(dst4_rw_addr)) == -1) 761 return -1; 762 763 struct bpf_insn insns[] = { 764 BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 765 766 /* if (sk.family == AF_INET && */ 767 BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 768 offsetof(struct bpf_sock_addr, family)), 769 BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 8), 770 771 /* sk.type == SOCK_DGRAM) { */ 772 BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 773 offsetof(struct bpf_sock_addr, type)), 774 BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 6), 775 776 /* msg_src_ip4 = src4_rw_ip */ 777 BPF_MOV32_IMM(BPF_REG_7, src4_rw_ip.s_addr), 778 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, 779 offsetof(struct bpf_sock_addr, msg_src_ip4)), 780 781 /* user_ip4 = dst4_rw_addr.sin_addr */ 782 BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_addr.s_addr), 783 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, 784 offsetof(struct bpf_sock_addr, user_ip4)), 785 786 /* user_port = dst4_rw_addr.sin_port */ 787 BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_port), 788 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, 789 offsetof(struct bpf_sock_addr, user_port)), 790 /* } */ 791 792 /* return 1 */ 793 BPF_MOV64_IMM(BPF_REG_0, 1), 794 BPF_EXIT_INSN(), 795 }; 796 797 return load_insns(test, insns, ARRAY_SIZE(insns)); 798 } 799 800 static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test) 801 { 802 return load_path(test, RECVMSG4_PROG_PATH); 803 } 804 805 static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test) 806 { 807 return load_path(test, SENDMSG4_PROG_PATH); 808 } 809 810 static int sendmsg6_rw_dst_asm_prog_load(const struct sock_addr_test *test, 811 const char *rw_dst_ip) 812 { 813 struct sockaddr_in6 dst6_rw_addr; 814 struct in6_addr src6_rw_ip; 815 816 if (inet_pton(AF_INET6, SRC6_REWRITE_IP, (void *)&src6_rw_ip) != 1) { 817 log_err("Invalid IPv6: %s", SRC6_REWRITE_IP); 818 return -1; 819 } 820 821 if (mk_sockaddr(AF_INET6, rw_dst_ip, SERV6_REWRITE_PORT, 822 (struct sockaddr *)&dst6_rw_addr, 823 sizeof(dst6_rw_addr)) == -1) 824 return -1; 825 826 struct bpf_insn insns[] = { 827 BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 828 829 /* if (sk.family == AF_INET6) { */ 830 BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 831 offsetof(struct bpf_sock_addr, family)), 832 BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18), 833 834 #define STORE_IPV6_WORD_N(DST, SRC, N) \ 835 BPF_MOV32_IMM(BPF_REG_7, SRC[N]), \ 836 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, \ 837 offsetof(struct bpf_sock_addr, DST[N])) 838 839 #define STORE_IPV6(DST, SRC) \ 840 STORE_IPV6_WORD_N(DST, SRC, 0), \ 841 STORE_IPV6_WORD_N(DST, SRC, 1), \ 842 STORE_IPV6_WORD_N(DST, SRC, 2), \ 843 STORE_IPV6_WORD_N(DST, SRC, 3) 844 845 STORE_IPV6(msg_src_ip6, src6_rw_ip.s6_addr32), 846 STORE_IPV6(user_ip6, dst6_rw_addr.sin6_addr.s6_addr32), 847 848 /* user_port = dst6_rw_addr.sin6_port */ 849 BPF_MOV32_IMM(BPF_REG_7, dst6_rw_addr.sin6_port), 850 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, 851 offsetof(struct bpf_sock_addr, user_port)), 852 853 /* } */ 854 855 /* return 1 */ 856 BPF_MOV64_IMM(BPF_REG_0, 1), 857 BPF_EXIT_INSN(), 858 }; 859 860 return load_insns(test, insns, ARRAY_SIZE(insns)); 861 } 862 863 static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test) 864 { 865 return sendmsg6_rw_dst_asm_prog_load(test, SERV6_REWRITE_IP); 866 } 867 868 static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test) 869 { 870 return load_path(test, RECVMSG6_PROG_PATH); 871 } 872 873 static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test) 874 { 875 return sendmsg6_rw_dst_asm_prog_load(test, SERV6_V4MAPPED_IP); 876 } 877 878 static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test) 879 { 880 return sendmsg6_rw_dst_asm_prog_load(test, WILDCARD6_IP); 881 } 882 883 static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test) 884 { 885 return load_path(test, SENDMSG6_PROG_PATH); 886 } 887 888 static int cmp_addr(const struct sockaddr_storage *addr1, 889 const struct sockaddr_storage *addr2, int cmp_port) 890 { 891 const struct sockaddr_in *four1, *four2; 892 const struct sockaddr_in6 *six1, *six2; 893 894 if (addr1->ss_family != addr2->ss_family) 895 return -1; 896 897 if (addr1->ss_family == AF_INET) { 898 four1 = (const struct sockaddr_in *)addr1; 899 four2 = (const struct sockaddr_in *)addr2; 900 return !((four1->sin_port == four2->sin_port || !cmp_port) && 901 four1->sin_addr.s_addr == four2->sin_addr.s_addr); 902 } else if (addr1->ss_family == AF_INET6) { 903 six1 = (const struct sockaddr_in6 *)addr1; 904 six2 = (const struct sockaddr_in6 *)addr2; 905 return !((six1->sin6_port == six2->sin6_port || !cmp_port) && 906 !memcmp(&six1->sin6_addr, &six2->sin6_addr, 907 sizeof(struct in6_addr))); 908 } 909 910 return -1; 911 } 912 913 static int cmp_sock_addr(info_fn fn, int sock1, 914 const struct sockaddr_storage *addr2, int cmp_port) 915 { 916 struct sockaddr_storage addr1; 917 socklen_t len1 = sizeof(addr1); 918 919 memset(&addr1, 0, len1); 920 if (fn(sock1, (struct sockaddr *)&addr1, (socklen_t *)&len1) != 0) 921 return -1; 922 923 return cmp_addr(&addr1, addr2, cmp_port); 924 } 925 926 static int cmp_local_ip(int sock1, const struct sockaddr_storage *addr2) 927 { 928 return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 0); 929 } 930 931 static int cmp_local_addr(int sock1, const struct sockaddr_storage *addr2) 932 { 933 return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 1); 934 } 935 936 static int cmp_peer_addr(int sock1, const struct sockaddr_storage *addr2) 937 { 938 return cmp_sock_addr(getpeername, sock1, addr2, /*cmp_port*/ 1); 939 } 940 941 static int start_server(int type, const struct sockaddr_storage *addr, 942 socklen_t addr_len) 943 { 944 int fd; 945 946 fd = socket(addr->ss_family, type, 0); 947 if (fd == -1) { 948 log_err("Failed to create server socket"); 949 goto out; 950 } 951 952 if (bind(fd, (const struct sockaddr *)addr, addr_len) == -1) { 953 log_err("Failed to bind server socket"); 954 goto close_out; 955 } 956 957 if (type == SOCK_STREAM) { 958 if (listen(fd, 128) == -1) { 959 log_err("Failed to listen on server socket"); 960 goto close_out; 961 } 962 } 963 964 goto out; 965 close_out: 966 close(fd); 967 fd = -1; 968 out: 969 return fd; 970 } 971 972 static int connect_to_server(int type, const struct sockaddr_storage *addr, 973 socklen_t addr_len) 974 { 975 int domain; 976 int fd = -1; 977 978 domain = addr->ss_family; 979 980 if (domain != AF_INET && domain != AF_INET6) { 981 log_err("Unsupported address family"); 982 goto err; 983 } 984 985 fd = socket(domain, type, 0); 986 if (fd == -1) { 987 log_err("Failed to create client socket"); 988 goto err; 989 } 990 991 if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) { 992 log_err("Fail to connect to server"); 993 goto err; 994 } 995 996 goto out; 997 err: 998 close(fd); 999 fd = -1; 1000 out: 1001 return fd; 1002 } 1003 1004 int init_pktinfo(int domain, struct cmsghdr *cmsg) 1005 { 1006 struct in6_pktinfo *pktinfo6; 1007 struct in_pktinfo *pktinfo4; 1008 1009 if (domain == AF_INET) { 1010 cmsg->cmsg_level = SOL_IP; 1011 cmsg->cmsg_type = IP_PKTINFO; 1012 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 1013 pktinfo4 = (struct in_pktinfo *)CMSG_DATA(cmsg); 1014 memset(pktinfo4, 0, sizeof(struct in_pktinfo)); 1015 if (inet_pton(domain, SRC4_IP, 1016 (void *)&pktinfo4->ipi_spec_dst) != 1) 1017 return -1; 1018 } else if (domain == AF_INET6) { 1019 cmsg->cmsg_level = SOL_IPV6; 1020 cmsg->cmsg_type = IPV6_PKTINFO; 1021 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 1022 pktinfo6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); 1023 memset(pktinfo6, 0, sizeof(struct in6_pktinfo)); 1024 if (inet_pton(domain, SRC6_IP, 1025 (void *)&pktinfo6->ipi6_addr) != 1) 1026 return -1; 1027 } else { 1028 return -1; 1029 } 1030 1031 return 0; 1032 } 1033 1034 static int sendmsg_to_server(int type, const struct sockaddr_storage *addr, 1035 socklen_t addr_len, int set_cmsg, int flags, 1036 int *syscall_err) 1037 { 1038 union { 1039 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; 1040 struct cmsghdr align; 1041 } control6; 1042 union { 1043 char buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; 1044 struct cmsghdr align; 1045 } control4; 1046 struct msghdr hdr; 1047 struct iovec iov; 1048 char data = 'a'; 1049 int domain; 1050 int fd = -1; 1051 1052 domain = addr->ss_family; 1053 1054 if (domain != AF_INET && domain != AF_INET6) { 1055 log_err("Unsupported address family"); 1056 goto err; 1057 } 1058 1059 fd = socket(domain, type, 0); 1060 if (fd == -1) { 1061 log_err("Failed to create client socket"); 1062 goto err; 1063 } 1064 1065 memset(&iov, 0, sizeof(iov)); 1066 iov.iov_base = &data; 1067 iov.iov_len = sizeof(data); 1068 1069 memset(&hdr, 0, sizeof(hdr)); 1070 hdr.msg_name = (void *)addr; 1071 hdr.msg_namelen = addr_len; 1072 hdr.msg_iov = &iov; 1073 hdr.msg_iovlen = 1; 1074 1075 if (set_cmsg) { 1076 if (domain == AF_INET) { 1077 hdr.msg_control = &control4; 1078 hdr.msg_controllen = sizeof(control4.buf); 1079 } else if (domain == AF_INET6) { 1080 hdr.msg_control = &control6; 1081 hdr.msg_controllen = sizeof(control6.buf); 1082 } 1083 if (init_pktinfo(domain, CMSG_FIRSTHDR(&hdr))) { 1084 log_err("Fail to init pktinfo"); 1085 goto err; 1086 } 1087 } 1088 1089 if (sendmsg(fd, &hdr, flags) != sizeof(data)) { 1090 log_err("Fail to send message to server"); 1091 *syscall_err = errno; 1092 goto err; 1093 } 1094 1095 goto out; 1096 err: 1097 close(fd); 1098 fd = -1; 1099 out: 1100 return fd; 1101 } 1102 1103 static int fastconnect_to_server(const struct sockaddr_storage *addr, 1104 socklen_t addr_len) 1105 { 1106 int sendmsg_err; 1107 1108 return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0, 1109 MSG_FASTOPEN, &sendmsg_err); 1110 } 1111 1112 static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr) 1113 { 1114 struct timeval tv; 1115 struct msghdr hdr; 1116 struct iovec iov; 1117 char data[64]; 1118 fd_set rfds; 1119 1120 FD_ZERO(&rfds); 1121 FD_SET(sockfd, &rfds); 1122 1123 tv.tv_sec = 2; 1124 tv.tv_usec = 0; 1125 1126 if (select(sockfd + 1, &rfds, NULL, NULL, &tv) <= 0 || 1127 !FD_ISSET(sockfd, &rfds)) 1128 return -1; 1129 1130 memset(&iov, 0, sizeof(iov)); 1131 iov.iov_base = data; 1132 iov.iov_len = sizeof(data); 1133 1134 memset(&hdr, 0, sizeof(hdr)); 1135 hdr.msg_name = src_addr; 1136 hdr.msg_namelen = sizeof(struct sockaddr_storage); 1137 hdr.msg_iov = &iov; 1138 hdr.msg_iovlen = 1; 1139 1140 return recvmsg(sockfd, &hdr, 0); 1141 } 1142 1143 static int init_addrs(const struct sock_addr_test *test, 1144 struct sockaddr_storage *requested_addr, 1145 struct sockaddr_storage *expected_addr, 1146 struct sockaddr_storage *expected_src_addr) 1147 { 1148 socklen_t addr_len = sizeof(struct sockaddr_storage); 1149 1150 if (mk_sockaddr(test->domain, test->expected_ip, test->expected_port, 1151 (struct sockaddr *)expected_addr, addr_len) == -1) 1152 goto err; 1153 1154 if (mk_sockaddr(test->domain, test->requested_ip, test->requested_port, 1155 (struct sockaddr *)requested_addr, addr_len) == -1) 1156 goto err; 1157 1158 if (test->expected_src_ip && 1159 mk_sockaddr(test->domain, test->expected_src_ip, 0, 1160 (struct sockaddr *)expected_src_addr, addr_len) == -1) 1161 goto err; 1162 1163 return 0; 1164 err: 1165 return -1; 1166 } 1167 1168 static int run_bind_test_case(const struct sock_addr_test *test) 1169 { 1170 socklen_t addr_len = sizeof(struct sockaddr_storage); 1171 struct sockaddr_storage requested_addr; 1172 struct sockaddr_storage expected_addr; 1173 int clientfd = -1; 1174 int servfd = -1; 1175 int err = 0; 1176 1177 if (init_addrs(test, &requested_addr, &expected_addr, NULL)) 1178 goto err; 1179 1180 servfd = start_server(test->type, &requested_addr, addr_len); 1181 if (servfd == -1) 1182 goto err; 1183 1184 if (cmp_local_addr(servfd, &expected_addr)) 1185 goto err; 1186 1187 /* Try to connect to server just in case */ 1188 clientfd = connect_to_server(test->type, &expected_addr, addr_len); 1189 if (clientfd == -1) 1190 goto err; 1191 1192 goto out; 1193 err: 1194 err = -1; 1195 out: 1196 close(clientfd); 1197 close(servfd); 1198 return err; 1199 } 1200 1201 static int run_connect_test_case(const struct sock_addr_test *test) 1202 { 1203 socklen_t addr_len = sizeof(struct sockaddr_storage); 1204 struct sockaddr_storage expected_src_addr; 1205 struct sockaddr_storage requested_addr; 1206 struct sockaddr_storage expected_addr; 1207 int clientfd = -1; 1208 int servfd = -1; 1209 int err = 0; 1210 1211 if (init_addrs(test, &requested_addr, &expected_addr, 1212 &expected_src_addr)) 1213 goto err; 1214 1215 /* Prepare server to connect to */ 1216 servfd = start_server(test->type, &expected_addr, addr_len); 1217 if (servfd == -1) 1218 goto err; 1219 1220 clientfd = connect_to_server(test->type, &requested_addr, addr_len); 1221 if (clientfd == -1) 1222 goto err; 1223 1224 /* Make sure src and dst addrs were overridden properly */ 1225 if (cmp_peer_addr(clientfd, &expected_addr)) 1226 goto err; 1227 1228 if (cmp_local_ip(clientfd, &expected_src_addr)) 1229 goto err; 1230 1231 if (test->type == SOCK_STREAM) { 1232 /* Test TCP Fast Open scenario */ 1233 clientfd = fastconnect_to_server(&requested_addr, addr_len); 1234 if (clientfd == -1) 1235 goto err; 1236 1237 /* Make sure src and dst addrs were overridden properly */ 1238 if (cmp_peer_addr(clientfd, &expected_addr)) 1239 goto err; 1240 1241 if (cmp_local_ip(clientfd, &expected_src_addr)) 1242 goto err; 1243 } 1244 1245 goto out; 1246 err: 1247 err = -1; 1248 out: 1249 close(clientfd); 1250 close(servfd); 1251 return err; 1252 } 1253 1254 static int run_xmsg_test_case(const struct sock_addr_test *test, int max_cmsg) 1255 { 1256 socklen_t addr_len = sizeof(struct sockaddr_storage); 1257 struct sockaddr_storage expected_addr; 1258 struct sockaddr_storage server_addr; 1259 struct sockaddr_storage sendmsg_addr; 1260 struct sockaddr_storage recvmsg_addr; 1261 int clientfd = -1; 1262 int servfd = -1; 1263 int set_cmsg; 1264 int err = 0; 1265 1266 if (test->type != SOCK_DGRAM) 1267 goto err; 1268 1269 if (init_addrs(test, &sendmsg_addr, &server_addr, &expected_addr)) 1270 goto err; 1271 1272 /* Prepare server to sendmsg to */ 1273 servfd = start_server(test->type, &server_addr, addr_len); 1274 if (servfd == -1) 1275 goto err; 1276 1277 for (set_cmsg = 0; set_cmsg <= max_cmsg; ++set_cmsg) { 1278 if (clientfd >= 0) 1279 close(clientfd); 1280 1281 clientfd = sendmsg_to_server(test->type, &sendmsg_addr, 1282 addr_len, set_cmsg, /*flags*/0, 1283 &err); 1284 if (err) 1285 goto out; 1286 else if (clientfd == -1) 1287 goto err; 1288 1289 /* Try to receive message on server instead of using 1290 * getpeername(2) on client socket, to check that client's 1291 * destination address was rewritten properly, since 1292 * getpeername(2) doesn't work with unconnected datagram 1293 * sockets. 1294 * 1295 * Get source address from recvmsg(2) as well to make sure 1296 * source was rewritten properly: getsockname(2) can't be used 1297 * since socket is unconnected and source defined for one 1298 * specific packet may differ from the one used by default and 1299 * returned by getsockname(2). 1300 */ 1301 if (recvmsg_from_client(servfd, &recvmsg_addr) == -1) 1302 goto err; 1303 1304 if (cmp_addr(&recvmsg_addr, &expected_addr, /*cmp_port*/0)) 1305 goto err; 1306 } 1307 1308 goto out; 1309 err: 1310 err = -1; 1311 out: 1312 close(clientfd); 1313 close(servfd); 1314 return err; 1315 } 1316 1317 static int run_test_case(int cgfd, const struct sock_addr_test *test) 1318 { 1319 int progfd = -1; 1320 int err = 0; 1321 1322 printf("Test case: %s .. ", test->descr); 1323 1324 progfd = test->loadfn(test); 1325 if (test->expected_result == LOAD_REJECT && progfd < 0) 1326 goto out; 1327 else if (test->expected_result == LOAD_REJECT || progfd < 0) 1328 goto err; 1329 1330 err = bpf_prog_attach(progfd, cgfd, test->attach_type, 1331 BPF_F_ALLOW_OVERRIDE); 1332 if (test->expected_result == ATTACH_REJECT && err) { 1333 err = 0; /* error was expected, reset it */ 1334 goto out; 1335 } else if (test->expected_result == ATTACH_REJECT || err) { 1336 goto err; 1337 } else if (test->expected_result == ATTACH_OKAY) { 1338 err = 0; 1339 goto out; 1340 } 1341 1342 switch (test->attach_type) { 1343 case BPF_CGROUP_INET4_BIND: 1344 case BPF_CGROUP_INET6_BIND: 1345 err = run_bind_test_case(test); 1346 break; 1347 case BPF_CGROUP_INET4_CONNECT: 1348 case BPF_CGROUP_INET6_CONNECT: 1349 err = run_connect_test_case(test); 1350 break; 1351 case BPF_CGROUP_UDP4_SENDMSG: 1352 case BPF_CGROUP_UDP6_SENDMSG: 1353 err = run_xmsg_test_case(test, 1); 1354 break; 1355 case BPF_CGROUP_UDP4_RECVMSG: 1356 case BPF_CGROUP_UDP6_RECVMSG: 1357 err = run_xmsg_test_case(test, 0); 1358 break; 1359 default: 1360 goto err; 1361 } 1362 1363 if (test->expected_result == SYSCALL_EPERM && err == EPERM) { 1364 err = 0; /* error was expected, reset it */ 1365 goto out; 1366 } 1367 1368 if (test->expected_result == SYSCALL_ENOTSUPP && err == ENOTSUPP) { 1369 err = 0; /* error was expected, reset it */ 1370 goto out; 1371 } 1372 1373 if (err || test->expected_result != SUCCESS) 1374 goto err; 1375 1376 goto out; 1377 err: 1378 err = -1; 1379 out: 1380 /* Detaching w/o checking return code: best effort attempt. */ 1381 if (progfd != -1) 1382 bpf_prog_detach(cgfd, test->attach_type); 1383 close(progfd); 1384 printf("[%s]\n", err ? "FAIL" : "PASS"); 1385 return err; 1386 } 1387 1388 static int run_tests(int cgfd) 1389 { 1390 int passes = 0; 1391 int fails = 0; 1392 int i; 1393 1394 for (i = 0; i < ARRAY_SIZE(tests); ++i) { 1395 if (run_test_case(cgfd, &tests[i])) 1396 ++fails; 1397 else 1398 ++passes; 1399 } 1400 printf("Summary: %d PASSED, %d FAILED\n", passes, fails); 1401 return fails ? -1 : 0; 1402 } 1403 1404 int main(int argc, char **argv) 1405 { 1406 int cgfd = -1; 1407 int err = 0; 1408 1409 if (argc < 2) { 1410 fprintf(stderr, 1411 "%s has to be run via %s.sh. Skip direct run.\n", 1412 argv[0], argv[0]); 1413 exit(err); 1414 } 1415 1416 cgfd = cgroup_setup_and_join(CG_PATH); 1417 if (cgfd < 0) 1418 goto err; 1419 1420 /* Use libbpf 1.0 API mode */ 1421 libbpf_set_strict_mode(LIBBPF_STRICT_ALL); 1422 1423 if (run_tests(cgfd)) 1424 goto err; 1425 1426 goto out; 1427 err: 1428 err = -1; 1429 out: 1430 close(cgfd); 1431 cleanup_cgroup_environment(); 1432 return err; 1433 } 1434