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 struct bpf_load_program_attr load_attr; 649 int ret; 650 651 memset(&load_attr, 0, sizeof(struct bpf_load_program_attr)); 652 load_attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; 653 load_attr.expected_attach_type = test->expected_attach_type; 654 load_attr.insns = insns; 655 load_attr.insns_cnt = insns_cnt; 656 load_attr.license = "GPL"; 657 658 ret = bpf_load_program_xattr(&load_attr, bpf_log_buf, BPF_LOG_BUF_SIZE); 659 if (ret < 0 && test->expected_result != LOAD_REJECT) { 660 log_err(">>> Loading program error.\n" 661 ">>> Verifier output:\n%s\n-------\n", bpf_log_buf); 662 } 663 664 return ret; 665 } 666 667 static int load_path(const struct sock_addr_test *test, const char *path) 668 { 669 struct bpf_prog_load_attr attr; 670 struct bpf_object *obj; 671 int prog_fd; 672 673 memset(&attr, 0, sizeof(struct bpf_prog_load_attr)); 674 attr.file = path; 675 attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; 676 attr.expected_attach_type = test->expected_attach_type; 677 attr.prog_flags = BPF_F_TEST_RND_HI32; 678 679 if (bpf_prog_load_xattr(&attr, &obj, &prog_fd)) { 680 if (test->expected_result != LOAD_REJECT) 681 log_err(">>> Loading program (%s) error.\n", path); 682 return -1; 683 } 684 685 return prog_fd; 686 } 687 688 static int bind4_prog_load(const struct sock_addr_test *test) 689 { 690 return load_path(test, BIND4_PROG_PATH); 691 } 692 693 static int bind6_prog_load(const struct sock_addr_test *test) 694 { 695 return load_path(test, BIND6_PROG_PATH); 696 } 697 698 static int connect4_prog_load(const struct sock_addr_test *test) 699 { 700 return load_path(test, CONNECT4_PROG_PATH); 701 } 702 703 static int connect6_prog_load(const struct sock_addr_test *test) 704 { 705 return load_path(test, CONNECT6_PROG_PATH); 706 } 707 708 static int xmsg_ret_only_prog_load(const struct sock_addr_test *test, 709 int32_t rc) 710 { 711 struct bpf_insn insns[] = { 712 /* return rc */ 713 BPF_MOV64_IMM(BPF_REG_0, rc), 714 BPF_EXIT_INSN(), 715 }; 716 return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn)); 717 } 718 719 static int sendmsg_allow_prog_load(const struct sock_addr_test *test) 720 { 721 return xmsg_ret_only_prog_load(test, /*rc*/ 1); 722 } 723 724 static int sendmsg_deny_prog_load(const struct sock_addr_test *test) 725 { 726 return xmsg_ret_only_prog_load(test, /*rc*/ 0); 727 } 728 729 static int recvmsg_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 recvmsg_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 sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test) 740 { 741 struct sockaddr_in dst4_rw_addr; 742 struct in_addr src4_rw_ip; 743 744 if (inet_pton(AF_INET, SRC4_REWRITE_IP, (void *)&src4_rw_ip) != 1) { 745 log_err("Invalid IPv4: %s", SRC4_REWRITE_IP); 746 return -1; 747 } 748 749 if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT, 750 (struct sockaddr *)&dst4_rw_addr, 751 sizeof(dst4_rw_addr)) == -1) 752 return -1; 753 754 struct bpf_insn insns[] = { 755 BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 756 757 /* if (sk.family == AF_INET && */ 758 BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 759 offsetof(struct bpf_sock_addr, family)), 760 BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 8), 761 762 /* sk.type == SOCK_DGRAM) { */ 763 BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 764 offsetof(struct bpf_sock_addr, type)), 765 BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 6), 766 767 /* msg_src_ip4 = src4_rw_ip */ 768 BPF_MOV32_IMM(BPF_REG_7, src4_rw_ip.s_addr), 769 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, 770 offsetof(struct bpf_sock_addr, msg_src_ip4)), 771 772 /* user_ip4 = dst4_rw_addr.sin_addr */ 773 BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_addr.s_addr), 774 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, 775 offsetof(struct bpf_sock_addr, user_ip4)), 776 777 /* user_port = dst4_rw_addr.sin_port */ 778 BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_port), 779 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, 780 offsetof(struct bpf_sock_addr, user_port)), 781 /* } */ 782 783 /* return 1 */ 784 BPF_MOV64_IMM(BPF_REG_0, 1), 785 BPF_EXIT_INSN(), 786 }; 787 788 return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn)); 789 } 790 791 static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test) 792 { 793 return load_path(test, RECVMSG4_PROG_PATH); 794 } 795 796 static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test) 797 { 798 return load_path(test, SENDMSG4_PROG_PATH); 799 } 800 801 static int sendmsg6_rw_dst_asm_prog_load(const struct sock_addr_test *test, 802 const char *rw_dst_ip) 803 { 804 struct sockaddr_in6 dst6_rw_addr; 805 struct in6_addr src6_rw_ip; 806 807 if (inet_pton(AF_INET6, SRC6_REWRITE_IP, (void *)&src6_rw_ip) != 1) { 808 log_err("Invalid IPv6: %s", SRC6_REWRITE_IP); 809 return -1; 810 } 811 812 if (mk_sockaddr(AF_INET6, rw_dst_ip, SERV6_REWRITE_PORT, 813 (struct sockaddr *)&dst6_rw_addr, 814 sizeof(dst6_rw_addr)) == -1) 815 return -1; 816 817 struct bpf_insn insns[] = { 818 BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 819 820 /* if (sk.family == AF_INET6) { */ 821 BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 822 offsetof(struct bpf_sock_addr, family)), 823 BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18), 824 825 #define STORE_IPV6_WORD_N(DST, SRC, N) \ 826 BPF_MOV32_IMM(BPF_REG_7, SRC[N]), \ 827 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, \ 828 offsetof(struct bpf_sock_addr, DST[N])) 829 830 #define STORE_IPV6(DST, SRC) \ 831 STORE_IPV6_WORD_N(DST, SRC, 0), \ 832 STORE_IPV6_WORD_N(DST, SRC, 1), \ 833 STORE_IPV6_WORD_N(DST, SRC, 2), \ 834 STORE_IPV6_WORD_N(DST, SRC, 3) 835 836 STORE_IPV6(msg_src_ip6, src6_rw_ip.s6_addr32), 837 STORE_IPV6(user_ip6, dst6_rw_addr.sin6_addr.s6_addr32), 838 839 /* user_port = dst6_rw_addr.sin6_port */ 840 BPF_MOV32_IMM(BPF_REG_7, dst6_rw_addr.sin6_port), 841 BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, 842 offsetof(struct bpf_sock_addr, user_port)), 843 844 /* } */ 845 846 /* return 1 */ 847 BPF_MOV64_IMM(BPF_REG_0, 1), 848 BPF_EXIT_INSN(), 849 }; 850 851 return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn)); 852 } 853 854 static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test) 855 { 856 return sendmsg6_rw_dst_asm_prog_load(test, SERV6_REWRITE_IP); 857 } 858 859 static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test) 860 { 861 return load_path(test, RECVMSG6_PROG_PATH); 862 } 863 864 static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test) 865 { 866 return sendmsg6_rw_dst_asm_prog_load(test, SERV6_V4MAPPED_IP); 867 } 868 869 static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test) 870 { 871 return sendmsg6_rw_dst_asm_prog_load(test, WILDCARD6_IP); 872 } 873 874 static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test) 875 { 876 return load_path(test, SENDMSG6_PROG_PATH); 877 } 878 879 static int cmp_addr(const struct sockaddr_storage *addr1, 880 const struct sockaddr_storage *addr2, int cmp_port) 881 { 882 const struct sockaddr_in *four1, *four2; 883 const struct sockaddr_in6 *six1, *six2; 884 885 if (addr1->ss_family != addr2->ss_family) 886 return -1; 887 888 if (addr1->ss_family == AF_INET) { 889 four1 = (const struct sockaddr_in *)addr1; 890 four2 = (const struct sockaddr_in *)addr2; 891 return !((four1->sin_port == four2->sin_port || !cmp_port) && 892 four1->sin_addr.s_addr == four2->sin_addr.s_addr); 893 } else if (addr1->ss_family == AF_INET6) { 894 six1 = (const struct sockaddr_in6 *)addr1; 895 six2 = (const struct sockaddr_in6 *)addr2; 896 return !((six1->sin6_port == six2->sin6_port || !cmp_port) && 897 !memcmp(&six1->sin6_addr, &six2->sin6_addr, 898 sizeof(struct in6_addr))); 899 } 900 901 return -1; 902 } 903 904 static int cmp_sock_addr(info_fn fn, int sock1, 905 const struct sockaddr_storage *addr2, int cmp_port) 906 { 907 struct sockaddr_storage addr1; 908 socklen_t len1 = sizeof(addr1); 909 910 memset(&addr1, 0, len1); 911 if (fn(sock1, (struct sockaddr *)&addr1, (socklen_t *)&len1) != 0) 912 return -1; 913 914 return cmp_addr(&addr1, addr2, cmp_port); 915 } 916 917 static int cmp_local_ip(int sock1, const struct sockaddr_storage *addr2) 918 { 919 return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 0); 920 } 921 922 static int cmp_local_addr(int sock1, const struct sockaddr_storage *addr2) 923 { 924 return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 1); 925 } 926 927 static int cmp_peer_addr(int sock1, const struct sockaddr_storage *addr2) 928 { 929 return cmp_sock_addr(getpeername, sock1, addr2, /*cmp_port*/ 1); 930 } 931 932 static int start_server(int type, const struct sockaddr_storage *addr, 933 socklen_t addr_len) 934 { 935 int fd; 936 937 fd = socket(addr->ss_family, type, 0); 938 if (fd == -1) { 939 log_err("Failed to create server socket"); 940 goto out; 941 } 942 943 if (bind(fd, (const struct sockaddr *)addr, addr_len) == -1) { 944 log_err("Failed to bind server socket"); 945 goto close_out; 946 } 947 948 if (type == SOCK_STREAM) { 949 if (listen(fd, 128) == -1) { 950 log_err("Failed to listen on server socket"); 951 goto close_out; 952 } 953 } 954 955 goto out; 956 close_out: 957 close(fd); 958 fd = -1; 959 out: 960 return fd; 961 } 962 963 static int connect_to_server(int type, const struct sockaddr_storage *addr, 964 socklen_t addr_len) 965 { 966 int domain; 967 int fd = -1; 968 969 domain = addr->ss_family; 970 971 if (domain != AF_INET && domain != AF_INET6) { 972 log_err("Unsupported address family"); 973 goto err; 974 } 975 976 fd = socket(domain, type, 0); 977 if (fd == -1) { 978 log_err("Failed to create client socket"); 979 goto err; 980 } 981 982 if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) { 983 log_err("Fail to connect to server"); 984 goto err; 985 } 986 987 goto out; 988 err: 989 close(fd); 990 fd = -1; 991 out: 992 return fd; 993 } 994 995 int init_pktinfo(int domain, struct cmsghdr *cmsg) 996 { 997 struct in6_pktinfo *pktinfo6; 998 struct in_pktinfo *pktinfo4; 999 1000 if (domain == AF_INET) { 1001 cmsg->cmsg_level = SOL_IP; 1002 cmsg->cmsg_type = IP_PKTINFO; 1003 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 1004 pktinfo4 = (struct in_pktinfo *)CMSG_DATA(cmsg); 1005 memset(pktinfo4, 0, sizeof(struct in_pktinfo)); 1006 if (inet_pton(domain, SRC4_IP, 1007 (void *)&pktinfo4->ipi_spec_dst) != 1) 1008 return -1; 1009 } else if (domain == AF_INET6) { 1010 cmsg->cmsg_level = SOL_IPV6; 1011 cmsg->cmsg_type = IPV6_PKTINFO; 1012 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 1013 pktinfo6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); 1014 memset(pktinfo6, 0, sizeof(struct in6_pktinfo)); 1015 if (inet_pton(domain, SRC6_IP, 1016 (void *)&pktinfo6->ipi6_addr) != 1) 1017 return -1; 1018 } else { 1019 return -1; 1020 } 1021 1022 return 0; 1023 } 1024 1025 static int sendmsg_to_server(int type, const struct sockaddr_storage *addr, 1026 socklen_t addr_len, int set_cmsg, int flags, 1027 int *syscall_err) 1028 { 1029 union { 1030 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; 1031 struct cmsghdr align; 1032 } control6; 1033 union { 1034 char buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; 1035 struct cmsghdr align; 1036 } control4; 1037 struct msghdr hdr; 1038 struct iovec iov; 1039 char data = 'a'; 1040 int domain; 1041 int fd = -1; 1042 1043 domain = addr->ss_family; 1044 1045 if (domain != AF_INET && domain != AF_INET6) { 1046 log_err("Unsupported address family"); 1047 goto err; 1048 } 1049 1050 fd = socket(domain, type, 0); 1051 if (fd == -1) { 1052 log_err("Failed to create client socket"); 1053 goto err; 1054 } 1055 1056 memset(&iov, 0, sizeof(iov)); 1057 iov.iov_base = &data; 1058 iov.iov_len = sizeof(data); 1059 1060 memset(&hdr, 0, sizeof(hdr)); 1061 hdr.msg_name = (void *)addr; 1062 hdr.msg_namelen = addr_len; 1063 hdr.msg_iov = &iov; 1064 hdr.msg_iovlen = 1; 1065 1066 if (set_cmsg) { 1067 if (domain == AF_INET) { 1068 hdr.msg_control = &control4; 1069 hdr.msg_controllen = sizeof(control4.buf); 1070 } else if (domain == AF_INET6) { 1071 hdr.msg_control = &control6; 1072 hdr.msg_controllen = sizeof(control6.buf); 1073 } 1074 if (init_pktinfo(domain, CMSG_FIRSTHDR(&hdr))) { 1075 log_err("Fail to init pktinfo"); 1076 goto err; 1077 } 1078 } 1079 1080 if (sendmsg(fd, &hdr, flags) != sizeof(data)) { 1081 log_err("Fail to send message to server"); 1082 *syscall_err = errno; 1083 goto err; 1084 } 1085 1086 goto out; 1087 err: 1088 close(fd); 1089 fd = -1; 1090 out: 1091 return fd; 1092 } 1093 1094 static int fastconnect_to_server(const struct sockaddr_storage *addr, 1095 socklen_t addr_len) 1096 { 1097 int sendmsg_err; 1098 1099 return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0, 1100 MSG_FASTOPEN, &sendmsg_err); 1101 } 1102 1103 static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr) 1104 { 1105 struct timeval tv; 1106 struct msghdr hdr; 1107 struct iovec iov; 1108 char data[64]; 1109 fd_set rfds; 1110 1111 FD_ZERO(&rfds); 1112 FD_SET(sockfd, &rfds); 1113 1114 tv.tv_sec = 2; 1115 tv.tv_usec = 0; 1116 1117 if (select(sockfd + 1, &rfds, NULL, NULL, &tv) <= 0 || 1118 !FD_ISSET(sockfd, &rfds)) 1119 return -1; 1120 1121 memset(&iov, 0, sizeof(iov)); 1122 iov.iov_base = data; 1123 iov.iov_len = sizeof(data); 1124 1125 memset(&hdr, 0, sizeof(hdr)); 1126 hdr.msg_name = src_addr; 1127 hdr.msg_namelen = sizeof(struct sockaddr_storage); 1128 hdr.msg_iov = &iov; 1129 hdr.msg_iovlen = 1; 1130 1131 return recvmsg(sockfd, &hdr, 0); 1132 } 1133 1134 static int init_addrs(const struct sock_addr_test *test, 1135 struct sockaddr_storage *requested_addr, 1136 struct sockaddr_storage *expected_addr, 1137 struct sockaddr_storage *expected_src_addr) 1138 { 1139 socklen_t addr_len = sizeof(struct sockaddr_storage); 1140 1141 if (mk_sockaddr(test->domain, test->expected_ip, test->expected_port, 1142 (struct sockaddr *)expected_addr, addr_len) == -1) 1143 goto err; 1144 1145 if (mk_sockaddr(test->domain, test->requested_ip, test->requested_port, 1146 (struct sockaddr *)requested_addr, addr_len) == -1) 1147 goto err; 1148 1149 if (test->expected_src_ip && 1150 mk_sockaddr(test->domain, test->expected_src_ip, 0, 1151 (struct sockaddr *)expected_src_addr, addr_len) == -1) 1152 goto err; 1153 1154 return 0; 1155 err: 1156 return -1; 1157 } 1158 1159 static int run_bind_test_case(const struct sock_addr_test *test) 1160 { 1161 socklen_t addr_len = sizeof(struct sockaddr_storage); 1162 struct sockaddr_storage requested_addr; 1163 struct sockaddr_storage expected_addr; 1164 int clientfd = -1; 1165 int servfd = -1; 1166 int err = 0; 1167 1168 if (init_addrs(test, &requested_addr, &expected_addr, NULL)) 1169 goto err; 1170 1171 servfd = start_server(test->type, &requested_addr, addr_len); 1172 if (servfd == -1) 1173 goto err; 1174 1175 if (cmp_local_addr(servfd, &expected_addr)) 1176 goto err; 1177 1178 /* Try to connect to server just in case */ 1179 clientfd = connect_to_server(test->type, &expected_addr, addr_len); 1180 if (clientfd == -1) 1181 goto err; 1182 1183 goto out; 1184 err: 1185 err = -1; 1186 out: 1187 close(clientfd); 1188 close(servfd); 1189 return err; 1190 } 1191 1192 static int run_connect_test_case(const struct sock_addr_test *test) 1193 { 1194 socklen_t addr_len = sizeof(struct sockaddr_storage); 1195 struct sockaddr_storage expected_src_addr; 1196 struct sockaddr_storage requested_addr; 1197 struct sockaddr_storage expected_addr; 1198 int clientfd = -1; 1199 int servfd = -1; 1200 int err = 0; 1201 1202 if (init_addrs(test, &requested_addr, &expected_addr, 1203 &expected_src_addr)) 1204 goto err; 1205 1206 /* Prepare server to connect to */ 1207 servfd = start_server(test->type, &expected_addr, addr_len); 1208 if (servfd == -1) 1209 goto err; 1210 1211 clientfd = connect_to_server(test->type, &requested_addr, addr_len); 1212 if (clientfd == -1) 1213 goto err; 1214 1215 /* Make sure src and dst addrs were overridden properly */ 1216 if (cmp_peer_addr(clientfd, &expected_addr)) 1217 goto err; 1218 1219 if (cmp_local_ip(clientfd, &expected_src_addr)) 1220 goto err; 1221 1222 if (test->type == SOCK_STREAM) { 1223 /* Test TCP Fast Open scenario */ 1224 clientfd = fastconnect_to_server(&requested_addr, addr_len); 1225 if (clientfd == -1) 1226 goto err; 1227 1228 /* Make sure src and dst addrs were overridden properly */ 1229 if (cmp_peer_addr(clientfd, &expected_addr)) 1230 goto err; 1231 1232 if (cmp_local_ip(clientfd, &expected_src_addr)) 1233 goto err; 1234 } 1235 1236 goto out; 1237 err: 1238 err = -1; 1239 out: 1240 close(clientfd); 1241 close(servfd); 1242 return err; 1243 } 1244 1245 static int run_xmsg_test_case(const struct sock_addr_test *test, int max_cmsg) 1246 { 1247 socklen_t addr_len = sizeof(struct sockaddr_storage); 1248 struct sockaddr_storage expected_addr; 1249 struct sockaddr_storage server_addr; 1250 struct sockaddr_storage sendmsg_addr; 1251 struct sockaddr_storage recvmsg_addr; 1252 int clientfd = -1; 1253 int servfd = -1; 1254 int set_cmsg; 1255 int err = 0; 1256 1257 if (test->type != SOCK_DGRAM) 1258 goto err; 1259 1260 if (init_addrs(test, &sendmsg_addr, &server_addr, &expected_addr)) 1261 goto err; 1262 1263 /* Prepare server to sendmsg to */ 1264 servfd = start_server(test->type, &server_addr, addr_len); 1265 if (servfd == -1) 1266 goto err; 1267 1268 for (set_cmsg = 0; set_cmsg <= max_cmsg; ++set_cmsg) { 1269 if (clientfd >= 0) 1270 close(clientfd); 1271 1272 clientfd = sendmsg_to_server(test->type, &sendmsg_addr, 1273 addr_len, set_cmsg, /*flags*/0, 1274 &err); 1275 if (err) 1276 goto out; 1277 else if (clientfd == -1) 1278 goto err; 1279 1280 /* Try to receive message on server instead of using 1281 * getpeername(2) on client socket, to check that client's 1282 * destination address was rewritten properly, since 1283 * getpeername(2) doesn't work with unconnected datagram 1284 * sockets. 1285 * 1286 * Get source address from recvmsg(2) as well to make sure 1287 * source was rewritten properly: getsockname(2) can't be used 1288 * since socket is unconnected and source defined for one 1289 * specific packet may differ from the one used by default and 1290 * returned by getsockname(2). 1291 */ 1292 if (recvmsg_from_client(servfd, &recvmsg_addr) == -1) 1293 goto err; 1294 1295 if (cmp_addr(&recvmsg_addr, &expected_addr, /*cmp_port*/0)) 1296 goto err; 1297 } 1298 1299 goto out; 1300 err: 1301 err = -1; 1302 out: 1303 close(clientfd); 1304 close(servfd); 1305 return err; 1306 } 1307 1308 static int run_test_case(int cgfd, const struct sock_addr_test *test) 1309 { 1310 int progfd = -1; 1311 int err = 0; 1312 1313 printf("Test case: %s .. ", test->descr); 1314 1315 progfd = test->loadfn(test); 1316 if (test->expected_result == LOAD_REJECT && progfd < 0) 1317 goto out; 1318 else if (test->expected_result == LOAD_REJECT || progfd < 0) 1319 goto err; 1320 1321 err = bpf_prog_attach(progfd, cgfd, test->attach_type, 1322 BPF_F_ALLOW_OVERRIDE); 1323 if (test->expected_result == ATTACH_REJECT && err) { 1324 err = 0; /* error was expected, reset it */ 1325 goto out; 1326 } else if (test->expected_result == ATTACH_REJECT || err) { 1327 goto err; 1328 } else if (test->expected_result == ATTACH_OKAY) { 1329 err = 0; 1330 goto out; 1331 } 1332 1333 switch (test->attach_type) { 1334 case BPF_CGROUP_INET4_BIND: 1335 case BPF_CGROUP_INET6_BIND: 1336 err = run_bind_test_case(test); 1337 break; 1338 case BPF_CGROUP_INET4_CONNECT: 1339 case BPF_CGROUP_INET6_CONNECT: 1340 err = run_connect_test_case(test); 1341 break; 1342 case BPF_CGROUP_UDP4_SENDMSG: 1343 case BPF_CGROUP_UDP6_SENDMSG: 1344 err = run_xmsg_test_case(test, 1); 1345 break; 1346 case BPF_CGROUP_UDP4_RECVMSG: 1347 case BPF_CGROUP_UDP6_RECVMSG: 1348 err = run_xmsg_test_case(test, 0); 1349 break; 1350 default: 1351 goto err; 1352 } 1353 1354 if (test->expected_result == SYSCALL_EPERM && err == EPERM) { 1355 err = 0; /* error was expected, reset it */ 1356 goto out; 1357 } 1358 1359 if (test->expected_result == SYSCALL_ENOTSUPP && err == ENOTSUPP) { 1360 err = 0; /* error was expected, reset it */ 1361 goto out; 1362 } 1363 1364 if (err || test->expected_result != SUCCESS) 1365 goto err; 1366 1367 goto out; 1368 err: 1369 err = -1; 1370 out: 1371 /* Detaching w/o checking return code: best effort attempt. */ 1372 if (progfd != -1) 1373 bpf_prog_detach(cgfd, test->attach_type); 1374 close(progfd); 1375 printf("[%s]\n", err ? "FAIL" : "PASS"); 1376 return err; 1377 } 1378 1379 static int run_tests(int cgfd) 1380 { 1381 int passes = 0; 1382 int fails = 0; 1383 int i; 1384 1385 for (i = 0; i < ARRAY_SIZE(tests); ++i) { 1386 if (run_test_case(cgfd, &tests[i])) 1387 ++fails; 1388 else 1389 ++passes; 1390 } 1391 printf("Summary: %d PASSED, %d FAILED\n", passes, fails); 1392 return fails ? -1 : 0; 1393 } 1394 1395 int main(int argc, char **argv) 1396 { 1397 int cgfd = -1; 1398 int err = 0; 1399 1400 if (argc < 2) { 1401 fprintf(stderr, 1402 "%s has to be run via %s.sh. Skip direct run.\n", 1403 argv[0], argv[0]); 1404 exit(err); 1405 } 1406 1407 cgfd = cgroup_setup_and_join(CG_PATH); 1408 if (cgfd < 0) 1409 goto err; 1410 1411 if (run_tests(cgfd)) 1412 goto err; 1413 1414 goto out; 1415 err: 1416 err = -1; 1417 out: 1418 close(cgfd); 1419 cleanup_cgroup_environment(); 1420 return err; 1421 } 1422