Tests more consistently that calling bpf_ksock_send() from unconnected ksock socket fails and that bpf_ksock_connect() can be called from the SYSCALL program creating the socket or from the LSM program also calling bpf_ksock_send(). Signed-off-by: Mahe Tardy --- .../testing/selftests/bpf/prog_tests/ksock.c | 53 +++++++++++++++---- tools/testing/selftests/bpf/progs/ksock_lsm.c | 32 ++++++++--- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/ksock.c b/tools/testing/selftests/bpf/prog_tests/ksock.c index dd6b167623d9..78677bfffdf3 100644 --- a/tools/testing/selftests/bpf/prog_tests/ksock.c +++ b/tools/testing/selftests/bpf/prog_tests/ksock.c @@ -17,6 +17,12 @@ struct ksock_test_env { int rfd; }; +struct ksock_test_case { + const char *name; + bool connect_in_syscall; + bool connect_in_lsm; +}; + static bool ksock_test_env_setup(struct ksock_test_env *env) { struct sockaddr_in addr = { @@ -55,16 +61,18 @@ static bool ksock_test_env_setup(struct ksock_test_env *env) return false; } -void test_ksock_lsm(void) +static void test_ksock_lsm_case(const struct ksock_test_case *test) { LIBBPF_OPTS(bpf_test_run_opts, opts); - struct ksock_test_env env; struct sockaddr_in trigger_addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), }; + struct ksock_test_env env; struct ksock_lsm *skel; char recv_data[sizeof(skel->data->send_data)] = {}; + bool connected = test->connect_in_syscall || test->connect_in_lsm; + int expected_send_ret = connected ? (int)sizeof(skel->data->send_data) : -EDESTADDRREQ; ssize_t n; int tfd = -1; int err; @@ -79,6 +87,8 @@ void test_ksock_lsm(void) /* Step 1: Run the setup SYSCALL prog to create the ksock */ skel->bss->ipv4_remote = htonl(INADDR_LOOPBACK); skel->bss->remote_port = RECV_PORT; + skel->bss->connect_in_syscall = test->connect_in_syscall; + skel->bss->connect_in_lsm = test->connect_in_lsm; err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.ksock_setup), &opts); if (!ASSERT_OK(err, "ksock_setup run")) @@ -103,15 +113,25 @@ void test_ksock_lsm(void) if (!ASSERT_OK(err, "trigger bind")) goto fail; - /* Step 3: Verify the LSM hook sent the notification */ - if (!ASSERT_EQ(skel->data->send_ret, sizeof(skel->data->send_data), - "LSM send bytes")) + /* Step 3: Verify the operations and received notification, if any. */ + if (!ASSERT_EQ(skel->data->connect_ret, connected ? 0 : -1, "connect retval")) + goto fail; + + if (!ASSERT_EQ(skel->data->send_ret, expected_send_ret, "LSM send retval")) + goto fail; + + n = recvfrom(env.rfd, recv_data, sizeof(recv_data), + connected ? 0 : MSG_DONTWAIT, NULL, NULL); + if (!connected) { + if (ASSERT_EQ(n, -1, "no datagram")) + ASSERT_EQ(errno, EAGAIN, "recvfrom errno"); goto fail; + } - n = recvfrom(env.rfd, recv_data, sizeof(recv_data), 0, NULL, NULL); - if (ASSERT_EQ(n, sizeof(recv_data), "recvfrom len")) - ASSERT_MEMEQ(recv_data, skel->data->send_data, sizeof(recv_data), - "payload match"); + if (!ASSERT_EQ(n, sizeof(recv_data), "recvfrom len") || + !ASSERT_MEMEQ(recv_data, skel->data->send_data, sizeof(recv_data), + "payload match")) + goto fail; fail: if (tfd >= 0) @@ -124,6 +144,21 @@ void test_ksock_lsm(void) ksock_lsm__destroy(skel); } +void test_ksock_lsm(void) +{ + static const struct ksock_test_case tests[] = { + { .name = "unconnected_send" }, + { .name = "syscall_connect_send", .connect_in_syscall = true }, + { .name = "lsm_connect_send", .connect_in_lsm = true }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(tests); i++) { + if (test__start_subtest(tests[i].name)) + test_ksock_lsm_case(&tests[i]); + } +} + void test_ksock_lsm_verifier(void) { RUN_TESTS(ksock_lsm_verifier); diff --git a/tools/testing/selftests/bpf/progs/ksock_lsm.c b/tools/testing/selftests/bpf/progs/ksock_lsm.c index 9808451098ef..944398ce2852 100644 --- a/tools/testing/selftests/bpf/progs/ksock_lsm.c +++ b/tools/testing/selftests/bpf/progs/ksock_lsm.c @@ -13,6 +13,9 @@ char send_data[32] = "hello from bpf ksock"; __be32 ipv4_remote; __u16 remote_port; int target_pid; +bool connect_in_syscall; +bool connect_in_lsm; +int connect_ret = -1; int send_ret = -1; SEC("syscall") @@ -31,14 +34,15 @@ int ksock_setup(void *ctx) if (!ks) return err; - addr.sin.sin_family = AF_INET; - addr.sin.sin_port = bpf_htons(remote_port); - addr.sin.sin_addr.s_addr = ipv4_remote; - - err = bpf_ksock_connect(ks, &addr, sizeof(addr)); - if (err) { - bpf_ksock_release(ks); - return err; + if (connect_in_syscall) { + addr.sin.sin_family = AF_INET; + addr.sin.sin_port = bpf_htons(remote_port); + addr.sin.sin_addr.s_addr = ipv4_remote; + connect_ret = bpf_ksock_connect(ks, &addr, sizeof(addr)); + if (connect_ret) { + bpf_ksock_release(ks); + return connect_ret; + } } err = ksock_ctx_insert(ks); @@ -51,6 +55,7 @@ SEC("lsm.s/socket_bind") int BPF_PROG(ksock_socket_bind, struct socket *sock, struct sockaddr *address, int addrlen, int ret) { + union bpf_ksock_addr addr = {}; struct bpf_ksock *ks; u32 pid = bpf_get_current_pid_tgid() >> 32; @@ -63,7 +68,18 @@ int BPF_PROG(ksock_socket_bind, struct socket *sock, struct sockaddr *address, return ret; } + addr.sin.sin_family = AF_INET; + addr.sin.sin_port = bpf_htons(remote_port); + addr.sin.sin_addr.s_addr = ipv4_remote; + + if (connect_in_lsm) { + connect_ret = bpf_ksock_connect(ks, &addr, sizeof(addr)); + if (connect_ret) + goto out; + } + send_ret = bpf_ksock_send(ks, send_data, sizeof(send_data)); +out: bpf_ksock_release(ks); return ret; -- 2.43.0