From 88dadc632763bdccddf99d8454aa3a7932605f00 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Wed, 4 Sep 2019 09:25:04 -0700 Subject: selftests/bpf: test_progs: add test__join_cgroup helper test__join_cgroup() combines the following operations that usually go hand in hand and returns cgroup fd: * setup cgroup environment (make sure cgroupfs is mounted) * mkdir cgroup * join cgroup It also marks a test as a "cgroup cleanup needed" and removes cgroup state after the test is done. Signed-off-by: Stanislav Fomichev Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/Makefile | 4 ++-- tools/testing/selftests/bpf/test_progs.c | 38 ++++++++++++++++++++++++++++++++ tools/testing/selftests/bpf/test_progs.h | 1 + 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 9eef5edf17be..ce9650bad453 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -106,7 +106,7 @@ $(OUTPUT)/test_socket_cookie: cgroup_helpers.c $(OUTPUT)/test_sockmap: cgroup_helpers.c $(OUTPUT)/test_tcpbpf_user: cgroup_helpers.c $(OUTPUT)/test_tcpnotify_user: cgroup_helpers.c trace_helpers.c -$(OUTPUT)/test_progs: trace_helpers.c +$(OUTPUT)/test_progs: cgroup_helpers.c trace_helpers.c $(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c $(OUTPUT)/test_cgroup_storage: cgroup_helpers.c $(OUTPUT)/test_netcnt: cgroup_helpers.c @@ -200,7 +200,7 @@ $(ALU32_BUILD_DIR)/test_progs_32: test_progs.c $(OUTPUT)/libbpf.a\ | $(ALU32_BUILD_DIR) $(CC) $(TEST_PROGS_CFLAGS) $(CFLAGS) \ -o $(ALU32_BUILD_DIR)/test_progs_32 \ - test_progs.c test_stub.c trace_helpers.c prog_tests/*.c \ + test_progs.c test_stub.c cgroup_helpers.c trace_helpers.c prog_tests/*.c \ $(OUTPUT)/libbpf.a $(LDLIBS) $(ALU32_BUILD_DIR)/test_progs_32: $(PROG_TESTS_H) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index e8616e778cb5..af75a1c7a458 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -2,6 +2,7 @@ /* Copyright (c) 2017 Facebook */ #include "test_progs.h" +#include "cgroup_helpers.h" #include "bpf_rlimit.h" #include #include @@ -17,6 +18,7 @@ struct prog_test_def { int error_cnt; int skip_cnt; bool tested; + bool need_cgroup_cleanup; const char *subtest_name; int subtest_num; @@ -122,6 +124,39 @@ void test__fail(void) env.test->error_cnt++; } +int test__join_cgroup(const char *path) +{ + int fd; + + if (!env.test->need_cgroup_cleanup) { + if (setup_cgroup_environment()) { + fprintf(stderr, + "#%d %s: Failed to setup cgroup environment\n", + env.test->test_num, env.test->test_name); + return -1; + } + + env.test->need_cgroup_cleanup = true; + } + + fd = create_and_get_cgroup(path); + if (fd < 0) { + fprintf(stderr, + "#%d %s: Failed to create cgroup '%s' (errno=%d)\n", + env.test->test_num, env.test->test_name, path, errno); + return fd; + } + + if (join_cgroup(path)) { + fprintf(stderr, + "#%d %s: Failed to join cgroup '%s' (errno=%d)\n", + env.test->test_num, env.test->test_name, path, errno); + return -1; + } + + return fd; +} + struct ipv4_packet pkt_v4 = { .eth.h_proto = __bpf_constant_htons(ETH_P_IP), .iph.ihl = 5, @@ -530,6 +565,9 @@ int main(int argc, char **argv) fprintf(env.stdout, "#%d %s:%s\n", test->test_num, test->test_name, test->error_cnt ? "FAIL" : "OK"); + + if (test->need_cgroup_cleanup) + cleanup_cgroup_environment(); } stdio_restore(); printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n", diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h index c8edb9464ba6..e518bd5da3e2 100644 --- a/tools/testing/selftests/bpf/test_progs.h +++ b/tools/testing/selftests/bpf/test_progs.h @@ -71,6 +71,7 @@ extern void test__force_log(); extern bool test__start_subtest(const char *name); extern void test__skip(void); extern void test__fail(void); +extern int test__join_cgroup(const char *path); #define MAGIC_BYTES 123 -- cgit v1.2.3 From 4a64742168ce9e9972dab3f684629845c6e6dc67 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Wed, 4 Sep 2019 09:25:05 -0700 Subject: selftests/bpf: test_progs: convert test_sockopt Move the files, adjust includes, remove entry from Makefile & .gitignore Signed-off-by: Stanislav Fomichev Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/.gitignore | 1 - tools/testing/selftests/bpf/Makefile | 3 +- tools/testing/selftests/bpf/prog_tests/sockopt.c | 985 +++++++++++++++++++++ tools/testing/selftests/bpf/test_sockopt.c | 1021 ---------------------- 4 files changed, 986 insertions(+), 1024 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/sockopt.c delete mode 100644 tools/testing/selftests/bpf/test_sockopt.c diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 60c9338cd9b4..0315120eac8f 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -39,7 +39,6 @@ libbpf.so.* test_hashmap test_btf_dump xdping -test_sockopt test_sockopt_sk test_sockopt_multi test_sockopt_inherit diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index ce9650bad453..7151cbc4676e 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -28,7 +28,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test test_sock test_btf test_sockmap get_cgroup_id_user test_socket_cookie \ test_cgroup_storage test_select_reuseport test_section_names \ test_netcnt test_tcpnotify_user test_sock_fields test_sysctl test_hashmap \ - test_btf_dump test_cgroup_attach xdping test_sockopt test_sockopt_sk \ + test_btf_dump test_cgroup_attach xdping test_sockopt_sk \ test_sockopt_multi test_sockopt_inherit test_tcp_rtt BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c))) @@ -113,7 +113,6 @@ $(OUTPUT)/test_netcnt: cgroup_helpers.c $(OUTPUT)/test_sock_fields: cgroup_helpers.c $(OUTPUT)/test_sysctl: cgroup_helpers.c $(OUTPUT)/test_cgroup_attach: cgroup_helpers.c -$(OUTPUT)/test_sockopt: cgroup_helpers.c $(OUTPUT)/test_sockopt_sk: cgroup_helpers.c $(OUTPUT)/test_sockopt_multi: cgroup_helpers.c $(OUTPUT)/test_sockopt_inherit: cgroup_helpers.c diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt.c b/tools/testing/selftests/bpf/prog_tests/sockopt.c new file mode 100644 index 000000000000..3e8517a8395a --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/sockopt.c @@ -0,0 +1,985 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "cgroup_helpers.h" + +static char bpf_log_buf[4096]; +static bool verbose; + +enum sockopt_test_error { + OK = 0, + DENY_LOAD, + DENY_ATTACH, + EPERM_GETSOCKOPT, + EFAULT_GETSOCKOPT, + EPERM_SETSOCKOPT, + EFAULT_SETSOCKOPT, +}; + +static struct sockopt_test { + const char *descr; + const struct bpf_insn insns[64]; + enum bpf_attach_type attach_type; + enum bpf_attach_type expected_attach_type; + + int set_optname; + int set_level; + const char set_optval[64]; + socklen_t set_optlen; + + int get_optname; + int get_level; + const char get_optval[64]; + socklen_t get_optlen; + socklen_t get_optlen_ret; + + enum sockopt_test_error error; +} tests[] = { + + /* ==================== getsockopt ==================== */ + + { + .descr = "getsockopt: no expected_attach_type", + .insns = { + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = 0, + .error = DENY_LOAD, + }, + { + .descr = "getsockopt: wrong expected_attach_type", + .insns = { + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + .error = DENY_ATTACH, + }, + { + .descr = "getsockopt: bypass bpf hook", + .insns = { + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .get_level = SOL_IP, + .set_level = SOL_IP, + + .get_optname = IP_TOS, + .set_optname = IP_TOS, + + .set_optval = { 1 << 3 }, + .set_optlen = 1, + + .get_optval = { 1 << 3 }, + .get_optlen = 1, + }, + { + .descr = "getsockopt: return EPERM from bpf hook", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .get_level = SOL_IP, + .get_optname = IP_TOS, + + .get_optlen = 1, + .error = EPERM_GETSOCKOPT, + }, + { + .descr = "getsockopt: no optval bounds check, deny loading", + .insns = { + /* r6 = ctx->optval */ + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optval)), + + /* ctx->optval[0] = 0x80 */ + BPF_MOV64_IMM(BPF_REG_0, 0x80), + BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_0, 0), + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + .error = DENY_LOAD, + }, + { + .descr = "getsockopt: read ctx->level", + .insns = { + /* r6 = ctx->level */ + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, level)), + + /* if (ctx->level == 123) { */ + BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4), + /* ctx->retval = 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, retval)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_JMP_A(1), + /* } else { */ + /* return 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + /* } */ + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .get_level = 123, + + .get_optlen = 1, + }, + { + .descr = "getsockopt: deny writing to ctx->level", + .insns = { + /* ctx->level = 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, level)), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .error = DENY_LOAD, + }, + { + .descr = "getsockopt: read ctx->optname", + .insns = { + /* r6 = ctx->optname */ + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optname)), + + /* if (ctx->optname == 123) { */ + BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4), + /* ctx->retval = 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, retval)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_JMP_A(1), + /* } else { */ + /* return 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + /* } */ + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .get_optname = 123, + + .get_optlen = 1, + }, + { + .descr = "getsockopt: read ctx->retval", + .insns = { + /* r6 = ctx->retval */ + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, retval)), + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .get_level = SOL_IP, + .get_optname = IP_TOS, + .get_optlen = 1, + }, + { + .descr = "getsockopt: deny writing to ctx->optname", + .insns = { + /* ctx->optname = 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optname)), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .error = DENY_LOAD, + }, + { + .descr = "getsockopt: read ctx->optlen", + .insns = { + /* r6 = ctx->optlen */ + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optlen)), + + /* if (ctx->optlen == 64) { */ + BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4), + /* ctx->retval = 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, retval)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_JMP_A(1), + /* } else { */ + /* return 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + /* } */ + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .get_optlen = 64, + }, + { + .descr = "getsockopt: deny bigger ctx->optlen", + .insns = { + /* ctx->optlen = 65 */ + BPF_MOV64_IMM(BPF_REG_0, 65), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optlen)), + + /* ctx->retval = 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, retval)), + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .get_optlen = 64, + + .error = EFAULT_GETSOCKOPT, + }, + { + .descr = "getsockopt: deny arbitrary ctx->retval", + .insns = { + /* ctx->retval = 123 */ + BPF_MOV64_IMM(BPF_REG_0, 123), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, retval)), + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .get_optlen = 64, + + .error = EFAULT_GETSOCKOPT, + }, + { + .descr = "getsockopt: support smaller ctx->optlen", + .insns = { + /* ctx->optlen = 32 */ + BPF_MOV64_IMM(BPF_REG_0, 32), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optlen)), + /* ctx->retval = 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, retval)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .get_optlen = 64, + .get_optlen_ret = 32, + }, + { + .descr = "getsockopt: deny writing to ctx->optval", + .insns = { + /* ctx->optval = 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optval)), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .error = DENY_LOAD, + }, + { + .descr = "getsockopt: deny writing to ctx->optval_end", + .insns = { + /* ctx->optval_end = 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optval_end)), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .error = DENY_LOAD, + }, + { + .descr = "getsockopt: rewrite value", + .insns = { + /* r6 = ctx->optval */ + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optval)), + /* r2 = ctx->optval */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), + /* r6 = ctx->optval + 1 */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), + + /* r7 = ctx->optval_end */ + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1, + offsetof(struct bpf_sockopt, optval_end)), + + /* if (ctx->optval + 1 <= ctx->optval_end) { */ + BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1), + /* ctx->optval[0] = 0xF0 */ + BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0), + /* } */ + + /* ctx->retval = 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, retval)), + + /* return 1*/ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_GETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + + .get_level = SOL_IP, + .get_optname = IP_TOS, + + .get_optval = { 0xF0 }, + .get_optlen = 1, + }, + + /* ==================== setsockopt ==================== */ + + { + .descr = "setsockopt: no expected_attach_type", + .insns = { + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = 0, + .error = DENY_LOAD, + }, + { + .descr = "setsockopt: wrong expected_attach_type", + .insns = { + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_GETSOCKOPT, + .error = DENY_ATTACH, + }, + { + .descr = "setsockopt: bypass bpf hook", + .insns = { + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .get_level = SOL_IP, + .set_level = SOL_IP, + + .get_optname = IP_TOS, + .set_optname = IP_TOS, + + .set_optval = { 1 << 3 }, + .set_optlen = 1, + + .get_optval = { 1 << 3 }, + .get_optlen = 1, + }, + { + .descr = "setsockopt: return EPERM from bpf hook", + .insns = { + /* return 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .set_level = SOL_IP, + .set_optname = IP_TOS, + + .set_optlen = 1, + .error = EPERM_SETSOCKOPT, + }, + { + .descr = "setsockopt: no optval bounds check, deny loading", + .insns = { + /* r6 = ctx->optval */ + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optval)), + + /* r0 = ctx->optval[0] */ + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, 0), + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + .error = DENY_LOAD, + }, + { + .descr = "setsockopt: read ctx->level", + .insns = { + /* r6 = ctx->level */ + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, level)), + + /* if (ctx->level == 123) { */ + BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4), + /* ctx->optlen = -1 */ + BPF_MOV64_IMM(BPF_REG_0, -1), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optlen)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_JMP_A(1), + /* } else { */ + /* return 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + /* } */ + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .set_level = 123, + + .set_optlen = 1, + }, + { + .descr = "setsockopt: allow changing ctx->level", + .insns = { + /* ctx->level = SOL_IP */ + BPF_MOV64_IMM(BPF_REG_0, SOL_IP), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, level)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .get_level = SOL_IP, + .set_level = 234, /* should be rewritten to SOL_IP */ + + .get_optname = IP_TOS, + .set_optname = IP_TOS, + + .set_optval = { 1 << 3 }, + .set_optlen = 1, + .get_optval = { 1 << 3 }, + .get_optlen = 1, + }, + { + .descr = "setsockopt: read ctx->optname", + .insns = { + /* r6 = ctx->optname */ + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optname)), + + /* if (ctx->optname == 123) { */ + BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4), + /* ctx->optlen = -1 */ + BPF_MOV64_IMM(BPF_REG_0, -1), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optlen)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_JMP_A(1), + /* } else { */ + /* return 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + /* } */ + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .set_optname = 123, + + .set_optlen = 1, + }, + { + .descr = "setsockopt: allow changing ctx->optname", + .insns = { + /* ctx->optname = IP_TOS */ + BPF_MOV64_IMM(BPF_REG_0, IP_TOS), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optname)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .get_level = SOL_IP, + .set_level = SOL_IP, + + .get_optname = IP_TOS, + .set_optname = 456, /* should be rewritten to IP_TOS */ + + .set_optval = { 1 << 3 }, + .set_optlen = 1, + .get_optval = { 1 << 3 }, + .get_optlen = 1, + }, + { + .descr = "setsockopt: read ctx->optlen", + .insns = { + /* r6 = ctx->optlen */ + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optlen)), + + /* if (ctx->optlen == 64) { */ + BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4), + /* ctx->optlen = -1 */ + BPF_MOV64_IMM(BPF_REG_0, -1), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optlen)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_JMP_A(1), + /* } else { */ + /* return 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + /* } */ + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .set_optlen = 64, + }, + { + .descr = "setsockopt: ctx->optlen == -1 is ok", + .insns = { + /* ctx->optlen = -1 */ + BPF_MOV64_IMM(BPF_REG_0, -1), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optlen)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .set_optlen = 64, + }, + { + .descr = "setsockopt: deny ctx->optlen < 0 (except -1)", + .insns = { + /* ctx->optlen = -2 */ + BPF_MOV64_IMM(BPF_REG_0, -2), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optlen)), + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .set_optlen = 4, + + .error = EFAULT_SETSOCKOPT, + }, + { + .descr = "setsockopt: deny ctx->optlen > input optlen", + .insns = { + /* ctx->optlen = 65 */ + BPF_MOV64_IMM(BPF_REG_0, 65), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optlen)), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .set_optlen = 64, + + .error = EFAULT_SETSOCKOPT, + }, + { + .descr = "setsockopt: allow changing ctx->optlen within bounds", + .insns = { + /* r6 = ctx->optval */ + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optval)), + /* r2 = ctx->optval */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), + /* r6 = ctx->optval + 1 */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), + + /* r7 = ctx->optval_end */ + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1, + offsetof(struct bpf_sockopt, optval_end)), + + /* if (ctx->optval + 1 <= ctx->optval_end) { */ + BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1), + /* ctx->optval[0] = 1 << 3 */ + BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 1 << 3), + /* } */ + + /* ctx->optlen = 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optlen)), + + /* return 1*/ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .get_level = SOL_IP, + .set_level = SOL_IP, + + .get_optname = IP_TOS, + .set_optname = IP_TOS, + + .set_optval = { 1, 1, 1, 1 }, + .set_optlen = 4, + .get_optval = { 1 << 3 }, + .get_optlen = 1, + }, + { + .descr = "setsockopt: deny write ctx->retval", + .insns = { + /* ctx->retval = 0 */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, retval)), + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .error = DENY_LOAD, + }, + { + .descr = "setsockopt: deny read ctx->retval", + .insns = { + /* r6 = ctx->retval */ + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, retval)), + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .error = DENY_LOAD, + }, + { + .descr = "setsockopt: deny writing to ctx->optval", + .insns = { + /* ctx->optval = 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optval)), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .error = DENY_LOAD, + }, + { + .descr = "setsockopt: deny writing to ctx->optval_end", + .insns = { + /* ctx->optval_end = 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, + offsetof(struct bpf_sockopt, optval_end)), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .error = DENY_LOAD, + }, + { + .descr = "setsockopt: allow IP_TOS <= 128", + .insns = { + /* r6 = ctx->optval */ + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optval)), + /* r7 = ctx->optval + 1 */ + BPF_MOV64_REG(BPF_REG_7, BPF_REG_6), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1), + + /* r8 = ctx->optval_end */ + BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1, + offsetof(struct bpf_sockopt, optval_end)), + + /* if (ctx->optval + 1 <= ctx->optval_end) { */ + BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4), + + /* r9 = ctx->optval[0] */ + BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0), + + /* if (ctx->optval[0] < 128) */ + BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_JMP_A(1), + /* } */ + + /* } else { */ + BPF_MOV64_IMM(BPF_REG_0, 0), + /* } */ + + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .get_level = SOL_IP, + .set_level = SOL_IP, + + .get_optname = IP_TOS, + .set_optname = IP_TOS, + + .set_optval = { 0x80 }, + .set_optlen = 1, + .get_optval = { 0x80 }, + .get_optlen = 1, + }, + { + .descr = "setsockopt: deny IP_TOS > 128", + .insns = { + /* r6 = ctx->optval */ + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optval)), + /* r7 = ctx->optval + 1 */ + BPF_MOV64_REG(BPF_REG_7, BPF_REG_6), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1), + + /* r8 = ctx->optval_end */ + BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1, + offsetof(struct bpf_sockopt, optval_end)), + + /* if (ctx->optval + 1 <= ctx->optval_end) { */ + BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4), + + /* r9 = ctx->optval[0] */ + BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0), + + /* if (ctx->optval[0] < 128) */ + BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_JMP_A(1), + /* } */ + + /* } else { */ + BPF_MOV64_IMM(BPF_REG_0, 0), + /* } */ + + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .get_level = SOL_IP, + .set_level = SOL_IP, + + .get_optname = IP_TOS, + .set_optname = IP_TOS, + + .set_optval = { 0x81 }, + .set_optlen = 1, + .get_optval = { 0x00 }, + .get_optlen = 1, + + .error = EPERM_SETSOCKOPT, + }, +}; + +static int load_prog(const struct bpf_insn *insns, + enum bpf_attach_type expected_attach_type) +{ + struct bpf_load_program_attr attr = { + .prog_type = BPF_PROG_TYPE_CGROUP_SOCKOPT, + .expected_attach_type = expected_attach_type, + .insns = insns, + .license = "GPL", + .log_level = 2, + }; + int fd; + + for (; + insns[attr.insns_cnt].code != (BPF_JMP | BPF_EXIT); + attr.insns_cnt++) { + } + attr.insns_cnt++; + + fd = bpf_load_program_xattr(&attr, bpf_log_buf, sizeof(bpf_log_buf)); + if (verbose && fd < 0) + fprintf(stderr, "%s\n", bpf_log_buf); + + return fd; +} + +static int run_test(int cgroup_fd, struct sockopt_test *test) +{ + int sock_fd, err, prog_fd; + void *optval = NULL; + int ret = 0; + + prog_fd = load_prog(test->insns, test->expected_attach_type); + if (prog_fd < 0) { + if (test->error == DENY_LOAD) + return 0; + + log_err("Failed to load BPF program"); + return -1; + } + + err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0); + if (err < 0) { + if (test->error == DENY_ATTACH) + goto close_prog_fd; + + log_err("Failed to attach BPF program"); + ret = -1; + goto close_prog_fd; + } + + sock_fd = socket(AF_INET, SOCK_STREAM, 0); + if (sock_fd < 0) { + log_err("Failed to create AF_INET socket"); + ret = -1; + goto detach_prog; + } + + if (test->set_optlen) { + err = setsockopt(sock_fd, test->set_level, test->set_optname, + test->set_optval, test->set_optlen); + if (err) { + if (errno == EPERM && test->error == EPERM_SETSOCKOPT) + goto close_sock_fd; + if (errno == EFAULT && test->error == EFAULT_SETSOCKOPT) + goto free_optval; + + log_err("Failed to call setsockopt"); + ret = -1; + goto close_sock_fd; + } + } + + if (test->get_optlen) { + optval = malloc(test->get_optlen); + socklen_t optlen = test->get_optlen; + socklen_t expected_get_optlen = test->get_optlen_ret ?: + test->get_optlen; + + err = getsockopt(sock_fd, test->get_level, test->get_optname, + optval, &optlen); + if (err) { + if (errno == EPERM && test->error == EPERM_GETSOCKOPT) + goto free_optval; + if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT) + goto free_optval; + + log_err("Failed to call getsockopt"); + ret = -1; + goto free_optval; + } + + if (optlen != expected_get_optlen) { + errno = 0; + log_err("getsockopt returned unexpected optlen"); + ret = -1; + goto free_optval; + } + + if (memcmp(optval, test->get_optval, optlen) != 0) { + errno = 0; + log_err("getsockopt returned unexpected optval"); + ret = -1; + goto free_optval; + } + } + + ret = test->error != OK; + +free_optval: + free(optval); +close_sock_fd: + close(sock_fd); +detach_prog: + bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type); +close_prog_fd: + close(prog_fd); + return ret; +} + +void test_sockopt(void) +{ + int cgroup_fd, i; + + cgroup_fd = test__join_cgroup("/sockopt"); + if (CHECK_FAIL(cgroup_fd < 0)) + return; + + for (i = 0; i < ARRAY_SIZE(tests); i++) { + test__start_subtest(tests[i].descr); + CHECK_FAIL(run_test(cgroup_fd, &tests[i])); + } + + close(cgroup_fd); +} diff --git a/tools/testing/selftests/bpf/test_sockopt.c b/tools/testing/selftests/bpf/test_sockopt.c deleted file mode 100644 index 23bd0819382d..000000000000 --- a/tools/testing/selftests/bpf/test_sockopt.c +++ /dev/null @@ -1,1021 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "bpf_rlimit.h" -#include "bpf_util.h" -#include "cgroup_helpers.h" - -#define CG_PATH "/sockopt" - -static char bpf_log_buf[4096]; -static bool verbose; - -enum sockopt_test_error { - OK = 0, - DENY_LOAD, - DENY_ATTACH, - EPERM_GETSOCKOPT, - EFAULT_GETSOCKOPT, - EPERM_SETSOCKOPT, - EFAULT_SETSOCKOPT, -}; - -static struct sockopt_test { - const char *descr; - const struct bpf_insn insns[64]; - enum bpf_attach_type attach_type; - enum bpf_attach_type expected_attach_type; - - int set_optname; - int set_level; - const char set_optval[64]; - socklen_t set_optlen; - - int get_optname; - int get_level; - const char get_optval[64]; - socklen_t get_optlen; - socklen_t get_optlen_ret; - - enum sockopt_test_error error; -} tests[] = { - - /* ==================== getsockopt ==================== */ - - { - .descr = "getsockopt: no expected_attach_type", - .insns = { - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = 0, - .error = DENY_LOAD, - }, - { - .descr = "getsockopt: wrong expected_attach_type", - .insns = { - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - .error = DENY_ATTACH, - }, - { - .descr = "getsockopt: bypass bpf hook", - .insns = { - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .get_level = SOL_IP, - .set_level = SOL_IP, - - .get_optname = IP_TOS, - .set_optname = IP_TOS, - - .set_optval = { 1 << 3 }, - .set_optlen = 1, - - .get_optval = { 1 << 3 }, - .get_optlen = 1, - }, - { - .descr = "getsockopt: return EPERM from bpf hook", - .insns = { - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .get_level = SOL_IP, - .get_optname = IP_TOS, - - .get_optlen = 1, - .error = EPERM_GETSOCKOPT, - }, - { - .descr = "getsockopt: no optval bounds check, deny loading", - .insns = { - /* r6 = ctx->optval */ - BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, optval)), - - /* ctx->optval[0] = 0x80 */ - BPF_MOV64_IMM(BPF_REG_0, 0x80), - BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_0, 0), - - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - .error = DENY_LOAD, - }, - { - .descr = "getsockopt: read ctx->level", - .insns = { - /* r6 = ctx->level */ - BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, level)), - - /* if (ctx->level == 123) { */ - BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4), - /* ctx->retval = 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, retval)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_JMP_A(1), - /* } else { */ - /* return 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - /* } */ - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .get_level = 123, - - .get_optlen = 1, - }, - { - .descr = "getsockopt: deny writing to ctx->level", - .insns = { - /* ctx->level = 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, level)), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .error = DENY_LOAD, - }, - { - .descr = "getsockopt: read ctx->optname", - .insns = { - /* r6 = ctx->optname */ - BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, optname)), - - /* if (ctx->optname == 123) { */ - BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4), - /* ctx->retval = 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, retval)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_JMP_A(1), - /* } else { */ - /* return 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - /* } */ - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .get_optname = 123, - - .get_optlen = 1, - }, - { - .descr = "getsockopt: read ctx->retval", - .insns = { - /* r6 = ctx->retval */ - BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, retval)), - - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .get_level = SOL_IP, - .get_optname = IP_TOS, - .get_optlen = 1, - }, - { - .descr = "getsockopt: deny writing to ctx->optname", - .insns = { - /* ctx->optname = 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optname)), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .error = DENY_LOAD, - }, - { - .descr = "getsockopt: read ctx->optlen", - .insns = { - /* r6 = ctx->optlen */ - BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, optlen)), - - /* if (ctx->optlen == 64) { */ - BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4), - /* ctx->retval = 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, retval)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_JMP_A(1), - /* } else { */ - /* return 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - /* } */ - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .get_optlen = 64, - }, - { - .descr = "getsockopt: deny bigger ctx->optlen", - .insns = { - /* ctx->optlen = 65 */ - BPF_MOV64_IMM(BPF_REG_0, 65), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optlen)), - - /* ctx->retval = 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, retval)), - - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .get_optlen = 64, - - .error = EFAULT_GETSOCKOPT, - }, - { - .descr = "getsockopt: deny arbitrary ctx->retval", - .insns = { - /* ctx->retval = 123 */ - BPF_MOV64_IMM(BPF_REG_0, 123), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, retval)), - - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .get_optlen = 64, - - .error = EFAULT_GETSOCKOPT, - }, - { - .descr = "getsockopt: support smaller ctx->optlen", - .insns = { - /* ctx->optlen = 32 */ - BPF_MOV64_IMM(BPF_REG_0, 32), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optlen)), - /* ctx->retval = 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, retval)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .get_optlen = 64, - .get_optlen_ret = 32, - }, - { - .descr = "getsockopt: deny writing to ctx->optval", - .insns = { - /* ctx->optval = 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optval)), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .error = DENY_LOAD, - }, - { - .descr = "getsockopt: deny writing to ctx->optval_end", - .insns = { - /* ctx->optval_end = 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optval_end)), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .error = DENY_LOAD, - }, - { - .descr = "getsockopt: rewrite value", - .insns = { - /* r6 = ctx->optval */ - BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, optval)), - /* r2 = ctx->optval */ - BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), - /* r6 = ctx->optval + 1 */ - BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), - - /* r7 = ctx->optval_end */ - BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1, - offsetof(struct bpf_sockopt, optval_end)), - - /* if (ctx->optval + 1 <= ctx->optval_end) { */ - BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1), - /* ctx->optval[0] = 0xF0 */ - BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0), - /* } */ - - /* ctx->retval = 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, retval)), - - /* return 1*/ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_GETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - - .get_level = SOL_IP, - .get_optname = IP_TOS, - - .get_optval = { 0xF0 }, - .get_optlen = 1, - }, - - /* ==================== setsockopt ==================== */ - - { - .descr = "setsockopt: no expected_attach_type", - .insns = { - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = 0, - .error = DENY_LOAD, - }, - { - .descr = "setsockopt: wrong expected_attach_type", - .insns = { - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - .error = DENY_ATTACH, - }, - { - .descr = "setsockopt: bypass bpf hook", - .insns = { - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .get_level = SOL_IP, - .set_level = SOL_IP, - - .get_optname = IP_TOS, - .set_optname = IP_TOS, - - .set_optval = { 1 << 3 }, - .set_optlen = 1, - - .get_optval = { 1 << 3 }, - .get_optlen = 1, - }, - { - .descr = "setsockopt: return EPERM from bpf hook", - .insns = { - /* return 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .set_level = SOL_IP, - .set_optname = IP_TOS, - - .set_optlen = 1, - .error = EPERM_SETSOCKOPT, - }, - { - .descr = "setsockopt: no optval bounds check, deny loading", - .insns = { - /* r6 = ctx->optval */ - BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, optval)), - - /* r0 = ctx->optval[0] */ - BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, 0), - - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - .error = DENY_LOAD, - }, - { - .descr = "setsockopt: read ctx->level", - .insns = { - /* r6 = ctx->level */ - BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, level)), - - /* if (ctx->level == 123) { */ - BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4), - /* ctx->optlen = -1 */ - BPF_MOV64_IMM(BPF_REG_0, -1), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optlen)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_JMP_A(1), - /* } else { */ - /* return 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - /* } */ - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .set_level = 123, - - .set_optlen = 1, - }, - { - .descr = "setsockopt: allow changing ctx->level", - .insns = { - /* ctx->level = SOL_IP */ - BPF_MOV64_IMM(BPF_REG_0, SOL_IP), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, level)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .get_level = SOL_IP, - .set_level = 234, /* should be rewritten to SOL_IP */ - - .get_optname = IP_TOS, - .set_optname = IP_TOS, - - .set_optval = { 1 << 3 }, - .set_optlen = 1, - .get_optval = { 1 << 3 }, - .get_optlen = 1, - }, - { - .descr = "setsockopt: read ctx->optname", - .insns = { - /* r6 = ctx->optname */ - BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, optname)), - - /* if (ctx->optname == 123) { */ - BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 123, 4), - /* ctx->optlen = -1 */ - BPF_MOV64_IMM(BPF_REG_0, -1), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optlen)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_JMP_A(1), - /* } else { */ - /* return 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - /* } */ - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .set_optname = 123, - - .set_optlen = 1, - }, - { - .descr = "setsockopt: allow changing ctx->optname", - .insns = { - /* ctx->optname = IP_TOS */ - BPF_MOV64_IMM(BPF_REG_0, IP_TOS), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optname)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .get_level = SOL_IP, - .set_level = SOL_IP, - - .get_optname = IP_TOS, - .set_optname = 456, /* should be rewritten to IP_TOS */ - - .set_optval = { 1 << 3 }, - .set_optlen = 1, - .get_optval = { 1 << 3 }, - .get_optlen = 1, - }, - { - .descr = "setsockopt: read ctx->optlen", - .insns = { - /* r6 = ctx->optlen */ - BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, optlen)), - - /* if (ctx->optlen == 64) { */ - BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 64, 4), - /* ctx->optlen = -1 */ - BPF_MOV64_IMM(BPF_REG_0, -1), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optlen)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_JMP_A(1), - /* } else { */ - /* return 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - /* } */ - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .set_optlen = 64, - }, - { - .descr = "setsockopt: ctx->optlen == -1 is ok", - .insns = { - /* ctx->optlen = -1 */ - BPF_MOV64_IMM(BPF_REG_0, -1), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optlen)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .set_optlen = 64, - }, - { - .descr = "setsockopt: deny ctx->optlen < 0 (except -1)", - .insns = { - /* ctx->optlen = -2 */ - BPF_MOV64_IMM(BPF_REG_0, -2), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optlen)), - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .set_optlen = 4, - - .error = EFAULT_SETSOCKOPT, - }, - { - .descr = "setsockopt: deny ctx->optlen > input optlen", - .insns = { - /* ctx->optlen = 65 */ - BPF_MOV64_IMM(BPF_REG_0, 65), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optlen)), - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .set_optlen = 64, - - .error = EFAULT_SETSOCKOPT, - }, - { - .descr = "setsockopt: allow changing ctx->optlen within bounds", - .insns = { - /* r6 = ctx->optval */ - BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, optval)), - /* r2 = ctx->optval */ - BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), - /* r6 = ctx->optval + 1 */ - BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), - - /* r7 = ctx->optval_end */ - BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1, - offsetof(struct bpf_sockopt, optval_end)), - - /* if (ctx->optval + 1 <= ctx->optval_end) { */ - BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1), - /* ctx->optval[0] = 1 << 3 */ - BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 1 << 3), - /* } */ - - /* ctx->optlen = 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optlen)), - - /* return 1*/ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .get_level = SOL_IP, - .set_level = SOL_IP, - - .get_optname = IP_TOS, - .set_optname = IP_TOS, - - .set_optval = { 1, 1, 1, 1 }, - .set_optlen = 4, - .get_optval = { 1 << 3 }, - .get_optlen = 1, - }, - { - .descr = "setsockopt: deny write ctx->retval", - .insns = { - /* ctx->retval = 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, retval)), - - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .error = DENY_LOAD, - }, - { - .descr = "setsockopt: deny read ctx->retval", - .insns = { - /* r6 = ctx->retval */ - BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, retval)), - - /* return 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .error = DENY_LOAD, - }, - { - .descr = "setsockopt: deny writing to ctx->optval", - .insns = { - /* ctx->optval = 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optval)), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .error = DENY_LOAD, - }, - { - .descr = "setsockopt: deny writing to ctx->optval_end", - .insns = { - /* ctx->optval_end = 1 */ - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, - offsetof(struct bpf_sockopt, optval_end)), - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .error = DENY_LOAD, - }, - { - .descr = "setsockopt: allow IP_TOS <= 128", - .insns = { - /* r6 = ctx->optval */ - BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, optval)), - /* r7 = ctx->optval + 1 */ - BPF_MOV64_REG(BPF_REG_7, BPF_REG_6), - BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1), - - /* r8 = ctx->optval_end */ - BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1, - offsetof(struct bpf_sockopt, optval_end)), - - /* if (ctx->optval + 1 <= ctx->optval_end) { */ - BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4), - - /* r9 = ctx->optval[0] */ - BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0), - - /* if (ctx->optval[0] < 128) */ - BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2), - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_JMP_A(1), - /* } */ - - /* } else { */ - BPF_MOV64_IMM(BPF_REG_0, 0), - /* } */ - - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .get_level = SOL_IP, - .set_level = SOL_IP, - - .get_optname = IP_TOS, - .set_optname = IP_TOS, - - .set_optval = { 0x80 }, - .set_optlen = 1, - .get_optval = { 0x80 }, - .get_optlen = 1, - }, - { - .descr = "setsockopt: deny IP_TOS > 128", - .insns = { - /* r6 = ctx->optval */ - BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, - offsetof(struct bpf_sockopt, optval)), - /* r7 = ctx->optval + 1 */ - BPF_MOV64_REG(BPF_REG_7, BPF_REG_6), - BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1), - - /* r8 = ctx->optval_end */ - BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_1, - offsetof(struct bpf_sockopt, optval_end)), - - /* if (ctx->optval + 1 <= ctx->optval_end) { */ - BPF_JMP_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 4), - - /* r9 = ctx->optval[0] */ - BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_6, 0), - - /* if (ctx->optval[0] < 128) */ - BPF_JMP_IMM(BPF_JGT, BPF_REG_9, 128, 2), - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_JMP_A(1), - /* } */ - - /* } else { */ - BPF_MOV64_IMM(BPF_REG_0, 0), - /* } */ - - BPF_EXIT_INSN(), - }, - .attach_type = BPF_CGROUP_SETSOCKOPT, - .expected_attach_type = BPF_CGROUP_SETSOCKOPT, - - .get_level = SOL_IP, - .set_level = SOL_IP, - - .get_optname = IP_TOS, - .set_optname = IP_TOS, - - .set_optval = { 0x81 }, - .set_optlen = 1, - .get_optval = { 0x00 }, - .get_optlen = 1, - - .error = EPERM_SETSOCKOPT, - }, -}; - -static int load_prog(const struct bpf_insn *insns, - enum bpf_attach_type expected_attach_type) -{ - struct bpf_load_program_attr attr = { - .prog_type = BPF_PROG_TYPE_CGROUP_SOCKOPT, - .expected_attach_type = expected_attach_type, - .insns = insns, - .license = "GPL", - .log_level = 2, - }; - int fd; - - for (; - insns[attr.insns_cnt].code != (BPF_JMP | BPF_EXIT); - attr.insns_cnt++) { - } - attr.insns_cnt++; - - fd = bpf_load_program_xattr(&attr, bpf_log_buf, sizeof(bpf_log_buf)); - if (verbose && fd < 0) - fprintf(stderr, "%s\n", bpf_log_buf); - - return fd; -} - -static int run_test(int cgroup_fd, struct sockopt_test *test) -{ - int sock_fd, err, prog_fd; - void *optval = NULL; - int ret = 0; - - prog_fd = load_prog(test->insns, test->expected_attach_type); - if (prog_fd < 0) { - if (test->error == DENY_LOAD) - return 0; - - log_err("Failed to load BPF program"); - return -1; - } - - err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0); - if (err < 0) { - if (test->error == DENY_ATTACH) - goto close_prog_fd; - - log_err("Failed to attach BPF program"); - ret = -1; - goto close_prog_fd; - } - - sock_fd = socket(AF_INET, SOCK_STREAM, 0); - if (sock_fd < 0) { - log_err("Failed to create AF_INET socket"); - ret = -1; - goto detach_prog; - } - - if (test->set_optlen) { - err = setsockopt(sock_fd, test->set_level, test->set_optname, - test->set_optval, test->set_optlen); - if (err) { - if (errno == EPERM && test->error == EPERM_SETSOCKOPT) - goto close_sock_fd; - if (errno == EFAULT && test->error == EFAULT_SETSOCKOPT) - goto free_optval; - - log_err("Failed to call setsockopt"); - ret = -1; - goto close_sock_fd; - } - } - - if (test->get_optlen) { - optval = malloc(test->get_optlen); - socklen_t optlen = test->get_optlen; - socklen_t expected_get_optlen = test->get_optlen_ret ?: - test->get_optlen; - - err = getsockopt(sock_fd, test->get_level, test->get_optname, - optval, &optlen); - if (err) { - if (errno == EPERM && test->error == EPERM_GETSOCKOPT) - goto free_optval; - if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT) - goto free_optval; - - log_err("Failed to call getsockopt"); - ret = -1; - goto free_optval; - } - - if (optlen != expected_get_optlen) { - errno = 0; - log_err("getsockopt returned unexpected optlen"); - ret = -1; - goto free_optval; - } - - if (memcmp(optval, test->get_optval, optlen) != 0) { - errno = 0; - log_err("getsockopt returned unexpected optval"); - ret = -1; - goto free_optval; - } - } - - ret = test->error != OK; - -free_optval: - free(optval); -close_sock_fd: - close(sock_fd); -detach_prog: - bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type); -close_prog_fd: - close(prog_fd); - return ret; -} - -int main(int args, char **argv) -{ - int err = EXIT_FAILURE, error_cnt = 0; - int cgroup_fd, i; - - if (setup_cgroup_environment()) - goto cleanup_obj; - - cgroup_fd = create_and_get_cgroup(CG_PATH); - if (cgroup_fd < 0) - goto cleanup_cgroup_env; - - if (join_cgroup(CG_PATH)) - goto cleanup_cgroup; - - for (i = 0; i < ARRAY_SIZE(tests); i++) { - int err = run_test(cgroup_fd, &tests[i]); - - if (err) - error_cnt++; - - printf("#%d %s: %s\n", i, err ? "FAIL" : "PASS", - tests[i].descr); - } - - printf("Summary: %ld PASSED, %d FAILED\n", - ARRAY_SIZE(tests) - error_cnt, error_cnt); - err = error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; - -cleanup_cgroup: - close(cgroup_fd); -cleanup_cgroup_env: - cleanup_cgroup_environment(); -cleanup_obj: - return err; -} -- cgit v1.2.3 From 9a365e67d8bbcfff47063a4eeaa98fd3668e223a Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Wed, 4 Sep 2019 09:25:06 -0700 Subject: selftests/bpf: test_progs: convert test_sockopt_sk Move the files, adjust includes, remove entry from Makefile & .gitignore Signed-off-by: Stanislav Fomichev Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/.gitignore | 1 - tools/testing/selftests/bpf/Makefile | 3 +- .../testing/selftests/bpf/prog_tests/sockopt_sk.c | 200 +++++++++++++++++ tools/testing/selftests/bpf/test_progs.h | 3 +- tools/testing/selftests/bpf/test_sockopt_sk.c | 236 --------------------- 5 files changed, 203 insertions(+), 240 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/sockopt_sk.c delete mode 100644 tools/testing/selftests/bpf/test_sockopt_sk.c diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 0315120eac8f..bc83c1a7ea1b 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -39,7 +39,6 @@ libbpf.so.* test_hashmap test_btf_dump xdping -test_sockopt_sk test_sockopt_multi test_sockopt_inherit test_tcp_rtt diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 7151cbc4676e..32a54b71d30d 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -28,7 +28,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test test_sock test_btf test_sockmap get_cgroup_id_user test_socket_cookie \ test_cgroup_storage test_select_reuseport test_section_names \ test_netcnt test_tcpnotify_user test_sock_fields test_sysctl test_hashmap \ - test_btf_dump test_cgroup_attach xdping test_sockopt_sk \ + test_btf_dump test_cgroup_attach xdping \ test_sockopt_multi test_sockopt_inherit test_tcp_rtt BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c))) @@ -113,7 +113,6 @@ $(OUTPUT)/test_netcnt: cgroup_helpers.c $(OUTPUT)/test_sock_fields: cgroup_helpers.c $(OUTPUT)/test_sysctl: cgroup_helpers.c $(OUTPUT)/test_cgroup_attach: cgroup_helpers.c -$(OUTPUT)/test_sockopt_sk: cgroup_helpers.c $(OUTPUT)/test_sockopt_multi: cgroup_helpers.c $(OUTPUT)/test_sockopt_inherit: cgroup_helpers.c $(OUTPUT)/test_tcp_rtt: cgroup_helpers.c diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt_sk.c b/tools/testing/selftests/bpf/prog_tests/sockopt_sk.c new file mode 100644 index 000000000000..2061a6beac0f --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/sockopt_sk.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "cgroup_helpers.h" + +#define SOL_CUSTOM 0xdeadbeef + +static int getsetsockopt(void) +{ + int fd, err; + union { + char u8[4]; + __u32 u32; + char cc[16]; /* TCP_CA_NAME_MAX */ + } buf = {}; + socklen_t optlen; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + log_err("Failed to create socket"); + return -1; + } + + /* IP_TOS - BPF bypass */ + + buf.u8[0] = 0x08; + err = setsockopt(fd, SOL_IP, IP_TOS, &buf, 1); + if (err) { + log_err("Failed to call setsockopt(IP_TOS)"); + goto err; + } + + buf.u8[0] = 0x00; + optlen = 1; + err = getsockopt(fd, SOL_IP, IP_TOS, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt(IP_TOS)"); + goto err; + } + + if (buf.u8[0] != 0x08) { + log_err("Unexpected getsockopt(IP_TOS) buf[0] 0x%02x != 0x08", + buf.u8[0]); + goto err; + } + + /* IP_TTL - EPERM */ + + buf.u8[0] = 1; + err = setsockopt(fd, SOL_IP, IP_TTL, &buf, 1); + if (!err || errno != EPERM) { + log_err("Unexpected success from setsockopt(IP_TTL)"); + goto err; + } + + /* SOL_CUSTOM - handled by BPF */ + + buf.u8[0] = 0x01; + err = setsockopt(fd, SOL_CUSTOM, 0, &buf, 1); + if (err) { + log_err("Failed to call setsockopt"); + goto err; + } + + buf.u32 = 0x00; + optlen = 4; + err = getsockopt(fd, SOL_CUSTOM, 0, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt"); + goto err; + } + + if (optlen != 1) { + log_err("Unexpected optlen %d != 1", optlen); + goto err; + } + if (buf.u8[0] != 0x01) { + log_err("Unexpected buf[0] 0x%02x != 0x01", buf.u8[0]); + goto err; + } + + /* SO_SNDBUF is overwritten */ + + buf.u32 = 0x01010101; + err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, 4); + if (err) { + log_err("Failed to call setsockopt(SO_SNDBUF)"); + goto err; + } + + buf.u32 = 0x00; + optlen = 4; + err = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt(SO_SNDBUF)"); + goto err; + } + + if (buf.u32 != 0x55AA*2) { + log_err("Unexpected getsockopt(SO_SNDBUF) 0x%x != 0x55AA*2", + buf.u32); + goto err; + } + + /* TCP_CONGESTION can extend the string */ + + strcpy(buf.cc, "nv"); + err = setsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, strlen("nv")); + if (err) { + log_err("Failed to call setsockopt(TCP_CONGESTION)"); + goto err; + } + + + optlen = sizeof(buf.cc); + err = getsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt(TCP_CONGESTION)"); + goto err; + } + + if (strcmp(buf.cc, "cubic") != 0) { + log_err("Unexpected getsockopt(TCP_CONGESTION) %s != %s", + buf.cc, "cubic"); + goto err; + } + + close(fd); + return 0; +err: + close(fd); + return -1; +} + +static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title) +{ + enum bpf_attach_type attach_type; + enum bpf_prog_type prog_type; + struct bpf_program *prog; + int err; + + err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); + if (err) { + log_err("Failed to deduct types for %s BPF program", title); + return -1; + } + + prog = bpf_object__find_program_by_title(obj, title); + if (!prog) { + log_err("Failed to find %s BPF program", title); + return -1; + } + + err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, + attach_type, 0); + if (err) { + log_err("Failed to attach %s BPF program", title); + return -1; + } + + return 0; +} + +static void run_test(int cgroup_fd) +{ + struct bpf_prog_load_attr attr = { + .file = "./sockopt_sk.o", + }; + struct bpf_object *obj; + int ignored; + int err; + + err = bpf_prog_load_xattr(&attr, &obj, &ignored); + if (CHECK_FAIL(err)) + return; + + err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt"); + if (CHECK_FAIL(err)) + goto close_bpf_object; + + err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt"); + if (CHECK_FAIL(err)) + goto close_bpf_object; + + CHECK_FAIL(getsetsockopt()); + +close_bpf_object: + bpf_object__close(obj); +} + +void test_sockopt_sk(void) +{ + int cgroup_fd; + + cgroup_fd = test__join_cgroup("/sockopt_sk"); + if (CHECK_FAIL(cgroup_fd < 0)) + return; + + run_test(cgroup_fd); + close(cgroup_fd); +} diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h index e518bd5da3e2..0c48f64f732b 100644 --- a/tools/testing/selftests/bpf/test_progs.h +++ b/tools/testing/selftests/bpf/test_progs.h @@ -16,9 +16,10 @@ typedef __u16 __sum16; #include #include #include -#include +#include #include #include +#include #include #include diff --git a/tools/testing/selftests/bpf/test_sockopt_sk.c b/tools/testing/selftests/bpf/test_sockopt_sk.c deleted file mode 100644 index e4f6055d92e9..000000000000 --- a/tools/testing/selftests/bpf/test_sockopt_sk.c +++ /dev/null @@ -1,236 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "bpf_rlimit.h" -#include "bpf_util.h" -#include "cgroup_helpers.h" - -#define CG_PATH "/sockopt" - -#define SOL_CUSTOM 0xdeadbeef - -static int getsetsockopt(void) -{ - int fd, err; - union { - char u8[4]; - __u32 u32; - char cc[16]; /* TCP_CA_NAME_MAX */ - } buf = {}; - socklen_t optlen; - - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd < 0) { - log_err("Failed to create socket"); - return -1; - } - - /* IP_TOS - BPF bypass */ - - buf.u8[0] = 0x08; - err = setsockopt(fd, SOL_IP, IP_TOS, &buf, 1); - if (err) { - log_err("Failed to call setsockopt(IP_TOS)"); - goto err; - } - - buf.u8[0] = 0x00; - optlen = 1; - err = getsockopt(fd, SOL_IP, IP_TOS, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt(IP_TOS)"); - goto err; - } - - if (buf.u8[0] != 0x08) { - log_err("Unexpected getsockopt(IP_TOS) buf[0] 0x%02x != 0x08", - buf.u8[0]); - goto err; - } - - /* IP_TTL - EPERM */ - - buf.u8[0] = 1; - err = setsockopt(fd, SOL_IP, IP_TTL, &buf, 1); - if (!err || errno != EPERM) { - log_err("Unexpected success from setsockopt(IP_TTL)"); - goto err; - } - - /* SOL_CUSTOM - handled by BPF */ - - buf.u8[0] = 0x01; - err = setsockopt(fd, SOL_CUSTOM, 0, &buf, 1); - if (err) { - log_err("Failed to call setsockopt"); - goto err; - } - - buf.u32 = 0x00; - optlen = 4; - err = getsockopt(fd, SOL_CUSTOM, 0, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt"); - goto err; - } - - if (optlen != 1) { - log_err("Unexpected optlen %d != 1", optlen); - goto err; - } - if (buf.u8[0] != 0x01) { - log_err("Unexpected buf[0] 0x%02x != 0x01", buf.u8[0]); - goto err; - } - - /* SO_SNDBUF is overwritten */ - - buf.u32 = 0x01010101; - err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, 4); - if (err) { - log_err("Failed to call setsockopt(SO_SNDBUF)"); - goto err; - } - - buf.u32 = 0x00; - optlen = 4; - err = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt(SO_SNDBUF)"); - goto err; - } - - if (buf.u32 != 0x55AA*2) { - log_err("Unexpected getsockopt(SO_SNDBUF) 0x%x != 0x55AA*2", - buf.u32); - goto err; - } - - /* TCP_CONGESTION can extend the string */ - - strcpy(buf.cc, "nv"); - err = setsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, strlen("nv")); - if (err) { - log_err("Failed to call setsockopt(TCP_CONGESTION)"); - goto err; - } - - - optlen = sizeof(buf.cc); - err = getsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt(TCP_CONGESTION)"); - goto err; - } - - if (strcmp(buf.cc, "cubic") != 0) { - log_err("Unexpected getsockopt(TCP_CONGESTION) %s != %s", - buf.cc, "cubic"); - goto err; - } - - close(fd); - return 0; -err: - close(fd); - return -1; -} - -static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title) -{ - enum bpf_attach_type attach_type; - enum bpf_prog_type prog_type; - struct bpf_program *prog; - int err; - - err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); - if (err) { - log_err("Failed to deduct types for %s BPF program", title); - return -1; - } - - prog = bpf_object__find_program_by_title(obj, title); - if (!prog) { - log_err("Failed to find %s BPF program", title); - return -1; - } - - err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, - attach_type, 0); - if (err) { - log_err("Failed to attach %s BPF program", title); - return -1; - } - - return 0; -} - -static int run_test(int cgroup_fd) -{ - struct bpf_prog_load_attr attr = { - .file = "./sockopt_sk.o", - }; - struct bpf_object *obj; - int ignored; - int err; - - err = bpf_prog_load_xattr(&attr, &obj, &ignored); - if (err) { - log_err("Failed to load BPF object"); - return -1; - } - - err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt"); - if (err) - goto close_bpf_object; - - err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt"); - if (err) - goto close_bpf_object; - - err = getsetsockopt(); - -close_bpf_object: - bpf_object__close(obj); - return err; -} - -int main(int args, char **argv) -{ - int cgroup_fd; - int err = EXIT_SUCCESS; - - if (setup_cgroup_environment()) - goto cleanup_obj; - - cgroup_fd = create_and_get_cgroup(CG_PATH); - if (cgroup_fd < 0) - goto cleanup_cgroup_env; - - if (join_cgroup(CG_PATH)) - goto cleanup_cgroup; - - if (run_test(cgroup_fd)) - err = EXIT_FAILURE; - - printf("test_sockopt_sk: %s\n", - err == EXIT_SUCCESS ? "PASSED" : "FAILED"); - -cleanup_cgroup: - close(cgroup_fd); -cleanup_cgroup_env: - cleanup_cgroup_environment(); -cleanup_obj: - return err; -} -- cgit v1.2.3 From 3886bd7c9b01317a5721161f8314f6c25f4f6229 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Wed, 4 Sep 2019 09:25:07 -0700 Subject: selftests/bpf: test_progs: convert test_sockopt_multi Move the files, adjust includes, remove entry from Makefile & .gitignore Signed-off-by: Stanislav Fomichev Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/.gitignore | 1 - tools/testing/selftests/bpf/Makefile | 3 +- .../selftests/bpf/prog_tests/sockopt_multi.c | 332 ++++++++++++++++++ tools/testing/selftests/bpf/test_sockopt_multi.c | 374 --------------------- 4 files changed, 333 insertions(+), 377 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/sockopt_multi.c delete mode 100644 tools/testing/selftests/bpf/test_sockopt_multi.c diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index bc83c1a7ea1b..4143add5a11e 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -39,6 +39,5 @@ libbpf.so.* test_hashmap test_btf_dump xdping -test_sockopt_multi test_sockopt_inherit test_tcp_rtt diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 32a54b71d30d..0ab9642c4f5e 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -29,7 +29,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test test_cgroup_storage test_select_reuseport test_section_names \ test_netcnt test_tcpnotify_user test_sock_fields test_sysctl test_hashmap \ test_btf_dump test_cgroup_attach xdping \ - test_sockopt_multi test_sockopt_inherit test_tcp_rtt + test_sockopt_inherit test_tcp_rtt BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c))) TEST_GEN_FILES = $(BPF_OBJ_FILES) @@ -113,7 +113,6 @@ $(OUTPUT)/test_netcnt: cgroup_helpers.c $(OUTPUT)/test_sock_fields: cgroup_helpers.c $(OUTPUT)/test_sysctl: cgroup_helpers.c $(OUTPUT)/test_cgroup_attach: cgroup_helpers.c -$(OUTPUT)/test_sockopt_multi: cgroup_helpers.c $(OUTPUT)/test_sockopt_inherit: cgroup_helpers.c $(OUTPUT)/test_tcp_rtt: cgroup_helpers.c diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c b/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c new file mode 100644 index 000000000000..29188d6f5c8d --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "cgroup_helpers.h" + +static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title) +{ + enum bpf_attach_type attach_type; + enum bpf_prog_type prog_type; + struct bpf_program *prog; + int err; + + err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); + if (err) { + log_err("Failed to deduct types for %s BPF program", title); + return -1; + } + + prog = bpf_object__find_program_by_title(obj, title); + if (!prog) { + log_err("Failed to find %s BPF program", title); + return -1; + } + + err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, + attach_type, BPF_F_ALLOW_MULTI); + if (err) { + log_err("Failed to attach %s BPF program", title); + return -1; + } + + return 0; +} + +static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title) +{ + enum bpf_attach_type attach_type; + enum bpf_prog_type prog_type; + struct bpf_program *prog; + int err; + + err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); + if (err) + return -1; + + prog = bpf_object__find_program_by_title(obj, title); + if (!prog) + return -1; + + err = bpf_prog_detach2(bpf_program__fd(prog), cgroup_fd, + attach_type); + if (err) + return -1; + + return 0; +} + +static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, + int cg_child, int sock_fd) +{ + socklen_t optlen; + __u8 buf; + int err; + + /* Set IP_TOS to the expected value (0x80). */ + + buf = 0x80; + err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); + if (err < 0) { + log_err("Failed to call setsockopt(IP_TOS)"); + goto detach; + } + + buf = 0x00; + optlen = 1; + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt(IP_TOS)"); + goto detach; + } + + if (buf != 0x80) { + log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf); + err = -1; + goto detach; + } + + /* Attach child program and make sure it returns new value: + * - kernel: -> 0x80 + * - child: 0x80 -> 0x90 + */ + + err = prog_attach(obj, cg_child, "cgroup/getsockopt/child"); + if (err) + goto detach; + + buf = 0x00; + optlen = 1; + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt(IP_TOS)"); + goto detach; + } + + if (buf != 0x90) { + log_err("Unexpected getsockopt 0x%x != 0x90", buf); + err = -1; + goto detach; + } + + /* Attach parent program and make sure it returns new value: + * - kernel: -> 0x80 + * - child: 0x80 -> 0x90 + * - parent: 0x90 -> 0xA0 + */ + + err = prog_attach(obj, cg_parent, "cgroup/getsockopt/parent"); + if (err) + goto detach; + + buf = 0x00; + optlen = 1; + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt(IP_TOS)"); + goto detach; + } + + if (buf != 0xA0) { + log_err("Unexpected getsockopt 0x%x != 0xA0", buf); + err = -1; + goto detach; + } + + /* Setting unexpected initial sockopt should return EPERM: + * - kernel: -> 0x40 + * - child: unexpected 0x40, EPERM + * - parent: unexpected 0x40, EPERM + */ + + buf = 0x40; + if (setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1) < 0) { + log_err("Failed to call setsockopt(IP_TOS)"); + goto detach; + } + + buf = 0x00; + optlen = 1; + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); + if (!err) { + log_err("Unexpected success from getsockopt(IP_TOS)"); + goto detach; + } + + /* Detach child program and make sure we still get EPERM: + * - kernel: -> 0x40 + * - parent: unexpected 0x40, EPERM + */ + + err = prog_detach(obj, cg_child, "cgroup/getsockopt/child"); + if (err) { + log_err("Failed to detach child program"); + goto detach; + } + + buf = 0x00; + optlen = 1; + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); + if (!err) { + log_err("Unexpected success from getsockopt(IP_TOS)"); + goto detach; + } + + /* Set initial value to the one the parent program expects: + * - kernel: -> 0x90 + * - parent: 0x90 -> 0xA0 + */ + + buf = 0x90; + err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); + if (err < 0) { + log_err("Failed to call setsockopt(IP_TOS)"); + goto detach; + } + + buf = 0x00; + optlen = 1; + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt(IP_TOS)"); + goto detach; + } + + if (buf != 0xA0) { + log_err("Unexpected getsockopt 0x%x != 0xA0", buf); + err = -1; + goto detach; + } + +detach: + prog_detach(obj, cg_child, "cgroup/getsockopt/child"); + prog_detach(obj, cg_parent, "cgroup/getsockopt/parent"); + + return err; +} + +static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, + int cg_child, int sock_fd) +{ + socklen_t optlen; + __u8 buf; + int err; + + /* Set IP_TOS to the expected value (0x80). */ + + buf = 0x80; + err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); + if (err < 0) { + log_err("Failed to call setsockopt(IP_TOS)"); + goto detach; + } + + buf = 0x00; + optlen = 1; + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt(IP_TOS)"); + goto detach; + } + + if (buf != 0x80) { + log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf); + err = -1; + goto detach; + } + + /* Attach child program and make sure it adds 0x10. */ + + err = prog_attach(obj, cg_child, "cgroup/setsockopt"); + if (err) + goto detach; + + buf = 0x80; + err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); + if (err < 0) { + log_err("Failed to call setsockopt(IP_TOS)"); + goto detach; + } + + buf = 0x00; + optlen = 1; + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt(IP_TOS)"); + goto detach; + } + + if (buf != 0x80 + 0x10) { + log_err("Unexpected getsockopt 0x%x != 0x80 + 0x10", buf); + err = -1; + goto detach; + } + + /* Attach parent program and make sure it adds another 0x10. */ + + err = prog_attach(obj, cg_parent, "cgroup/setsockopt"); + if (err) + goto detach; + + buf = 0x80; + err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); + if (err < 0) { + log_err("Failed to call setsockopt(IP_TOS)"); + goto detach; + } + + buf = 0x00; + optlen = 1; + err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); + if (err) { + log_err("Failed to call getsockopt(IP_TOS)"); + goto detach; + } + + if (buf != 0x80 + 2 * 0x10) { + log_err("Unexpected getsockopt 0x%x != 0x80 + 2 * 0x10", buf); + err = -1; + goto detach; + } + +detach: + prog_detach(obj, cg_child, "cgroup/setsockopt"); + prog_detach(obj, cg_parent, "cgroup/setsockopt"); + + return err; +} + +void test_sockopt_multi(void) +{ + struct bpf_prog_load_attr attr = { + .file = "./sockopt_multi.o", + }; + int cg_parent = -1, cg_child = -1; + struct bpf_object *obj = NULL; + int sock_fd = -1; + int err = -1; + int ignored; + + cg_parent = test__join_cgroup("/parent"); + if (CHECK_FAIL(cg_parent < 0)) + goto out; + + cg_child = test__join_cgroup("/parent/child"); + if (CHECK_FAIL(cg_child < 0)) + goto out; + + err = bpf_prog_load_xattr(&attr, &obj, &ignored); + if (CHECK_FAIL(err)) + goto out; + + sock_fd = socket(AF_INET, SOCK_STREAM, 0); + if (CHECK_FAIL(sock_fd < 0)) + goto out; + + CHECK_FAIL(run_getsockopt_test(obj, cg_parent, cg_child, sock_fd)); + CHECK_FAIL(run_setsockopt_test(obj, cg_parent, cg_child, sock_fd)); + +out: + close(sock_fd); + bpf_object__close(obj); + close(cg_child); + close(cg_parent); +} diff --git a/tools/testing/selftests/bpf/test_sockopt_multi.c b/tools/testing/selftests/bpf/test_sockopt_multi.c deleted file mode 100644 index 4be3441db867..000000000000 --- a/tools/testing/selftests/bpf/test_sockopt_multi.c +++ /dev/null @@ -1,374 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "bpf_rlimit.h" -#include "bpf_util.h" -#include "cgroup_helpers.h" - -static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title) -{ - enum bpf_attach_type attach_type; - enum bpf_prog_type prog_type; - struct bpf_program *prog; - int err; - - err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); - if (err) { - log_err("Failed to deduct types for %s BPF program", title); - return -1; - } - - prog = bpf_object__find_program_by_title(obj, title); - if (!prog) { - log_err("Failed to find %s BPF program", title); - return -1; - } - - err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, - attach_type, BPF_F_ALLOW_MULTI); - if (err) { - log_err("Failed to attach %s BPF program", title); - return -1; - } - - return 0; -} - -static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title) -{ - enum bpf_attach_type attach_type; - enum bpf_prog_type prog_type; - struct bpf_program *prog; - int err; - - err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); - if (err) - return -1; - - prog = bpf_object__find_program_by_title(obj, title); - if (!prog) - return -1; - - err = bpf_prog_detach2(bpf_program__fd(prog), cgroup_fd, - attach_type); - if (err) - return -1; - - return 0; -} - -static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, - int cg_child, int sock_fd) -{ - socklen_t optlen; - __u8 buf; - int err; - - /* Set IP_TOS to the expected value (0x80). */ - - buf = 0x80; - err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); - if (err < 0) { - log_err("Failed to call setsockopt(IP_TOS)"); - goto detach; - } - - buf = 0x00; - optlen = 1; - err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt(IP_TOS)"); - goto detach; - } - - if (buf != 0x80) { - log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf); - err = -1; - goto detach; - } - - /* Attach child program and make sure it returns new value: - * - kernel: -> 0x80 - * - child: 0x80 -> 0x90 - */ - - err = prog_attach(obj, cg_child, "cgroup/getsockopt/child"); - if (err) - goto detach; - - buf = 0x00; - optlen = 1; - err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt(IP_TOS)"); - goto detach; - } - - if (buf != 0x90) { - log_err("Unexpected getsockopt 0x%x != 0x90", buf); - err = -1; - goto detach; - } - - /* Attach parent program and make sure it returns new value: - * - kernel: -> 0x80 - * - child: 0x80 -> 0x90 - * - parent: 0x90 -> 0xA0 - */ - - err = prog_attach(obj, cg_parent, "cgroup/getsockopt/parent"); - if (err) - goto detach; - - buf = 0x00; - optlen = 1; - err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt(IP_TOS)"); - goto detach; - } - - if (buf != 0xA0) { - log_err("Unexpected getsockopt 0x%x != 0xA0", buf); - err = -1; - goto detach; - } - - /* Setting unexpected initial sockopt should return EPERM: - * - kernel: -> 0x40 - * - child: unexpected 0x40, EPERM - * - parent: unexpected 0x40, EPERM - */ - - buf = 0x40; - if (setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1) < 0) { - log_err("Failed to call setsockopt(IP_TOS)"); - goto detach; - } - - buf = 0x00; - optlen = 1; - err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); - if (!err) { - log_err("Unexpected success from getsockopt(IP_TOS)"); - goto detach; - } - - /* Detach child program and make sure we still get EPERM: - * - kernel: -> 0x40 - * - parent: unexpected 0x40, EPERM - */ - - err = prog_detach(obj, cg_child, "cgroup/getsockopt/child"); - if (err) { - log_err("Failed to detach child program"); - goto detach; - } - - buf = 0x00; - optlen = 1; - err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); - if (!err) { - log_err("Unexpected success from getsockopt(IP_TOS)"); - goto detach; - } - - /* Set initial value to the one the parent program expects: - * - kernel: -> 0x90 - * - parent: 0x90 -> 0xA0 - */ - - buf = 0x90; - err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); - if (err < 0) { - log_err("Failed to call setsockopt(IP_TOS)"); - goto detach; - } - - buf = 0x00; - optlen = 1; - err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt(IP_TOS)"); - goto detach; - } - - if (buf != 0xA0) { - log_err("Unexpected getsockopt 0x%x != 0xA0", buf); - err = -1; - goto detach; - } - -detach: - prog_detach(obj, cg_child, "cgroup/getsockopt/child"); - prog_detach(obj, cg_parent, "cgroup/getsockopt/parent"); - - return err; -} - -static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, - int cg_child, int sock_fd) -{ - socklen_t optlen; - __u8 buf; - int err; - - /* Set IP_TOS to the expected value (0x80). */ - - buf = 0x80; - err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); - if (err < 0) { - log_err("Failed to call setsockopt(IP_TOS)"); - goto detach; - } - - buf = 0x00; - optlen = 1; - err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt(IP_TOS)"); - goto detach; - } - - if (buf != 0x80) { - log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf); - err = -1; - goto detach; - } - - /* Attach child program and make sure it adds 0x10. */ - - err = prog_attach(obj, cg_child, "cgroup/setsockopt"); - if (err) - goto detach; - - buf = 0x80; - err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); - if (err < 0) { - log_err("Failed to call setsockopt(IP_TOS)"); - goto detach; - } - - buf = 0x00; - optlen = 1; - err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt(IP_TOS)"); - goto detach; - } - - if (buf != 0x80 + 0x10) { - log_err("Unexpected getsockopt 0x%x != 0x80 + 0x10", buf); - err = -1; - goto detach; - } - - /* Attach parent program and make sure it adds another 0x10. */ - - err = prog_attach(obj, cg_parent, "cgroup/setsockopt"); - if (err) - goto detach; - - buf = 0x80; - err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1); - if (err < 0) { - log_err("Failed to call setsockopt(IP_TOS)"); - goto detach; - } - - buf = 0x00; - optlen = 1; - err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen); - if (err) { - log_err("Failed to call getsockopt(IP_TOS)"); - goto detach; - } - - if (buf != 0x80 + 2 * 0x10) { - log_err("Unexpected getsockopt 0x%x != 0x80 + 2 * 0x10", buf); - err = -1; - goto detach; - } - -detach: - prog_detach(obj, cg_child, "cgroup/setsockopt"); - prog_detach(obj, cg_parent, "cgroup/setsockopt"); - - return err; -} - -int main(int argc, char **argv) -{ - struct bpf_prog_load_attr attr = { - .file = "./sockopt_multi.o", - }; - int cg_parent = -1, cg_child = -1; - struct bpf_object *obj = NULL; - int sock_fd = -1; - int err = -1; - int ignored; - - if (setup_cgroup_environment()) { - log_err("Failed to setup cgroup environment\n"); - goto out; - } - - cg_parent = create_and_get_cgroup("/parent"); - if (cg_parent < 0) { - log_err("Failed to create cgroup /parent\n"); - goto out; - } - - cg_child = create_and_get_cgroup("/parent/child"); - if (cg_child < 0) { - log_err("Failed to create cgroup /parent/child\n"); - goto out; - } - - if (join_cgroup("/parent/child")) { - log_err("Failed to join cgroup /parent/child\n"); - goto out; - } - - err = bpf_prog_load_xattr(&attr, &obj, &ignored); - if (err) { - log_err("Failed to load BPF object"); - goto out; - } - - sock_fd = socket(AF_INET, SOCK_STREAM, 0); - if (sock_fd < 0) { - log_err("Failed to create socket"); - goto out; - } - - if (run_getsockopt_test(obj, cg_parent, cg_child, sock_fd)) - err = -1; - printf("test_sockopt_multi: getsockopt %s\n", - err ? "FAILED" : "PASSED"); - - if (run_setsockopt_test(obj, cg_parent, cg_child, sock_fd)) - err = -1; - printf("test_sockopt_multi: setsockopt %s\n", - err ? "FAILED" : "PASSED"); - -out: - close(sock_fd); - bpf_object__close(obj); - close(cg_child); - close(cg_parent); - - printf("test_sockopt_multi: %s\n", err ? "FAILED" : "PASSED"); - return err ? EXIT_FAILURE : EXIT_SUCCESS; -} -- cgit v1.2.3 From e3e02e1d9c24b0c3a36f9c854ae80e61fd62b2a9 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Wed, 4 Sep 2019 09:25:08 -0700 Subject: selftests/bpf: test_progs: convert test_sockopt_inherit Move the files, adjust includes, remove entry from Makefile & .gitignore I also added pthread_cond_wait for the server thread startup. We don't want to connect to the server that's not yet up (for some reason this existing race is now more prominent with test_progs). Signed-off-by: Stanislav Fomichev Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/.gitignore | 1 - tools/testing/selftests/bpf/Makefile | 4 +- .../selftests/bpf/prog_tests/sockopt_inherit.c | 235 +++++++++++++++++++ tools/testing/selftests/bpf/test_sockopt_inherit.c | 253 --------------------- 4 files changed, 236 insertions(+), 257 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c delete mode 100644 tools/testing/selftests/bpf/test_sockopt_inherit.c diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 4143add5a11e..5b06bb45b500 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -39,5 +39,4 @@ libbpf.so.* test_hashmap test_btf_dump xdping -test_sockopt_inherit test_tcp_rtt diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 0ab9642c4f5e..4d9a0304a011 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -28,8 +28,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test test_sock test_btf test_sockmap get_cgroup_id_user test_socket_cookie \ test_cgroup_storage test_select_reuseport test_section_names \ test_netcnt test_tcpnotify_user test_sock_fields test_sysctl test_hashmap \ - test_btf_dump test_cgroup_attach xdping \ - test_sockopt_inherit test_tcp_rtt + test_btf_dump test_cgroup_attach xdping test_tcp_rtt BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c))) TEST_GEN_FILES = $(BPF_OBJ_FILES) @@ -113,7 +112,6 @@ $(OUTPUT)/test_netcnt: cgroup_helpers.c $(OUTPUT)/test_sock_fields: cgroup_helpers.c $(OUTPUT)/test_sysctl: cgroup_helpers.c $(OUTPUT)/test_cgroup_attach: cgroup_helpers.c -$(OUTPUT)/test_sockopt_inherit: cgroup_helpers.c $(OUTPUT)/test_tcp_rtt: cgroup_helpers.c .PHONY: force diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c b/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c new file mode 100644 index 000000000000..6cbeea7b4bf1 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "cgroup_helpers.h" + +#define SOL_CUSTOM 0xdeadbeef +#define CUSTOM_INHERIT1 0 +#define CUSTOM_INHERIT2 1 +#define CUSTOM_LISTENER 2 + +static int connect_to_server(int server_fd) +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + int fd; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + log_err("Failed to create client socket"); + return -1; + } + + if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) { + log_err("Failed to get server addr"); + goto out; + } + + if (connect(fd, (const struct sockaddr *)&addr, len) < 0) { + log_err("Fail to connect to server"); + goto out; + } + + return fd; + +out: + close(fd); + return -1; +} + +static int verify_sockopt(int fd, int optname, const char *msg, char expected) +{ + socklen_t optlen = 1; + char buf = 0; + int err; + + err = getsockopt(fd, SOL_CUSTOM, optname, &buf, &optlen); + if (err) { + log_err("%s: failed to call getsockopt", msg); + return 1; + } + + printf("%s %d: got=0x%x ? expected=0x%x\n", msg, optname, buf, expected); + + if (buf != expected) { + log_err("%s: unexpected getsockopt value %d != %d", msg, + buf, expected); + return 1; + } + + return 0; +} + +static pthread_mutex_t server_started_mtx = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t server_started = PTHREAD_COND_INITIALIZER; + +static void *server_thread(void *arg) +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + int fd = *(int *)arg; + int client_fd; + int err = 0; + + err = listen(fd, 1); + + pthread_mutex_lock(&server_started_mtx); + pthread_cond_signal(&server_started); + pthread_mutex_unlock(&server_started_mtx); + + if (CHECK_FAIL(err < 0)) { + perror("Failed to listed on socket"); + return NULL; + } + + err += verify_sockopt(fd, CUSTOM_INHERIT1, "listen", 1); + err += verify_sockopt(fd, CUSTOM_INHERIT2, "listen", 1); + err += verify_sockopt(fd, CUSTOM_LISTENER, "listen", 1); + + client_fd = accept(fd, (struct sockaddr *)&addr, &len); + if (CHECK_FAIL(client_fd < 0)) { + perror("Failed to accept client"); + return NULL; + } + + err += verify_sockopt(client_fd, CUSTOM_INHERIT1, "accept", 1); + err += verify_sockopt(client_fd, CUSTOM_INHERIT2, "accept", 1); + err += verify_sockopt(client_fd, CUSTOM_LISTENER, "accept", 0); + + close(client_fd); + + return (void *)(long)err; +} + +static int start_server(void) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_LOOPBACK), + }; + char buf; + int err; + int fd; + int i; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + log_err("Failed to create server socket"); + return -1; + } + + for (i = CUSTOM_INHERIT1; i <= CUSTOM_LISTENER; i++) { + buf = 0x01; + err = setsockopt(fd, SOL_CUSTOM, i, &buf, 1); + if (err) { + log_err("Failed to call setsockopt(%d)", i); + close(fd); + return -1; + } + } + + if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) { + log_err("Failed to bind socket"); + close(fd); + return -1; + } + + return fd; +} + +static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title) +{ + enum bpf_attach_type attach_type; + enum bpf_prog_type prog_type; + struct bpf_program *prog; + int err; + + err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); + if (err) { + log_err("Failed to deduct types for %s BPF program", title); + return -1; + } + + prog = bpf_object__find_program_by_title(obj, title); + if (!prog) { + log_err("Failed to find %s BPF program", title); + return -1; + } + + err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, + attach_type, 0); + if (err) { + log_err("Failed to attach %s BPF program", title); + return -1; + } + + return 0; +} + +static void run_test(int cgroup_fd) +{ + struct bpf_prog_load_attr attr = { + .file = "./sockopt_inherit.o", + }; + int server_fd = -1, client_fd; + struct bpf_object *obj; + void *server_err; + pthread_t tid; + int ignored; + int err; + + err = bpf_prog_load_xattr(&attr, &obj, &ignored); + if (CHECK_FAIL(err)) + return; + + err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt"); + if (CHECK_FAIL(err)) + goto close_bpf_object; + + err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt"); + if (CHECK_FAIL(err)) + goto close_bpf_object; + + server_fd = start_server(); + if (CHECK_FAIL(server_fd < 0)) + goto close_bpf_object; + + if (CHECK_FAIL(pthread_create(&tid, NULL, server_thread, + (void *)&server_fd))) + goto close_bpf_object; + + pthread_mutex_lock(&server_started_mtx); + pthread_cond_wait(&server_started, &server_started_mtx); + pthread_mutex_unlock(&server_started_mtx); + + client_fd = connect_to_server(server_fd); + if (CHECK_FAIL(client_fd < 0)) + goto close_server_fd; + + CHECK_FAIL(verify_sockopt(client_fd, CUSTOM_INHERIT1, "connect", 0)); + CHECK_FAIL(verify_sockopt(client_fd, CUSTOM_INHERIT2, "connect", 0)); + CHECK_FAIL(verify_sockopt(client_fd, CUSTOM_LISTENER, "connect", 0)); + + pthread_join(tid, &server_err); + + err = (int)(long)server_err; + CHECK_FAIL(err); + + close(client_fd); + +close_server_fd: + close(server_fd); +close_bpf_object: + bpf_object__close(obj); +} + +void test_sockopt_inherit(void) +{ + int cgroup_fd; + + cgroup_fd = test__join_cgroup("/sockopt_inherit"); + if (CHECK_FAIL(cgroup_fd < 0)) + return; + + run_test(cgroup_fd); + close(cgroup_fd); +} diff --git a/tools/testing/selftests/bpf/test_sockopt_inherit.c b/tools/testing/selftests/bpf/test_sockopt_inherit.c deleted file mode 100644 index 1bf699815b9b..000000000000 --- a/tools/testing/selftests/bpf/test_sockopt_inherit.c +++ /dev/null @@ -1,253 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "bpf_rlimit.h" -#include "bpf_util.h" -#include "cgroup_helpers.h" - -#define CG_PATH "/sockopt_inherit" -#define SOL_CUSTOM 0xdeadbeef -#define CUSTOM_INHERIT1 0 -#define CUSTOM_INHERIT2 1 -#define CUSTOM_LISTENER 2 - -static int connect_to_server(int server_fd) -{ - struct sockaddr_storage addr; - socklen_t len = sizeof(addr); - int fd; - - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd < 0) { - log_err("Failed to create client socket"); - return -1; - } - - if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) { - log_err("Failed to get server addr"); - goto out; - } - - if (connect(fd, (const struct sockaddr *)&addr, len) < 0) { - log_err("Fail to connect to server"); - goto out; - } - - return fd; - -out: - close(fd); - return -1; -} - -static int verify_sockopt(int fd, int optname, const char *msg, char expected) -{ - socklen_t optlen = 1; - char buf = 0; - int err; - - err = getsockopt(fd, SOL_CUSTOM, optname, &buf, &optlen); - if (err) { - log_err("%s: failed to call getsockopt", msg); - return 1; - } - - printf("%s %d: got=0x%x ? expected=0x%x\n", msg, optname, buf, expected); - - if (buf != expected) { - log_err("%s: unexpected getsockopt value %d != %d", msg, - buf, expected); - return 1; - } - - return 0; -} - -static void *server_thread(void *arg) -{ - struct sockaddr_storage addr; - socklen_t len = sizeof(addr); - int fd = *(int *)arg; - int client_fd; - int err = 0; - - if (listen(fd, 1) < 0) - error(1, errno, "Failed to listed on socket"); - - err += verify_sockopt(fd, CUSTOM_INHERIT1, "listen", 1); - err += verify_sockopt(fd, CUSTOM_INHERIT2, "listen", 1); - err += verify_sockopt(fd, CUSTOM_LISTENER, "listen", 1); - - client_fd = accept(fd, (struct sockaddr *)&addr, &len); - if (client_fd < 0) - error(1, errno, "Failed to accept client"); - - err += verify_sockopt(client_fd, CUSTOM_INHERIT1, "accept", 1); - err += verify_sockopt(client_fd, CUSTOM_INHERIT2, "accept", 1); - err += verify_sockopt(client_fd, CUSTOM_LISTENER, "accept", 0); - - close(client_fd); - - return (void *)(long)err; -} - -static int start_server(void) -{ - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = htonl(INADDR_LOOPBACK), - }; - char buf; - int err; - int fd; - int i; - - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd < 0) { - log_err("Failed to create server socket"); - return -1; - } - - for (i = CUSTOM_INHERIT1; i <= CUSTOM_LISTENER; i++) { - buf = 0x01; - err = setsockopt(fd, SOL_CUSTOM, i, &buf, 1); - if (err) { - log_err("Failed to call setsockopt(%d)", i); - close(fd); - return -1; - } - } - - if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) { - log_err("Failed to bind socket"); - close(fd); - return -1; - } - - return fd; -} - -static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title) -{ - enum bpf_attach_type attach_type; - enum bpf_prog_type prog_type; - struct bpf_program *prog; - int err; - - err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); - if (err) { - log_err("Failed to deduct types for %s BPF program", title); - return -1; - } - - prog = bpf_object__find_program_by_title(obj, title); - if (!prog) { - log_err("Failed to find %s BPF program", title); - return -1; - } - - err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, - attach_type, 0); - if (err) { - log_err("Failed to attach %s BPF program", title); - return -1; - } - - return 0; -} - -static int run_test(int cgroup_fd) -{ - struct bpf_prog_load_attr attr = { - .file = "./sockopt_inherit.o", - }; - int server_fd = -1, client_fd; - struct bpf_object *obj; - void *server_err; - pthread_t tid; - int ignored; - int err; - - err = bpf_prog_load_xattr(&attr, &obj, &ignored); - if (err) { - log_err("Failed to load BPF object"); - return -1; - } - - err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt"); - if (err) - goto close_bpf_object; - - err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt"); - if (err) - goto close_bpf_object; - - server_fd = start_server(); - if (server_fd < 0) { - err = -1; - goto close_bpf_object; - } - - pthread_create(&tid, NULL, server_thread, (void *)&server_fd); - - client_fd = connect_to_server(server_fd); - if (client_fd < 0) { - err = -1; - goto close_server_fd; - } - - err += verify_sockopt(client_fd, CUSTOM_INHERIT1, "connect", 0); - err += verify_sockopt(client_fd, CUSTOM_INHERIT2, "connect", 0); - err += verify_sockopt(client_fd, CUSTOM_LISTENER, "connect", 0); - - pthread_join(tid, &server_err); - - err += (int)(long)server_err; - - close(client_fd); - -close_server_fd: - close(server_fd); -close_bpf_object: - bpf_object__close(obj); - return err; -} - -int main(int args, char **argv) -{ - int cgroup_fd; - int err = EXIT_SUCCESS; - - if (setup_cgroup_environment()) - return err; - - cgroup_fd = create_and_get_cgroup(CG_PATH); - if (cgroup_fd < 0) - goto cleanup_cgroup_env; - - if (join_cgroup(CG_PATH)) - goto cleanup_cgroup; - - if (run_test(cgroup_fd)) - err = EXIT_FAILURE; - - printf("test_sockopt_inherit: %s\n", - err == EXIT_SUCCESS ? "PASSED" : "FAILED"); - -cleanup_cgroup: - close(cgroup_fd); -cleanup_cgroup_env: - cleanup_cgroup_environment(); - return err; -} -- cgit v1.2.3 From 1f4f80fed217e8186a7e1067ae71260e133012ce Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Wed, 4 Sep 2019 09:25:09 -0700 Subject: selftests/bpf: test_progs: convert test_tcp_rtt Move the files, adjust includes, remove entry from Makefile & .gitignore Signed-off-by: Stanislav Fomichev Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/.gitignore | 1 - tools/testing/selftests/bpf/Makefile | 3 +- tools/testing/selftests/bpf/prog_tests/tcp_rtt.c | 256 ++++++++++++++++++++ tools/testing/selftests/bpf/test_tcp_rtt.c | 285 ----------------------- 4 files changed, 257 insertions(+), 288 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/tcp_rtt.c delete mode 100644 tools/testing/selftests/bpf/test_tcp_rtt.c diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 5b06bb45b500..7470327edcfe 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -39,4 +39,3 @@ libbpf.so.* test_hashmap test_btf_dump xdping -test_tcp_rtt diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 4d9a0304a011..7f3196af1ae4 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -28,7 +28,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test test_sock test_btf test_sockmap get_cgroup_id_user test_socket_cookie \ test_cgroup_storage test_select_reuseport test_section_names \ test_netcnt test_tcpnotify_user test_sock_fields test_sysctl test_hashmap \ - test_btf_dump test_cgroup_attach xdping test_tcp_rtt + test_btf_dump test_cgroup_attach xdping BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c))) TEST_GEN_FILES = $(BPF_OBJ_FILES) @@ -112,7 +112,6 @@ $(OUTPUT)/test_netcnt: cgroup_helpers.c $(OUTPUT)/test_sock_fields: cgroup_helpers.c $(OUTPUT)/test_sysctl: cgroup_helpers.c $(OUTPUT)/test_cgroup_attach: cgroup_helpers.c -$(OUTPUT)/test_tcp_rtt: cgroup_helpers.c .PHONY: force diff --git a/tools/testing/selftests/bpf/prog_tests/tcp_rtt.c b/tools/testing/selftests/bpf/prog_tests/tcp_rtt.c new file mode 100644 index 000000000000..fdc0b3614a9e --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/tcp_rtt.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "cgroup_helpers.h" + +struct tcp_rtt_storage { + __u32 invoked; + __u32 dsack_dups; + __u32 delivered; + __u32 delivered_ce; + __u32 icsk_retransmits; +}; + +static void send_byte(int fd) +{ + char b = 0x55; + + if (CHECK_FAIL(write(fd, &b, sizeof(b)) != 1)) + perror("Failed to send single byte"); +} + +static int wait_for_ack(int fd, int retries) +{ + struct tcp_info info; + socklen_t optlen; + int i, err; + + for (i = 0; i < retries; i++) { + optlen = sizeof(info); + err = getsockopt(fd, SOL_TCP, TCP_INFO, &info, &optlen); + if (err < 0) { + log_err("Failed to lookup TCP stats"); + return err; + } + + if (info.tcpi_unacked == 0) + return 0; + + usleep(10); + } + + log_err("Did not receive ACK"); + return -1; +} + +static int verify_sk(int map_fd, int client_fd, const char *msg, __u32 invoked, + __u32 dsack_dups, __u32 delivered, __u32 delivered_ce, + __u32 icsk_retransmits) +{ + int err = 0; + struct tcp_rtt_storage val; + + if (CHECK_FAIL(bpf_map_lookup_elem(map_fd, &client_fd, &val) < 0)) { + perror("Failed to read socket storage"); + return -1; + } + + if (val.invoked != invoked) { + log_err("%s: unexpected bpf_tcp_sock.invoked %d != %d", + msg, val.invoked, invoked); + err++; + } + + if (val.dsack_dups != dsack_dups) { + log_err("%s: unexpected bpf_tcp_sock.dsack_dups %d != %d", + msg, val.dsack_dups, dsack_dups); + err++; + } + + if (val.delivered != delivered) { + log_err("%s: unexpected bpf_tcp_sock.delivered %d != %d", + msg, val.delivered, delivered); + err++; + } + + if (val.delivered_ce != delivered_ce) { + log_err("%s: unexpected bpf_tcp_sock.delivered_ce %d != %d", + msg, val.delivered_ce, delivered_ce); + err++; + } + + if (val.icsk_retransmits != icsk_retransmits) { + log_err("%s: unexpected bpf_tcp_sock.icsk_retransmits %d != %d", + msg, val.icsk_retransmits, icsk_retransmits); + err++; + } + + return err; +} + +static int connect_to_server(int server_fd) +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + int fd; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + log_err("Failed to create client socket"); + return -1; + } + + if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) { + log_err("Failed to get server addr"); + goto out; + } + + if (connect(fd, (const struct sockaddr *)&addr, len) < 0) { + log_err("Fail to connect to server"); + goto out; + } + + return fd; + +out: + close(fd); + return -1; +} + +static int run_test(int cgroup_fd, int server_fd) +{ + struct bpf_prog_load_attr attr = { + .prog_type = BPF_PROG_TYPE_SOCK_OPS, + .file = "./tcp_rtt.o", + .expected_attach_type = BPF_CGROUP_SOCK_OPS, + }; + struct bpf_object *obj; + struct bpf_map *map; + int client_fd; + int prog_fd; + int map_fd; + int err; + + err = bpf_prog_load_xattr(&attr, &obj, &prog_fd); + if (err) { + log_err("Failed to load BPF object"); + return -1; + } + + map = bpf_map__next(NULL, obj); + map_fd = bpf_map__fd(map); + + err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0); + if (err) { + log_err("Failed to attach BPF program"); + goto close_bpf_object; + } + + client_fd = connect_to_server(server_fd); + if (client_fd < 0) { + err = -1; + goto close_bpf_object; + } + + err += verify_sk(map_fd, client_fd, "syn-ack", + /*invoked=*/1, + /*dsack_dups=*/0, + /*delivered=*/1, + /*delivered_ce=*/0, + /*icsk_retransmits=*/0); + + send_byte(client_fd); + if (wait_for_ack(client_fd, 100) < 0) { + err = -1; + goto close_client_fd; + } + + + err += verify_sk(map_fd, client_fd, "first payload byte", + /*invoked=*/2, + /*dsack_dups=*/0, + /*delivered=*/2, + /*delivered_ce=*/0, + /*icsk_retransmits=*/0); + +close_client_fd: + close(client_fd); + +close_bpf_object: + bpf_object__close(obj); + return err; +} + +static int start_server(void) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_LOOPBACK), + }; + int fd; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + log_err("Failed to create server socket"); + return -1; + } + + if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) { + log_err("Failed to bind socket"); + close(fd); + return -1; + } + + return fd; +} + +static void *server_thread(void *arg) +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + int fd = *(int *)arg; + int client_fd; + + if (CHECK_FAIL(listen(fd, 1)) < 0) { + perror("Failed to listed on socket"); + return NULL; + } + + client_fd = accept(fd, (struct sockaddr *)&addr, &len); + if (CHECK_FAIL(client_fd < 0)) { + perror("Failed to accept client"); + return NULL; + } + + /* Wait for the next connection (that never arrives) + * to keep this thread alive to prevent calling + * close() on client_fd. + */ + if (CHECK_FAIL(accept(fd, (struct sockaddr *)&addr, &len) >= 0)) { + perror("Unexpected success in second accept"); + return NULL; + } + + close(client_fd); + + return NULL; +} + +void test_tcp_rtt(void) +{ + int server_fd, cgroup_fd; + pthread_t tid; + + cgroup_fd = test__join_cgroup("/tcp_rtt"); + if (CHECK_FAIL(cgroup_fd < 0)) + return; + + server_fd = start_server(); + if (CHECK_FAIL(server_fd < 0)) + goto close_cgroup_fd; + + pthread_create(&tid, NULL, server_thread, (void *)&server_fd); + CHECK_FAIL(run_test(cgroup_fd, server_fd)); + close(server_fd); +close_cgroup_fd: + close(cgroup_fd); +} diff --git a/tools/testing/selftests/bpf/test_tcp_rtt.c b/tools/testing/selftests/bpf/test_tcp_rtt.c deleted file mode 100644 index 93916a69823e..000000000000 --- a/tools/testing/selftests/bpf/test_tcp_rtt.c +++ /dev/null @@ -1,285 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "bpf_rlimit.h" -#include "bpf_util.h" -#include "cgroup_helpers.h" - -#define CG_PATH "/tcp_rtt" - -struct tcp_rtt_storage { - __u32 invoked; - __u32 dsack_dups; - __u32 delivered; - __u32 delivered_ce; - __u32 icsk_retransmits; -}; - -static void send_byte(int fd) -{ - char b = 0x55; - - if (write(fd, &b, sizeof(b)) != 1) - error(1, errno, "Failed to send single byte"); -} - -static int wait_for_ack(int fd, int retries) -{ - struct tcp_info info; - socklen_t optlen; - int i, err; - - for (i = 0; i < retries; i++) { - optlen = sizeof(info); - err = getsockopt(fd, SOL_TCP, TCP_INFO, &info, &optlen); - if (err < 0) { - log_err("Failed to lookup TCP stats"); - return err; - } - - if (info.tcpi_unacked == 0) - return 0; - - usleep(10); - } - - log_err("Did not receive ACK"); - return -1; -} - -static int verify_sk(int map_fd, int client_fd, const char *msg, __u32 invoked, - __u32 dsack_dups, __u32 delivered, __u32 delivered_ce, - __u32 icsk_retransmits) -{ - int err = 0; - struct tcp_rtt_storage val; - - if (bpf_map_lookup_elem(map_fd, &client_fd, &val) < 0) - error(1, errno, "Failed to read socket storage"); - - if (val.invoked != invoked) { - log_err("%s: unexpected bpf_tcp_sock.invoked %d != %d", - msg, val.invoked, invoked); - err++; - } - - if (val.dsack_dups != dsack_dups) { - log_err("%s: unexpected bpf_tcp_sock.dsack_dups %d != %d", - msg, val.dsack_dups, dsack_dups); - err++; - } - - if (val.delivered != delivered) { - log_err("%s: unexpected bpf_tcp_sock.delivered %d != %d", - msg, val.delivered, delivered); - err++; - } - - if (val.delivered_ce != delivered_ce) { - log_err("%s: unexpected bpf_tcp_sock.delivered_ce %d != %d", - msg, val.delivered_ce, delivered_ce); - err++; - } - - if (val.icsk_retransmits != icsk_retransmits) { - log_err("%s: unexpected bpf_tcp_sock.icsk_retransmits %d != %d", - msg, val.icsk_retransmits, icsk_retransmits); - err++; - } - - return err; -} - -static int connect_to_server(int server_fd) -{ - struct sockaddr_storage addr; - socklen_t len = sizeof(addr); - int fd; - - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd < 0) { - log_err("Failed to create client socket"); - return -1; - } - - if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) { - log_err("Failed to get server addr"); - goto out; - } - - if (connect(fd, (const struct sockaddr *)&addr, len) < 0) { - log_err("Fail to connect to server"); - goto out; - } - - return fd; - -out: - close(fd); - return -1; -} - -static int run_test(int cgroup_fd, int server_fd) -{ - struct bpf_prog_load_attr attr = { - .prog_type = BPF_PROG_TYPE_SOCK_OPS, - .file = "./tcp_rtt.o", - .expected_attach_type = BPF_CGROUP_SOCK_OPS, - }; - struct bpf_object *obj; - struct bpf_map *map; - int client_fd; - int prog_fd; - int map_fd; - int err; - - err = bpf_prog_load_xattr(&attr, &obj, &prog_fd); - if (err) { - log_err("Failed to load BPF object"); - return -1; - } - - map = bpf_map__next(NULL, obj); - map_fd = bpf_map__fd(map); - - err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0); - if (err) { - log_err("Failed to attach BPF program"); - goto close_bpf_object; - } - - client_fd = connect_to_server(server_fd); - if (client_fd < 0) { - err = -1; - goto close_bpf_object; - } - - err += verify_sk(map_fd, client_fd, "syn-ack", - /*invoked=*/1, - /*dsack_dups=*/0, - /*delivered=*/1, - /*delivered_ce=*/0, - /*icsk_retransmits=*/0); - - send_byte(client_fd); - if (wait_for_ack(client_fd, 100) < 0) { - err = -1; - goto close_client_fd; - } - - - err += verify_sk(map_fd, client_fd, "first payload byte", - /*invoked=*/2, - /*dsack_dups=*/0, - /*delivered=*/2, - /*delivered_ce=*/0, - /*icsk_retransmits=*/0); - -close_client_fd: - close(client_fd); - -close_bpf_object: - bpf_object__close(obj); - return err; -} - -static int start_server(void) -{ - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = htonl(INADDR_LOOPBACK), - }; - int fd; - - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd < 0) { - log_err("Failed to create server socket"); - return -1; - } - - if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) { - log_err("Failed to bind socket"); - close(fd); - return -1; - } - - return fd; -} - -static void *server_thread(void *arg) -{ - struct sockaddr_storage addr; - socklen_t len = sizeof(addr); - int fd = *(int *)arg; - int client_fd; - - if (listen(fd, 1) < 0) - error(1, errno, "Failed to listed on socket"); - - client_fd = accept(fd, (struct sockaddr *)&addr, &len); - if (client_fd < 0) - error(1, errno, "Failed to accept client"); - - /* Wait for the next connection (that never arrives) - * to keep this thread alive to prevent calling - * close() on client_fd. - */ - if (accept(fd, (struct sockaddr *)&addr, &len) >= 0) - error(1, errno, "Unexpected success in second accept"); - - close(client_fd); - - return NULL; -} - -int main(int args, char **argv) -{ - int server_fd, cgroup_fd; - int err = EXIT_SUCCESS; - pthread_t tid; - - if (setup_cgroup_environment()) - goto cleanup_obj; - - cgroup_fd = create_and_get_cgroup(CG_PATH); - if (cgroup_fd < 0) - goto cleanup_cgroup_env; - - if (join_cgroup(CG_PATH)) - goto cleanup_cgroup; - - server_fd = start_server(); - if (server_fd < 0) { - err = EXIT_FAILURE; - goto cleanup_cgroup; - } - - pthread_create(&tid, NULL, server_thread, (void *)&server_fd); - - if (run_test(cgroup_fd, server_fd)) - err = EXIT_FAILURE; - - close(server_fd); - - printf("test_sockopt_sk: %s\n", - err == EXIT_SUCCESS ? "PASSED" : "FAILED"); - -cleanup_cgroup: - close(cgroup_fd); -cleanup_cgroup_env: - cleanup_cgroup_environment(); -cleanup_obj: - return err; -} -- cgit v1.2.3