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