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