18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2018 Facebook 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <stdio.h> 58c2ecf20Sopenharmony_ci#include <unistd.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <arpa/inet.h> 88c2ecf20Sopenharmony_ci#include <sys/types.h> 98c2ecf20Sopenharmony_ci#include <sys/socket.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/filter.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <bpf/bpf.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "cgroup_helpers.h" 168c2ecf20Sopenharmony_ci#include <bpf/bpf_endian.h> 178c2ecf20Sopenharmony_ci#include "bpf_rlimit.h" 188c2ecf20Sopenharmony_ci#include "bpf_util.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define CG_PATH "/foo" 218c2ecf20Sopenharmony_ci#define MAX_INSNS 512 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cichar bpf_log_buf[BPF_LOG_BUF_SIZE]; 248c2ecf20Sopenharmony_cistatic bool verbose = false; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct sock_test { 278c2ecf20Sopenharmony_ci const char *descr; 288c2ecf20Sopenharmony_ci /* BPF prog properties */ 298c2ecf20Sopenharmony_ci struct bpf_insn insns[MAX_INSNS]; 308c2ecf20Sopenharmony_ci enum bpf_attach_type expected_attach_type; 318c2ecf20Sopenharmony_ci enum bpf_attach_type attach_type; 328c2ecf20Sopenharmony_ci /* Socket properties */ 338c2ecf20Sopenharmony_ci int domain; 348c2ecf20Sopenharmony_ci int type; 358c2ecf20Sopenharmony_ci /* Endpoint to bind() to */ 368c2ecf20Sopenharmony_ci const char *ip; 378c2ecf20Sopenharmony_ci unsigned short port; 388c2ecf20Sopenharmony_ci /* Expected test result */ 398c2ecf20Sopenharmony_ci enum { 408c2ecf20Sopenharmony_ci LOAD_REJECT, 418c2ecf20Sopenharmony_ci ATTACH_REJECT, 428c2ecf20Sopenharmony_ci BIND_REJECT, 438c2ecf20Sopenharmony_ci SUCCESS, 448c2ecf20Sopenharmony_ci } result; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic struct sock_test tests[] = { 488c2ecf20Sopenharmony_ci { 498c2ecf20Sopenharmony_ci "bind4 load with invalid access: src_ip6", 508c2ecf20Sopenharmony_ci .insns = { 518c2ecf20Sopenharmony_ci BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 528c2ecf20Sopenharmony_ci BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 538c2ecf20Sopenharmony_ci offsetof(struct bpf_sock, src_ip6[0])), 548c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 558c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 568c2ecf20Sopenharmony_ci }, 578c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 588c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 598c2ecf20Sopenharmony_ci 0, 608c2ecf20Sopenharmony_ci 0, 618c2ecf20Sopenharmony_ci NULL, 628c2ecf20Sopenharmony_ci 0, 638c2ecf20Sopenharmony_ci LOAD_REJECT, 648c2ecf20Sopenharmony_ci }, 658c2ecf20Sopenharmony_ci { 668c2ecf20Sopenharmony_ci "bind4 load with invalid access: mark", 678c2ecf20Sopenharmony_ci .insns = { 688c2ecf20Sopenharmony_ci BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 698c2ecf20Sopenharmony_ci BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 708c2ecf20Sopenharmony_ci offsetof(struct bpf_sock, mark)), 718c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 728c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 738c2ecf20Sopenharmony_ci }, 748c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 758c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 768c2ecf20Sopenharmony_ci 0, 778c2ecf20Sopenharmony_ci 0, 788c2ecf20Sopenharmony_ci NULL, 798c2ecf20Sopenharmony_ci 0, 808c2ecf20Sopenharmony_ci LOAD_REJECT, 818c2ecf20Sopenharmony_ci }, 828c2ecf20Sopenharmony_ci { 838c2ecf20Sopenharmony_ci "bind6 load with invalid access: src_ip4", 848c2ecf20Sopenharmony_ci .insns = { 858c2ecf20Sopenharmony_ci BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 868c2ecf20Sopenharmony_ci BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 878c2ecf20Sopenharmony_ci offsetof(struct bpf_sock, src_ip4)), 888c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 898c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 908c2ecf20Sopenharmony_ci }, 918c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 928c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 938c2ecf20Sopenharmony_ci 0, 948c2ecf20Sopenharmony_ci 0, 958c2ecf20Sopenharmony_ci NULL, 968c2ecf20Sopenharmony_ci 0, 978c2ecf20Sopenharmony_ci LOAD_REJECT, 988c2ecf20Sopenharmony_ci }, 998c2ecf20Sopenharmony_ci { 1008c2ecf20Sopenharmony_ci "sock_create load with invalid access: src_port", 1018c2ecf20Sopenharmony_ci .insns = { 1028c2ecf20Sopenharmony_ci BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 1038c2ecf20Sopenharmony_ci BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 1048c2ecf20Sopenharmony_ci offsetof(struct bpf_sock, src_port)), 1058c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 1068c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 1078c2ecf20Sopenharmony_ci }, 1088c2ecf20Sopenharmony_ci BPF_CGROUP_INET_SOCK_CREATE, 1098c2ecf20Sopenharmony_ci BPF_CGROUP_INET_SOCK_CREATE, 1108c2ecf20Sopenharmony_ci 0, 1118c2ecf20Sopenharmony_ci 0, 1128c2ecf20Sopenharmony_ci NULL, 1138c2ecf20Sopenharmony_ci 0, 1148c2ecf20Sopenharmony_ci LOAD_REJECT, 1158c2ecf20Sopenharmony_ci }, 1168c2ecf20Sopenharmony_ci { 1178c2ecf20Sopenharmony_ci "sock_create load w/o expected_attach_type (compat mode)", 1188c2ecf20Sopenharmony_ci .insns = { 1198c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 1208c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci 0, 1238c2ecf20Sopenharmony_ci BPF_CGROUP_INET_SOCK_CREATE, 1248c2ecf20Sopenharmony_ci AF_INET, 1258c2ecf20Sopenharmony_ci SOCK_STREAM, 1268c2ecf20Sopenharmony_ci "127.0.0.1", 1278c2ecf20Sopenharmony_ci 8097, 1288c2ecf20Sopenharmony_ci SUCCESS, 1298c2ecf20Sopenharmony_ci }, 1308c2ecf20Sopenharmony_ci { 1318c2ecf20Sopenharmony_ci "sock_create load w/ expected_attach_type", 1328c2ecf20Sopenharmony_ci .insns = { 1338c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 1348c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 1358c2ecf20Sopenharmony_ci }, 1368c2ecf20Sopenharmony_ci BPF_CGROUP_INET_SOCK_CREATE, 1378c2ecf20Sopenharmony_ci BPF_CGROUP_INET_SOCK_CREATE, 1388c2ecf20Sopenharmony_ci AF_INET, 1398c2ecf20Sopenharmony_ci SOCK_STREAM, 1408c2ecf20Sopenharmony_ci "127.0.0.1", 1418c2ecf20Sopenharmony_ci 8097, 1428c2ecf20Sopenharmony_ci SUCCESS, 1438c2ecf20Sopenharmony_ci }, 1448c2ecf20Sopenharmony_ci { 1458c2ecf20Sopenharmony_ci "attach type mismatch bind4 vs bind6", 1468c2ecf20Sopenharmony_ci .insns = { 1478c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 1488c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 1498c2ecf20Sopenharmony_ci }, 1508c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 1518c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 1528c2ecf20Sopenharmony_ci 0, 1538c2ecf20Sopenharmony_ci 0, 1548c2ecf20Sopenharmony_ci NULL, 1558c2ecf20Sopenharmony_ci 0, 1568c2ecf20Sopenharmony_ci ATTACH_REJECT, 1578c2ecf20Sopenharmony_ci }, 1588c2ecf20Sopenharmony_ci { 1598c2ecf20Sopenharmony_ci "attach type mismatch bind6 vs bind4", 1608c2ecf20Sopenharmony_ci .insns = { 1618c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 1628c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 1638c2ecf20Sopenharmony_ci }, 1648c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 1658c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 1668c2ecf20Sopenharmony_ci 0, 1678c2ecf20Sopenharmony_ci 0, 1688c2ecf20Sopenharmony_ci NULL, 1698c2ecf20Sopenharmony_ci 0, 1708c2ecf20Sopenharmony_ci ATTACH_REJECT, 1718c2ecf20Sopenharmony_ci }, 1728c2ecf20Sopenharmony_ci { 1738c2ecf20Sopenharmony_ci "attach type mismatch default vs bind4", 1748c2ecf20Sopenharmony_ci .insns = { 1758c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 1768c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 1778c2ecf20Sopenharmony_ci }, 1788c2ecf20Sopenharmony_ci 0, 1798c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 1808c2ecf20Sopenharmony_ci 0, 1818c2ecf20Sopenharmony_ci 0, 1828c2ecf20Sopenharmony_ci NULL, 1838c2ecf20Sopenharmony_ci 0, 1848c2ecf20Sopenharmony_ci ATTACH_REJECT, 1858c2ecf20Sopenharmony_ci }, 1868c2ecf20Sopenharmony_ci { 1878c2ecf20Sopenharmony_ci "attach type mismatch bind6 vs sock_create", 1888c2ecf20Sopenharmony_ci .insns = { 1898c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 1908c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 1918c2ecf20Sopenharmony_ci }, 1928c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 1938c2ecf20Sopenharmony_ci BPF_CGROUP_INET_SOCK_CREATE, 1948c2ecf20Sopenharmony_ci 0, 1958c2ecf20Sopenharmony_ci 0, 1968c2ecf20Sopenharmony_ci NULL, 1978c2ecf20Sopenharmony_ci 0, 1988c2ecf20Sopenharmony_ci ATTACH_REJECT, 1998c2ecf20Sopenharmony_ci }, 2008c2ecf20Sopenharmony_ci { 2018c2ecf20Sopenharmony_ci "bind4 reject all", 2028c2ecf20Sopenharmony_ci .insns = { 2038c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 0), 2048c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 2058c2ecf20Sopenharmony_ci }, 2068c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 2078c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 2088c2ecf20Sopenharmony_ci AF_INET, 2098c2ecf20Sopenharmony_ci SOCK_STREAM, 2108c2ecf20Sopenharmony_ci "0.0.0.0", 2118c2ecf20Sopenharmony_ci 0, 2128c2ecf20Sopenharmony_ci BIND_REJECT, 2138c2ecf20Sopenharmony_ci }, 2148c2ecf20Sopenharmony_ci { 2158c2ecf20Sopenharmony_ci "bind6 reject all", 2168c2ecf20Sopenharmony_ci .insns = { 2178c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 0), 2188c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 2198c2ecf20Sopenharmony_ci }, 2208c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 2218c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 2228c2ecf20Sopenharmony_ci AF_INET6, 2238c2ecf20Sopenharmony_ci SOCK_STREAM, 2248c2ecf20Sopenharmony_ci "::", 2258c2ecf20Sopenharmony_ci 0, 2268c2ecf20Sopenharmony_ci BIND_REJECT, 2278c2ecf20Sopenharmony_ci }, 2288c2ecf20Sopenharmony_ci { 2298c2ecf20Sopenharmony_ci "bind6 deny specific IP & port", 2308c2ecf20Sopenharmony_ci .insns = { 2318c2ecf20Sopenharmony_ci BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* if (ip == expected && port == expected) */ 2348c2ecf20Sopenharmony_ci BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 2358c2ecf20Sopenharmony_ci offsetof(struct bpf_sock, src_ip6[3])), 2368c2ecf20Sopenharmony_ci BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 2378c2ecf20Sopenharmony_ci __bpf_constant_ntohl(0x00000001), 4), 2388c2ecf20Sopenharmony_ci BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 2398c2ecf20Sopenharmony_ci offsetof(struct bpf_sock, src_port)), 2408c2ecf20Sopenharmony_ci BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2), 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* return DENY; */ 2438c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 0), 2448c2ecf20Sopenharmony_ci BPF_JMP_A(1), 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* else return ALLOW; */ 2478c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 2488c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 2498c2ecf20Sopenharmony_ci }, 2508c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 2518c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 2528c2ecf20Sopenharmony_ci AF_INET6, 2538c2ecf20Sopenharmony_ci SOCK_STREAM, 2548c2ecf20Sopenharmony_ci "::1", 2558c2ecf20Sopenharmony_ci 8193, 2568c2ecf20Sopenharmony_ci BIND_REJECT, 2578c2ecf20Sopenharmony_ci }, 2588c2ecf20Sopenharmony_ci { 2598c2ecf20Sopenharmony_ci "bind4 allow specific IP & port", 2608c2ecf20Sopenharmony_ci .insns = { 2618c2ecf20Sopenharmony_ci BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* if (ip == expected && port == expected) */ 2648c2ecf20Sopenharmony_ci BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 2658c2ecf20Sopenharmony_ci offsetof(struct bpf_sock, src_ip4)), 2668c2ecf20Sopenharmony_ci BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 2678c2ecf20Sopenharmony_ci __bpf_constant_ntohl(0x7F000001), 4), 2688c2ecf20Sopenharmony_ci BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 2698c2ecf20Sopenharmony_ci offsetof(struct bpf_sock, src_port)), 2708c2ecf20Sopenharmony_ci BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2), 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* return ALLOW; */ 2738c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 2748c2ecf20Sopenharmony_ci BPF_JMP_A(1), 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* else return DENY; */ 2778c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 0), 2788c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 2798c2ecf20Sopenharmony_ci }, 2808c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 2818c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 2828c2ecf20Sopenharmony_ci AF_INET, 2838c2ecf20Sopenharmony_ci SOCK_STREAM, 2848c2ecf20Sopenharmony_ci "127.0.0.1", 2858c2ecf20Sopenharmony_ci 4098, 2868c2ecf20Sopenharmony_ci SUCCESS, 2878c2ecf20Sopenharmony_ci }, 2888c2ecf20Sopenharmony_ci { 2898c2ecf20Sopenharmony_ci "bind4 allow all", 2908c2ecf20Sopenharmony_ci .insns = { 2918c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 2928c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 2938c2ecf20Sopenharmony_ci }, 2948c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 2958c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_POST_BIND, 2968c2ecf20Sopenharmony_ci AF_INET, 2978c2ecf20Sopenharmony_ci SOCK_STREAM, 2988c2ecf20Sopenharmony_ci "0.0.0.0", 2998c2ecf20Sopenharmony_ci 0, 3008c2ecf20Sopenharmony_ci SUCCESS, 3018c2ecf20Sopenharmony_ci }, 3028c2ecf20Sopenharmony_ci { 3038c2ecf20Sopenharmony_ci "bind6 allow all", 3048c2ecf20Sopenharmony_ci .insns = { 3058c2ecf20Sopenharmony_ci BPF_MOV64_IMM(BPF_REG_0, 1), 3068c2ecf20Sopenharmony_ci BPF_EXIT_INSN(), 3078c2ecf20Sopenharmony_ci }, 3088c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 3098c2ecf20Sopenharmony_ci BPF_CGROUP_INET6_POST_BIND, 3108c2ecf20Sopenharmony_ci AF_INET6, 3118c2ecf20Sopenharmony_ci SOCK_STREAM, 3128c2ecf20Sopenharmony_ci "::", 3138c2ecf20Sopenharmony_ci 0, 3148c2ecf20Sopenharmony_ci SUCCESS, 3158c2ecf20Sopenharmony_ci }, 3168c2ecf20Sopenharmony_ci}; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic size_t probe_prog_length(const struct bpf_insn *fp) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci size_t len; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci for (len = MAX_INSNS - 1; len > 0; --len) 3238c2ecf20Sopenharmony_ci if (fp[len].code != 0 || fp[len].imm != 0) 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci return len + 1; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic int load_sock_prog(const struct bpf_insn *prog, 3298c2ecf20Sopenharmony_ci enum bpf_attach_type attach_type) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct bpf_load_program_attr attr; 3328c2ecf20Sopenharmony_ci int ret; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci memset(&attr, 0, sizeof(struct bpf_load_program_attr)); 3358c2ecf20Sopenharmony_ci attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK; 3368c2ecf20Sopenharmony_ci attr.expected_attach_type = attach_type; 3378c2ecf20Sopenharmony_ci attr.insns = prog; 3388c2ecf20Sopenharmony_ci attr.insns_cnt = probe_prog_length(attr.insns); 3398c2ecf20Sopenharmony_ci attr.license = "GPL"; 3408c2ecf20Sopenharmony_ci attr.log_level = 2; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci ret = bpf_load_program_xattr(&attr, bpf_log_buf, BPF_LOG_BUF_SIZE); 3438c2ecf20Sopenharmony_ci if (verbose && ret < 0) 3448c2ecf20Sopenharmony_ci fprintf(stderr, "%s\n", bpf_log_buf); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return ret; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int attach_sock_prog(int cgfd, int progfd, 3508c2ecf20Sopenharmony_ci enum bpf_attach_type attach_type) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci return bpf_prog_attach(progfd, cgfd, attach_type, BPF_F_ALLOW_OVERRIDE); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int bind_sock(int domain, int type, const char *ip, unsigned short port) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct sockaddr_storage addr; 3588c2ecf20Sopenharmony_ci struct sockaddr_in6 *addr6; 3598c2ecf20Sopenharmony_ci struct sockaddr_in *addr4; 3608c2ecf20Sopenharmony_ci int sockfd = -1; 3618c2ecf20Sopenharmony_ci socklen_t len; 3628c2ecf20Sopenharmony_ci int err = 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci sockfd = socket(domain, type, 0); 3658c2ecf20Sopenharmony_ci if (sockfd < 0) 3668c2ecf20Sopenharmony_ci goto err; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci memset(&addr, 0, sizeof(addr)); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (domain == AF_INET) { 3718c2ecf20Sopenharmony_ci len = sizeof(struct sockaddr_in); 3728c2ecf20Sopenharmony_ci addr4 = (struct sockaddr_in *)&addr; 3738c2ecf20Sopenharmony_ci addr4->sin_family = domain; 3748c2ecf20Sopenharmony_ci addr4->sin_port = htons(port); 3758c2ecf20Sopenharmony_ci if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) 3768c2ecf20Sopenharmony_ci goto err; 3778c2ecf20Sopenharmony_ci } else if (domain == AF_INET6) { 3788c2ecf20Sopenharmony_ci len = sizeof(struct sockaddr_in6); 3798c2ecf20Sopenharmony_ci addr6 = (struct sockaddr_in6 *)&addr; 3808c2ecf20Sopenharmony_ci addr6->sin6_family = domain; 3818c2ecf20Sopenharmony_ci addr6->sin6_port = htons(port); 3828c2ecf20Sopenharmony_ci if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) 3838c2ecf20Sopenharmony_ci goto err; 3848c2ecf20Sopenharmony_ci } else { 3858c2ecf20Sopenharmony_ci goto err; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) 3898c2ecf20Sopenharmony_ci goto err; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci goto out; 3928c2ecf20Sopenharmony_cierr: 3938c2ecf20Sopenharmony_ci err = -1; 3948c2ecf20Sopenharmony_ciout: 3958c2ecf20Sopenharmony_ci close(sockfd); 3968c2ecf20Sopenharmony_ci return err; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic int run_test_case(int cgfd, const struct sock_test *test) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci int progfd = -1; 4028c2ecf20Sopenharmony_ci int err = 0; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci printf("Test case: %s .. ", test->descr); 4058c2ecf20Sopenharmony_ci progfd = load_sock_prog(test->insns, test->expected_attach_type); 4068c2ecf20Sopenharmony_ci if (progfd < 0) { 4078c2ecf20Sopenharmony_ci if (test->result == LOAD_REJECT) 4088c2ecf20Sopenharmony_ci goto out; 4098c2ecf20Sopenharmony_ci else 4108c2ecf20Sopenharmony_ci goto err; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (attach_sock_prog(cgfd, progfd, test->attach_type) == -1) { 4148c2ecf20Sopenharmony_ci if (test->result == ATTACH_REJECT) 4158c2ecf20Sopenharmony_ci goto out; 4168c2ecf20Sopenharmony_ci else 4178c2ecf20Sopenharmony_ci goto err; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (bind_sock(test->domain, test->type, test->ip, test->port) == -1) { 4218c2ecf20Sopenharmony_ci /* sys_bind() may fail for different reasons, errno has to be 4228c2ecf20Sopenharmony_ci * checked to confirm that BPF program rejected it. 4238c2ecf20Sopenharmony_ci */ 4248c2ecf20Sopenharmony_ci if (test->result == BIND_REJECT && errno == EPERM) 4258c2ecf20Sopenharmony_ci goto out; 4268c2ecf20Sopenharmony_ci else 4278c2ecf20Sopenharmony_ci goto err; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (test->result != SUCCESS) 4328c2ecf20Sopenharmony_ci goto err; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci goto out; 4358c2ecf20Sopenharmony_cierr: 4368c2ecf20Sopenharmony_ci err = -1; 4378c2ecf20Sopenharmony_ciout: 4388c2ecf20Sopenharmony_ci /* Detaching w/o checking return code: best effort attempt. */ 4398c2ecf20Sopenharmony_ci if (progfd != -1) 4408c2ecf20Sopenharmony_ci bpf_prog_detach(cgfd, test->attach_type); 4418c2ecf20Sopenharmony_ci close(progfd); 4428c2ecf20Sopenharmony_ci printf("[%s]\n", err ? "FAIL" : "PASS"); 4438c2ecf20Sopenharmony_ci return err; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int run_tests(int cgfd) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int passes = 0; 4498c2ecf20Sopenharmony_ci int fails = 0; 4508c2ecf20Sopenharmony_ci int i; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tests); ++i) { 4538c2ecf20Sopenharmony_ci if (run_test_case(cgfd, &tests[i])) 4548c2ecf20Sopenharmony_ci ++fails; 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci ++passes; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci printf("Summary: %d PASSED, %d FAILED\n", passes, fails); 4598c2ecf20Sopenharmony_ci return fails ? -1 : 0; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ciint main(int argc, char **argv) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci int cgfd = -1; 4658c2ecf20Sopenharmony_ci int err = 0; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci cgfd = cgroup_setup_and_join(CG_PATH); 4688c2ecf20Sopenharmony_ci if (cgfd < 0) 4698c2ecf20Sopenharmony_ci goto err; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (run_tests(cgfd)) 4728c2ecf20Sopenharmony_ci goto err; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci goto out; 4758c2ecf20Sopenharmony_cierr: 4768c2ecf20Sopenharmony_ci err = -1; 4778c2ecf20Sopenharmony_ciout: 4788c2ecf20Sopenharmony_ci close(cgfd); 4798c2ecf20Sopenharmony_ci cleanup_cgroup_environment(); 4808c2ecf20Sopenharmony_ci return err; 4818c2ecf20Sopenharmony_ci} 482