aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorMartin KaFai Lau <martin.lau@kernel.org>2024-10-22 13:06:41 -0700
committerMartin KaFai Lau <martin.lau@kernel.org>2024-10-22 13:41:43 -0700
commitefe7921927dc01cffdaff623ef51609e1be5058a (patch)
tree5cd134e758f92185c92217bbcb91e03bc678b94a
parentMerge branch 'implement-mechanism-to-signal-other-threads' (diff)
parentselftests/bpf: Retire test_sock.c (diff)
downloadwireguard-linux-efe7921927dc01cffdaff623ef51609e1be5058a.tar.xz
wireguard-linux-efe7921927dc01cffdaff623ef51609e1be5058a.zip
Merge branch 'Retire test_sock.c'
Jordan Rife says: ==================== This patch series migrates test cases out of test_sock.c to prog_tests-style tests. It moves all BPF_CGROUP_INET4_POST_BIND and BPF_CGROUP_INET6_POST_BIND test cases into a new prog_test, sock_post_bind.c, while reimplementing all LOAD_REJECT test cases as verifier tests in progs/verifier_sock.c. Finally, it moves remaining BPF_CGROUP_INET_SOCK_CREATE test coverage into prog_tests/sock_create.c before retiring test_sock.c completely. Changes ======= v1->v2: - Remove superfluous verbose bool from the top of sock_post_bind.c. - Use ASSERT_OK_FD instead of ASSERT_GE to test cgroup_fd validity. - Run sock_post_bind tests in their own namespace, "sock_post_bind". ==================== Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Diffstat (limited to '')
-rw-r--r--tools/testing/selftests/bpf/.gitignore1
-rw-r--r--tools/testing/selftests/bpf/Makefile3
-rw-r--r--tools/testing/selftests/bpf/prog_tests/sock_create.c35
-rw-r--r--tools/testing/selftests/bpf/prog_tests/sock_post_bind.c (renamed from tools/testing/selftests/bpf/test_sock.c)254
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_sock.c60
5 files changed, 148 insertions, 205 deletions
diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore
index e6533b3400de..d45c9a9b304d 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -16,7 +16,6 @@ fixdep
/test_progs-cpuv4
test_verifier_log
feature
-test_sock
urandom_read
test_sockmap
test_lirc_mode2_user
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 28a76baa854d..c4fc9a3291a8 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -84,7 +84,7 @@ endif
# Order correspond to 'make run_tests' order
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
- test_sock test_sockmap \
+ test_sockmap \
test_tcpnotify_user test_sysctl \
test_progs-no_alu32
TEST_INST_SUBDIRS := no_alu32
@@ -335,7 +335,6 @@ JSON_WRITER := $(OUTPUT)/json_writer.o
CAP_HELPERS := $(OUTPUT)/cap_helpers.o
NETWORK_HELPERS := $(OUTPUT)/network_helpers.o
-$(OUTPUT)/test_sock: $(CGROUP_HELPERS) $(TESTING_HELPERS)
$(OUTPUT)/test_sockmap: $(CGROUP_HELPERS) $(TESTING_HELPERS)
$(OUTPUT)/test_tcpnotify_user: $(CGROUP_HELPERS) $(TESTING_HELPERS) $(TRACE_HELPERS)
$(OUTPUT)/test_sock_fields: $(CGROUP_HELPERS) $(TESTING_HELPERS)
diff --git a/tools/testing/selftests/bpf/prog_tests/sock_create.c b/tools/testing/selftests/bpf/prog_tests/sock_create.c
index 17a3713621dd..187ffc5e60c4 100644
--- a/tools/testing/selftests/bpf/prog_tests/sock_create.c
+++ b/tools/testing/selftests/bpf/prog_tests/sock_create.c
@@ -237,6 +237,19 @@ static struct sock_create_test {
.error = DENY_CREATE,
},
+ {
+ .descr = "load w/o expected_attach_type (compat mode)",
+ .insns = {
+ /* return 1 */
+ BPF_MOV64_IMM(BPF_REG_0, 1),
+ BPF_EXIT_INSN(),
+ },
+ .expected_attach_type = 0,
+ .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
+
+ .domain = AF_INET,
+ .type = SOCK_STREAM,
+ },
};
static int load_prog(const struct bpf_insn *insns,
@@ -291,16 +304,18 @@ static int run_test(int cgroup_fd, struct sock_create_test *test)
goto detach_prog;
}
- err = getsockopt(sock_fd, SOL_SOCKET, test->optname, &optval, &optlen);
- if (err) {
- log_err("Failed to call getsockopt");
- goto cleanup;
- }
-
- if (optval != test->optval) {
- errno = 0;
- log_err("getsockopt returned unexpected optval");
- goto cleanup;
+ if (test->optname) {
+ err = getsockopt(sock_fd, SOL_SOCKET, test->optname, &optval, &optlen);
+ if (err) {
+ log_err("Failed to call getsockopt");
+ goto cleanup;
+ }
+
+ if (optval != test->optval) {
+ errno = 0;
+ log_err("getsockopt returned unexpected optval");
+ goto cleanup;
+ }
}
ret = test->error != OK;
diff --git a/tools/testing/selftests/bpf/test_sock.c b/tools/testing/selftests/bpf/prog_tests/sock_post_bind.c
index 810c3740b2cc..788135c9c673 100644
--- a/tools/testing/selftests/bpf/test_sock.c
+++ b/tools/testing/selftests/bpf/prog_tests/sock_post_bind.c
@@ -1,132 +1,35 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018 Facebook
-
-#include <stdio.h>
-#include <unistd.h>
-
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <linux/filter.h>
-
-#include <bpf/bpf.h>
-
+#include <linux/bpf.h>
+#include <test_progs.h>
#include "cgroup_helpers.h"
-#include <bpf/bpf_endian.h>
-#include "bpf_util.h"
-#define CG_PATH "/foo"
-#define MAX_INSNS 512
+#define TEST_NS "sock_post_bind"
-char bpf_log_buf[BPF_LOG_BUF_SIZE];
-static bool verbose = false;
+static char bpf_log_buf[4096];
-struct sock_test {
- const char *descr;
+static struct sock_post_bind_test {
+ const char *descr;
/* BPF prog properties */
- struct bpf_insn insns[MAX_INSNS];
- enum bpf_attach_type expected_attach_type;
- enum bpf_attach_type attach_type;
+ const struct bpf_insn insns[64];
+ enum bpf_attach_type attach_type;
+ enum bpf_attach_type expected_attach_type;
/* Socket properties */
- int domain;
- int type;
+ int domain;
+ int type;
/* Endpoint to bind() to */
const char *ip;
unsigned short port;
unsigned short port_retry;
+
/* Expected test result */
enum {
- LOAD_REJECT,
ATTACH_REJECT,
BIND_REJECT,
SUCCESS,
RETRY_SUCCESS,
RETRY_REJECT
} result;
-};
-
-static struct sock_test tests[] = {
- {
- .descr = "bind4 load with invalid access: src_ip6",
- .insns = {
- BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
- BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
- offsetof(struct bpf_sock, src_ip6[0])),
- BPF_MOV64_IMM(BPF_REG_0, 1),
- BPF_EXIT_INSN(),
- },
- .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
- .attach_type = BPF_CGROUP_INET4_POST_BIND,
- .result = LOAD_REJECT,
- },
- {
- .descr = "bind4 load with invalid access: mark",
- .insns = {
- BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
- BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
- offsetof(struct bpf_sock, mark)),
- BPF_MOV64_IMM(BPF_REG_0, 1),
- BPF_EXIT_INSN(),
- },
- .expected_attach_type = BPF_CGROUP_INET4_POST_BIND,
- .attach_type = BPF_CGROUP_INET4_POST_BIND,
- .result = LOAD_REJECT,
- },
- {
- .descr = "bind6 load with invalid access: src_ip4",
- .insns = {
- BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
- BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
- offsetof(struct bpf_sock, src_ip4)),
- BPF_MOV64_IMM(BPF_REG_0, 1),
- BPF_EXIT_INSN(),
- },
- .expected_attach_type = BPF_CGROUP_INET6_POST_BIND,
- .attach_type = BPF_CGROUP_INET6_POST_BIND,
- .result = LOAD_REJECT,
- },
- {
- .descr = "sock_create load with invalid access: src_port",
- .insns = {
- BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
- BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
- offsetof(struct bpf_sock, src_port)),
- BPF_MOV64_IMM(BPF_REG_0, 1),
- BPF_EXIT_INSN(),
- },
- .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
- .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
- .result = LOAD_REJECT,
- },
- {
- .descr = "sock_create load w/o expected_attach_type (compat mode)",
- .insns = {
- BPF_MOV64_IMM(BPF_REG_0, 1),
- BPF_EXIT_INSN(),
- },
- .expected_attach_type = 0,
- .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
- .domain = AF_INET,
- .type = SOCK_STREAM,
- .ip = "127.0.0.1",
- .port = 8097,
- .result = SUCCESS,
- },
- {
- .descr = "sock_create load w/ expected_attach_type",
- .insns = {
- BPF_MOV64_IMM(BPF_REG_0, 1),
- BPF_EXIT_INSN(),
- },
- .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
- .attach_type = BPF_CGROUP_INET_SOCK_CREATE,
- .domain = AF_INET,
- .type = SOCK_STREAM,
- .ip = "127.0.0.1",
- .port = 8097,
- .result = SUCCESS,
- },
+} tests[] = {
{
.descr = "attach type mismatch bind4 vs bind6",
.insns = {
@@ -374,40 +277,29 @@ static struct sock_test tests[] = {
},
};
-static size_t probe_prog_length(const struct bpf_insn *fp)
-{
- size_t len;
-
- for (len = MAX_INSNS - 1; len > 0; --len)
- if (fp[len].code != 0 || fp[len].imm != 0)
- break;
- return len + 1;
-}
-
-static int load_sock_prog(const struct bpf_insn *prog,
- enum bpf_attach_type attach_type)
+static int load_prog(const struct bpf_insn *insns,
+ enum bpf_attach_type expected_attach_type)
{
- LIBBPF_OPTS(bpf_prog_load_opts, opts);
- int ret, insn_cnt;
-
- insn_cnt = probe_prog_length(prog);
-
- opts.expected_attach_type = attach_type;
- opts.log_buf = bpf_log_buf;
- opts.log_size = BPF_LOG_BUF_SIZE;
- opts.log_level = 2;
+ LIBBPF_OPTS(bpf_prog_load_opts, opts,
+ .expected_attach_type = expected_attach_type,
+ .log_level = 2,
+ .log_buf = bpf_log_buf,
+ .log_size = sizeof(bpf_log_buf),
+ );
+ int fd, insns_cnt = 0;
+
+ for (;
+ insns[insns_cnt].code != (BPF_JMP | BPF_EXIT);
+ insns_cnt++) {
+ }
+ insns_cnt++;
- ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", prog, insn_cnt, &opts);
- if (verbose && ret < 0)
+ fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns,
+ insns_cnt, &opts);
+ if (fd < 0)
fprintf(stderr, "%s\n", bpf_log_buf);
- return ret;
-}
-
-static int attach_sock_prog(int cgfd, int progfd,
- enum bpf_attach_type attach_type)
-{
- return bpf_prog_attach(progfd, cgfd, attach_type, BPF_F_ALLOW_OVERRIDE);
+ return fd;
}
static int bind_sock(int domain, int type, const char *ip,
@@ -477,22 +369,16 @@ out:
return res;
}
-static int run_test_case(int cgfd, const struct sock_test *test)
+static int run_test(int cgroup_fd, struct sock_post_bind_test *test)
{
- int progfd = -1;
- int err = 0;
- int res;
-
- printf("Test case: %s .. ", test->descr);
- progfd = load_sock_prog(test->insns, test->expected_attach_type);
- if (progfd < 0) {
- if (test->result == LOAD_REJECT)
- goto out;
- else
- goto err;
- }
+ int err, prog_fd, res, ret = 0;
- if (attach_sock_prog(cgfd, progfd, test->attach_type) < 0) {
+ prog_fd = load_prog(test->insns, test->expected_attach_type);
+ if (prog_fd < 0)
+ goto err;
+
+ err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);
+ if (err < 0) {
if (test->result == ATTACH_REJECT)
goto out;
else
@@ -503,54 +389,38 @@ static int run_test_case(int cgfd, const struct sock_test *test)
test->port_retry);
if (res > 0 && test->result == res)
goto out;
-
err:
- err = -1;
+ ret = -1;
out:
/* Detaching w/o checking return code: best effort attempt. */
- if (progfd != -1)
- bpf_prog_detach(cgfd, test->attach_type);
- close(progfd);
- printf("[%s]\n", err ? "FAIL" : "PASS");
- return err;
+ if (prog_fd != -1)
+ bpf_prog_detach(cgroup_fd, test->attach_type);
+ close(prog_fd);
+ return ret;
}
-static int run_tests(int cgfd)
+void test_sock_post_bind(void)
{
- int passes = 0;
- int fails = 0;
+ struct netns_obj *ns;
+ int cgroup_fd;
int i;
- for (i = 0; i < ARRAY_SIZE(tests); ++i) {
- if (run_test_case(cgfd, &tests[i]))
- ++fails;
- else
- ++passes;
- }
- printf("Summary: %d PASSED, %d FAILED\n", passes, fails);
- return fails ? -1 : 0;
-}
-
-int main(int argc, char **argv)
-{
- int cgfd = -1;
- int err = 0;
+ cgroup_fd = test__join_cgroup("/post_bind");
+ if (!ASSERT_OK_FD(cgroup_fd, "join_cgroup"))
+ return;
- cgfd = cgroup_setup_and_join(CG_PATH);
- if (cgfd < 0)
- goto err;
+ ns = netns_new(TEST_NS, true);
+ if (!ASSERT_OK_PTR(ns, "netns_new"))
+ goto cleanup;
- /* Use libbpf 1.0 API mode */
- libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ if (!test__start_subtest(tests[i].descr))
+ continue;
- if (run_tests(cgfd))
- goto err;
+ ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr);
+ }
- goto out;
-err:
- err = -1;
-out:
- close(cgfd);
- cleanup_cgroup_environment();
- return err;
+cleanup:
+ netns_free(ns);
+ close(cgroup_fd);
}
diff --git a/tools/testing/selftests/bpf/progs/verifier_sock.c b/tools/testing/selftests/bpf/progs/verifier_sock.c
index ee76b51005ab..d3e70e38e442 100644
--- a/tools/testing/selftests/bpf/progs/verifier_sock.c
+++ b/tools/testing/selftests/bpf/progs/verifier_sock.c
@@ -977,4 +977,64 @@ l1_%=: r0 = *(u8*)(r7 + 0); \
: __clobber_all);
}
+SEC("cgroup/post_bind4")
+__description("sk->src_ip6[0] [load 1st byte]")
+__failure __msg("invalid bpf_context access off=28 size=2")
+__naked void post_bind4_read_src_ip6(void)
+{
+ asm volatile (" \
+ r6 = r1; \
+ r7 = *(u16*)(r6 + %[bpf_sock_src_ip6_0]); \
+ r0 = 1; \
+ exit; \
+" :
+ : __imm_const(bpf_sock_src_ip6_0, offsetof(struct bpf_sock, src_ip6[0]))
+ : __clobber_all);
+}
+
+SEC("cgroup/post_bind4")
+__description("sk->mark [load mark]")
+__failure __msg("invalid bpf_context access off=16 size=2")
+__naked void post_bind4_read_mark(void)
+{
+ asm volatile (" \
+ r6 = r1; \
+ r7 = *(u16*)(r6 + %[bpf_sock_mark]); \
+ r0 = 1; \
+ exit; \
+" :
+ : __imm_const(bpf_sock_mark, offsetof(struct bpf_sock, mark))
+ : __clobber_all);
+}
+
+SEC("cgroup/post_bind6")
+__description("sk->src_ip4 [load src_ip4]")
+__failure __msg("invalid bpf_context access off=24 size=2")
+__naked void post_bind6_read_src_ip4(void)
+{
+ asm volatile (" \
+ r6 = r1; \
+ r7 = *(u16*)(r6 + %[bpf_sock_src_ip4]); \
+ r0 = 1; \
+ exit; \
+" :
+ : __imm_const(bpf_sock_src_ip4, offsetof(struct bpf_sock, src_ip4))
+ : __clobber_all);
+}
+
+SEC("cgroup/sock_create")
+__description("sk->src_port [word load]")
+__failure __msg("invalid bpf_context access off=44 size=2")
+__naked void sock_create_read_src_port(void)
+{
+ asm volatile (" \
+ r6 = r1; \
+ r7 = *(u16*)(r6 + %[bpf_sock_src_port]); \
+ r0 = 1; \
+ exit; \
+" :
+ : __imm_const(bpf_sock_src_port, offsetof(struct bpf_sock, src_port))
+ : __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";