1*94682d6aSJordan Rife // SPDX-License-Identifier: GPL-2.0 2*94682d6aSJordan Rife #include <linux/bpf.h> 3*94682d6aSJordan Rife #include <test_progs.h> 4*94682d6aSJordan Rife #include "cgroup_helpers.h" 5*94682d6aSJordan Rife 6*94682d6aSJordan Rife #define TEST_NS "sock_post_bind" 7*94682d6aSJordan Rife 8*94682d6aSJordan Rife static char bpf_log_buf[4096]; 9*94682d6aSJordan Rife 10*94682d6aSJordan Rife static struct sock_post_bind_test { 11*94682d6aSJordan Rife const char *descr; 12*94682d6aSJordan Rife /* BPF prog properties */ 13*94682d6aSJordan Rife const struct bpf_insn insns[64]; 14*94682d6aSJordan Rife enum bpf_attach_type attach_type; 15*94682d6aSJordan Rife enum bpf_attach_type expected_attach_type; 16*94682d6aSJordan Rife /* Socket properties */ 17*94682d6aSJordan Rife int domain; 18*94682d6aSJordan Rife int type; 19*94682d6aSJordan Rife /* Endpoint to bind() to */ 20*94682d6aSJordan Rife const char *ip; 21*94682d6aSJordan Rife unsigned short port; 22*94682d6aSJordan Rife unsigned short port_retry; 23*94682d6aSJordan Rife 24*94682d6aSJordan Rife /* Expected test result */ 25*94682d6aSJordan Rife enum { 26*94682d6aSJordan Rife ATTACH_REJECT, 27*94682d6aSJordan Rife BIND_REJECT, 28*94682d6aSJordan Rife SUCCESS, 29*94682d6aSJordan Rife RETRY_SUCCESS, 30*94682d6aSJordan Rife RETRY_REJECT 31*94682d6aSJordan Rife } result; 32*94682d6aSJordan Rife } tests[] = { 33*94682d6aSJordan Rife { 34*94682d6aSJordan Rife .descr = "attach type mismatch bind4 vs bind6", 35*94682d6aSJordan Rife .insns = { 36*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 37*94682d6aSJordan Rife BPF_EXIT_INSN(), 38*94682d6aSJordan Rife }, 39*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET4_POST_BIND, 40*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET6_POST_BIND, 41*94682d6aSJordan Rife .result = ATTACH_REJECT, 42*94682d6aSJordan Rife }, 43*94682d6aSJordan Rife { 44*94682d6aSJordan Rife .descr = "attach type mismatch bind6 vs bind4", 45*94682d6aSJordan Rife .insns = { 46*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 47*94682d6aSJordan Rife BPF_EXIT_INSN(), 48*94682d6aSJordan Rife }, 49*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET6_POST_BIND, 50*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET4_POST_BIND, 51*94682d6aSJordan Rife .result = ATTACH_REJECT, 52*94682d6aSJordan Rife }, 53*94682d6aSJordan Rife { 54*94682d6aSJordan Rife .descr = "attach type mismatch default vs bind4", 55*94682d6aSJordan Rife .insns = { 56*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 57*94682d6aSJordan Rife BPF_EXIT_INSN(), 58*94682d6aSJordan Rife }, 59*94682d6aSJordan Rife .expected_attach_type = 0, 60*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET4_POST_BIND, 61*94682d6aSJordan Rife .result = ATTACH_REJECT, 62*94682d6aSJordan Rife }, 63*94682d6aSJordan Rife { 64*94682d6aSJordan Rife .descr = "attach type mismatch bind6 vs sock_create", 65*94682d6aSJordan Rife .insns = { 66*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 67*94682d6aSJordan Rife BPF_EXIT_INSN(), 68*94682d6aSJordan Rife }, 69*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET6_POST_BIND, 70*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET_SOCK_CREATE, 71*94682d6aSJordan Rife .result = ATTACH_REJECT, 72*94682d6aSJordan Rife }, 73*94682d6aSJordan Rife { 74*94682d6aSJordan Rife .descr = "bind4 reject all", 75*94682d6aSJordan Rife .insns = { 76*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 0), 77*94682d6aSJordan Rife BPF_EXIT_INSN(), 78*94682d6aSJordan Rife }, 79*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET4_POST_BIND, 80*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET4_POST_BIND, 81*94682d6aSJordan Rife .domain = AF_INET, 82*94682d6aSJordan Rife .type = SOCK_STREAM, 83*94682d6aSJordan Rife .ip = "0.0.0.0", 84*94682d6aSJordan Rife .result = BIND_REJECT, 85*94682d6aSJordan Rife }, 86*94682d6aSJordan Rife { 87*94682d6aSJordan Rife .descr = "bind6 reject all", 88*94682d6aSJordan Rife .insns = { 89*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 0), 90*94682d6aSJordan Rife BPF_EXIT_INSN(), 91*94682d6aSJordan Rife }, 92*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET6_POST_BIND, 93*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET6_POST_BIND, 94*94682d6aSJordan Rife .domain = AF_INET6, 95*94682d6aSJordan Rife .type = SOCK_STREAM, 96*94682d6aSJordan Rife .ip = "::", 97*94682d6aSJordan Rife .result = BIND_REJECT, 98*94682d6aSJordan Rife }, 99*94682d6aSJordan Rife { 100*94682d6aSJordan Rife .descr = "bind6 deny specific IP & port", 101*94682d6aSJordan Rife .insns = { 102*94682d6aSJordan Rife BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 103*94682d6aSJordan Rife 104*94682d6aSJordan Rife /* if (ip == expected && port == expected) */ 105*94682d6aSJordan Rife BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 106*94682d6aSJordan Rife offsetof(struct bpf_sock, src_ip6[3])), 107*94682d6aSJordan Rife BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 108*94682d6aSJordan Rife __bpf_constant_ntohl(0x00000001), 4), 109*94682d6aSJordan Rife BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 110*94682d6aSJordan Rife offsetof(struct bpf_sock, src_port)), 111*94682d6aSJordan Rife BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2), 112*94682d6aSJordan Rife 113*94682d6aSJordan Rife /* return DENY; */ 114*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 0), 115*94682d6aSJordan Rife BPF_JMP_A(1), 116*94682d6aSJordan Rife 117*94682d6aSJordan Rife /* else return ALLOW; */ 118*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 119*94682d6aSJordan Rife BPF_EXIT_INSN(), 120*94682d6aSJordan Rife }, 121*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET6_POST_BIND, 122*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET6_POST_BIND, 123*94682d6aSJordan Rife .domain = AF_INET6, 124*94682d6aSJordan Rife .type = SOCK_STREAM, 125*94682d6aSJordan Rife .ip = "::1", 126*94682d6aSJordan Rife .port = 8193, 127*94682d6aSJordan Rife .result = BIND_REJECT, 128*94682d6aSJordan Rife }, 129*94682d6aSJordan Rife { 130*94682d6aSJordan Rife .descr = "bind4 allow specific IP & port", 131*94682d6aSJordan Rife .insns = { 132*94682d6aSJordan Rife BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 133*94682d6aSJordan Rife 134*94682d6aSJordan Rife /* if (ip == expected && port == expected) */ 135*94682d6aSJordan Rife BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 136*94682d6aSJordan Rife offsetof(struct bpf_sock, src_ip4)), 137*94682d6aSJordan Rife BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 138*94682d6aSJordan Rife __bpf_constant_ntohl(0x7F000001), 4), 139*94682d6aSJordan Rife BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 140*94682d6aSJordan Rife offsetof(struct bpf_sock, src_port)), 141*94682d6aSJordan Rife BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2), 142*94682d6aSJordan Rife 143*94682d6aSJordan Rife /* return ALLOW; */ 144*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 145*94682d6aSJordan Rife BPF_JMP_A(1), 146*94682d6aSJordan Rife 147*94682d6aSJordan Rife /* else return DENY; */ 148*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 0), 149*94682d6aSJordan Rife BPF_EXIT_INSN(), 150*94682d6aSJordan Rife }, 151*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET4_POST_BIND, 152*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET4_POST_BIND, 153*94682d6aSJordan Rife .domain = AF_INET, 154*94682d6aSJordan Rife .type = SOCK_STREAM, 155*94682d6aSJordan Rife .ip = "127.0.0.1", 156*94682d6aSJordan Rife .port = 4098, 157*94682d6aSJordan Rife .result = SUCCESS, 158*94682d6aSJordan Rife }, 159*94682d6aSJordan Rife { 160*94682d6aSJordan Rife .descr = "bind4 deny specific IP & port of TCP, and retry", 161*94682d6aSJordan Rife .insns = { 162*94682d6aSJordan Rife BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 163*94682d6aSJordan Rife 164*94682d6aSJordan Rife /* if (ip == expected && port == expected) */ 165*94682d6aSJordan Rife BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 166*94682d6aSJordan Rife offsetof(struct bpf_sock, src_ip4)), 167*94682d6aSJordan Rife BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 168*94682d6aSJordan Rife __bpf_constant_ntohl(0x7F000001), 4), 169*94682d6aSJordan Rife BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 170*94682d6aSJordan Rife offsetof(struct bpf_sock, src_port)), 171*94682d6aSJordan Rife BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2), 172*94682d6aSJordan Rife 173*94682d6aSJordan Rife /* return DENY; */ 174*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 0), 175*94682d6aSJordan Rife BPF_JMP_A(1), 176*94682d6aSJordan Rife 177*94682d6aSJordan Rife /* else return ALLOW; */ 178*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 179*94682d6aSJordan Rife BPF_EXIT_INSN(), 180*94682d6aSJordan Rife }, 181*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET4_POST_BIND, 182*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET4_POST_BIND, 183*94682d6aSJordan Rife .domain = AF_INET, 184*94682d6aSJordan Rife .type = SOCK_STREAM, 185*94682d6aSJordan Rife .ip = "127.0.0.1", 186*94682d6aSJordan Rife .port = 4098, 187*94682d6aSJordan Rife .port_retry = 5000, 188*94682d6aSJordan Rife .result = RETRY_SUCCESS, 189*94682d6aSJordan Rife }, 190*94682d6aSJordan Rife { 191*94682d6aSJordan Rife .descr = "bind4 deny specific IP & port of UDP, and retry", 192*94682d6aSJordan Rife .insns = { 193*94682d6aSJordan Rife BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 194*94682d6aSJordan Rife 195*94682d6aSJordan Rife /* if (ip == expected && port == expected) */ 196*94682d6aSJordan Rife BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 197*94682d6aSJordan Rife offsetof(struct bpf_sock, src_ip4)), 198*94682d6aSJordan Rife BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 199*94682d6aSJordan Rife __bpf_constant_ntohl(0x7F000001), 4), 200*94682d6aSJordan Rife BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 201*94682d6aSJordan Rife offsetof(struct bpf_sock, src_port)), 202*94682d6aSJordan Rife BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2), 203*94682d6aSJordan Rife 204*94682d6aSJordan Rife /* return DENY; */ 205*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 0), 206*94682d6aSJordan Rife BPF_JMP_A(1), 207*94682d6aSJordan Rife 208*94682d6aSJordan Rife /* else return ALLOW; */ 209*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 210*94682d6aSJordan Rife BPF_EXIT_INSN(), 211*94682d6aSJordan Rife }, 212*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET4_POST_BIND, 213*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET4_POST_BIND, 214*94682d6aSJordan Rife .domain = AF_INET, 215*94682d6aSJordan Rife .type = SOCK_DGRAM, 216*94682d6aSJordan Rife .ip = "127.0.0.1", 217*94682d6aSJordan Rife .port = 4098, 218*94682d6aSJordan Rife .port_retry = 5000, 219*94682d6aSJordan Rife .result = RETRY_SUCCESS, 220*94682d6aSJordan Rife }, 221*94682d6aSJordan Rife { 222*94682d6aSJordan Rife .descr = "bind6 deny specific IP & port, and retry", 223*94682d6aSJordan Rife .insns = { 224*94682d6aSJordan Rife BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), 225*94682d6aSJordan Rife 226*94682d6aSJordan Rife /* if (ip == expected && port == expected) */ 227*94682d6aSJordan Rife BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 228*94682d6aSJordan Rife offsetof(struct bpf_sock, src_ip6[3])), 229*94682d6aSJordan Rife BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 230*94682d6aSJordan Rife __bpf_constant_ntohl(0x00000001), 4), 231*94682d6aSJordan Rife BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, 232*94682d6aSJordan Rife offsetof(struct bpf_sock, src_port)), 233*94682d6aSJordan Rife BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2), 234*94682d6aSJordan Rife 235*94682d6aSJordan Rife /* return DENY; */ 236*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 0), 237*94682d6aSJordan Rife BPF_JMP_A(1), 238*94682d6aSJordan Rife 239*94682d6aSJordan Rife /* else return ALLOW; */ 240*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 241*94682d6aSJordan Rife BPF_EXIT_INSN(), 242*94682d6aSJordan Rife }, 243*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET6_POST_BIND, 244*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET6_POST_BIND, 245*94682d6aSJordan Rife .domain = AF_INET6, 246*94682d6aSJordan Rife .type = SOCK_STREAM, 247*94682d6aSJordan Rife .ip = "::1", 248*94682d6aSJordan Rife .port = 8193, 249*94682d6aSJordan Rife .port_retry = 9000, 250*94682d6aSJordan Rife .result = RETRY_SUCCESS, 251*94682d6aSJordan Rife }, 252*94682d6aSJordan Rife { 253*94682d6aSJordan Rife .descr = "bind4 allow all", 254*94682d6aSJordan Rife .insns = { 255*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 256*94682d6aSJordan Rife BPF_EXIT_INSN(), 257*94682d6aSJordan Rife }, 258*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET4_POST_BIND, 259*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET4_POST_BIND, 260*94682d6aSJordan Rife .domain = AF_INET, 261*94682d6aSJordan Rife .type = SOCK_STREAM, 262*94682d6aSJordan Rife .ip = "0.0.0.0", 263*94682d6aSJordan Rife .result = SUCCESS, 264*94682d6aSJordan Rife }, 265*94682d6aSJordan Rife { 266*94682d6aSJordan Rife .descr = "bind6 allow all", 267*94682d6aSJordan Rife .insns = { 268*94682d6aSJordan Rife BPF_MOV64_IMM(BPF_REG_0, 1), 269*94682d6aSJordan Rife BPF_EXIT_INSN(), 270*94682d6aSJordan Rife }, 271*94682d6aSJordan Rife .expected_attach_type = BPF_CGROUP_INET6_POST_BIND, 272*94682d6aSJordan Rife .attach_type = BPF_CGROUP_INET6_POST_BIND, 273*94682d6aSJordan Rife .domain = AF_INET6, 274*94682d6aSJordan Rife .type = SOCK_STREAM, 275*94682d6aSJordan Rife .ip = "::", 276*94682d6aSJordan Rife .result = SUCCESS, 277*94682d6aSJordan Rife }, 278*94682d6aSJordan Rife }; 279*94682d6aSJordan Rife 280*94682d6aSJordan Rife static int load_prog(const struct bpf_insn *insns, 281*94682d6aSJordan Rife enum bpf_attach_type expected_attach_type) 282*94682d6aSJordan Rife { 283*94682d6aSJordan Rife LIBBPF_OPTS(bpf_prog_load_opts, opts, 284*94682d6aSJordan Rife .expected_attach_type = expected_attach_type, 285*94682d6aSJordan Rife .log_level = 2, 286*94682d6aSJordan Rife .log_buf = bpf_log_buf, 287*94682d6aSJordan Rife .log_size = sizeof(bpf_log_buf), 288*94682d6aSJordan Rife ); 289*94682d6aSJordan Rife int fd, insns_cnt = 0; 290*94682d6aSJordan Rife 291*94682d6aSJordan Rife for (; 292*94682d6aSJordan Rife insns[insns_cnt].code != (BPF_JMP | BPF_EXIT); 293*94682d6aSJordan Rife insns_cnt++) { 294*94682d6aSJordan Rife } 295*94682d6aSJordan Rife insns_cnt++; 296*94682d6aSJordan Rife 297*94682d6aSJordan Rife fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns, 298*94682d6aSJordan Rife insns_cnt, &opts); 299*94682d6aSJordan Rife if (fd < 0) 300*94682d6aSJordan Rife fprintf(stderr, "%s\n", bpf_log_buf); 301*94682d6aSJordan Rife 302*94682d6aSJordan Rife return fd; 303*94682d6aSJordan Rife } 304*94682d6aSJordan Rife 305*94682d6aSJordan Rife static int bind_sock(int domain, int type, const char *ip, 306*94682d6aSJordan Rife unsigned short port, unsigned short port_retry) 307*94682d6aSJordan Rife { 308*94682d6aSJordan Rife struct sockaddr_storage addr; 309*94682d6aSJordan Rife struct sockaddr_in6 *addr6; 310*94682d6aSJordan Rife struct sockaddr_in *addr4; 311*94682d6aSJordan Rife int sockfd = -1; 312*94682d6aSJordan Rife socklen_t len; 313*94682d6aSJordan Rife int res = SUCCESS; 314*94682d6aSJordan Rife 315*94682d6aSJordan Rife sockfd = socket(domain, type, 0); 316*94682d6aSJordan Rife if (sockfd < 0) 317*94682d6aSJordan Rife goto err; 318*94682d6aSJordan Rife 319*94682d6aSJordan Rife memset(&addr, 0, sizeof(addr)); 320*94682d6aSJordan Rife 321*94682d6aSJordan Rife if (domain == AF_INET) { 322*94682d6aSJordan Rife len = sizeof(struct sockaddr_in); 323*94682d6aSJordan Rife addr4 = (struct sockaddr_in *)&addr; 324*94682d6aSJordan Rife addr4->sin_family = domain; 325*94682d6aSJordan Rife addr4->sin_port = htons(port); 326*94682d6aSJordan Rife if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) 327*94682d6aSJordan Rife goto err; 328*94682d6aSJordan Rife } else if (domain == AF_INET6) { 329*94682d6aSJordan Rife len = sizeof(struct sockaddr_in6); 330*94682d6aSJordan Rife addr6 = (struct sockaddr_in6 *)&addr; 331*94682d6aSJordan Rife addr6->sin6_family = domain; 332*94682d6aSJordan Rife addr6->sin6_port = htons(port); 333*94682d6aSJordan Rife if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) 334*94682d6aSJordan Rife goto err; 335*94682d6aSJordan Rife } else { 336*94682d6aSJordan Rife goto err; 337*94682d6aSJordan Rife } 338*94682d6aSJordan Rife 339*94682d6aSJordan Rife if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) { 340*94682d6aSJordan Rife /* sys_bind() may fail for different reasons, errno has to be 341*94682d6aSJordan Rife * checked to confirm that BPF program rejected it. 342*94682d6aSJordan Rife */ 343*94682d6aSJordan Rife if (errno != EPERM) 344*94682d6aSJordan Rife goto err; 345*94682d6aSJordan Rife if (port_retry) 346*94682d6aSJordan Rife goto retry; 347*94682d6aSJordan Rife res = BIND_REJECT; 348*94682d6aSJordan Rife goto out; 349*94682d6aSJordan Rife } 350*94682d6aSJordan Rife 351*94682d6aSJordan Rife goto out; 352*94682d6aSJordan Rife retry: 353*94682d6aSJordan Rife if (domain == AF_INET) 354*94682d6aSJordan Rife addr4->sin_port = htons(port_retry); 355*94682d6aSJordan Rife else 356*94682d6aSJordan Rife addr6->sin6_port = htons(port_retry); 357*94682d6aSJordan Rife if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) { 358*94682d6aSJordan Rife if (errno != EPERM) 359*94682d6aSJordan Rife goto err; 360*94682d6aSJordan Rife res = RETRY_REJECT; 361*94682d6aSJordan Rife } else { 362*94682d6aSJordan Rife res = RETRY_SUCCESS; 363*94682d6aSJordan Rife } 364*94682d6aSJordan Rife goto out; 365*94682d6aSJordan Rife err: 366*94682d6aSJordan Rife res = -1; 367*94682d6aSJordan Rife out: 368*94682d6aSJordan Rife close(sockfd); 369*94682d6aSJordan Rife return res; 370*94682d6aSJordan Rife } 371*94682d6aSJordan Rife 372*94682d6aSJordan Rife static int run_test(int cgroup_fd, struct sock_post_bind_test *test) 373*94682d6aSJordan Rife { 374*94682d6aSJordan Rife int err, prog_fd, res, ret = 0; 375*94682d6aSJordan Rife 376*94682d6aSJordan Rife prog_fd = load_prog(test->insns, test->expected_attach_type); 377*94682d6aSJordan Rife if (prog_fd < 0) 378*94682d6aSJordan Rife goto err; 379*94682d6aSJordan Rife 380*94682d6aSJordan Rife err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0); 381*94682d6aSJordan Rife if (err < 0) { 382*94682d6aSJordan Rife if (test->result == ATTACH_REJECT) 383*94682d6aSJordan Rife goto out; 384*94682d6aSJordan Rife else 385*94682d6aSJordan Rife goto err; 386*94682d6aSJordan Rife } 387*94682d6aSJordan Rife 388*94682d6aSJordan Rife res = bind_sock(test->domain, test->type, test->ip, test->port, 389*94682d6aSJordan Rife test->port_retry); 390*94682d6aSJordan Rife if (res > 0 && test->result == res) 391*94682d6aSJordan Rife goto out; 392*94682d6aSJordan Rife err: 393*94682d6aSJordan Rife ret = -1; 394*94682d6aSJordan Rife out: 395*94682d6aSJordan Rife /* Detaching w/o checking return code: best effort attempt. */ 396*94682d6aSJordan Rife if (prog_fd != -1) 397*94682d6aSJordan Rife bpf_prog_detach(cgroup_fd, test->attach_type); 398*94682d6aSJordan Rife close(prog_fd); 399*94682d6aSJordan Rife return ret; 400*94682d6aSJordan Rife } 401*94682d6aSJordan Rife 402*94682d6aSJordan Rife void test_sock_post_bind(void) 403*94682d6aSJordan Rife { 404*94682d6aSJordan Rife struct netns_obj *ns; 405*94682d6aSJordan Rife int cgroup_fd; 406*94682d6aSJordan Rife int i; 407*94682d6aSJordan Rife 408*94682d6aSJordan Rife cgroup_fd = test__join_cgroup("/post_bind"); 409*94682d6aSJordan Rife if (!ASSERT_OK_FD(cgroup_fd, "join_cgroup")) 410*94682d6aSJordan Rife return; 411*94682d6aSJordan Rife 412*94682d6aSJordan Rife ns = netns_new(TEST_NS, true); 413*94682d6aSJordan Rife if (!ASSERT_OK_PTR(ns, "netns_new")) 414*94682d6aSJordan Rife goto cleanup; 415*94682d6aSJordan Rife 416*94682d6aSJordan Rife for (i = 0; i < ARRAY_SIZE(tests); i++) { 417*94682d6aSJordan Rife if (!test__start_subtest(tests[i].descr)) 418*94682d6aSJordan Rife continue; 419*94682d6aSJordan Rife 420*94682d6aSJordan Rife ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr); 421*94682d6aSJordan Rife } 422*94682d6aSJordan Rife 423*94682d6aSJordan Rife cleanup: 424*94682d6aSJordan Rife netns_free(ns); 425*94682d6aSJordan Rife close(cgroup_fd); 426*94682d6aSJordan Rife } 427