Message ID | 20241218-test-vsock-leaks-v3-5-f1a4dcef9228@rbox.co (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | vsock/test: Tests for memory leaks | expand |
On Wed, Dec 18, 2024 at 03:32:38PM +0100, Michal Luczaj wrote: >Attempt to enqueue a child after the queue was flushed, but before >SOCK_DONE flag has been set. > >Test tries to produce a memory leak, kmemleak should be employed. Dealing >with a race condition, test by its very nature may lead to a false >negative. > >Fixed by commit d7b0ff5a8667 ("virtio/vsock: Fix accept_queue memory >leak"). > >Signed-off-by: Michal Luczaj <mhal@rbox.co> >--- > tools/testing/vsock/vsock_test.c | 52 ++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 52 insertions(+) Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> > >diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c >index 8bb2ab41c55f5c4d76e89903f80411915296c44e..2a8fcb062d9d207be988da5dd350e503ca20a143 100644 >--- a/tools/testing/vsock/vsock_test.c >+++ b/tools/testing/vsock/vsock_test.c >@@ -29,6 +29,10 @@ > #include "control.h" > #include "util.h" > >+/* Basic messages for control_writeulong(), control_readulong() */ >+#define CONTROL_CONTINUE 1 >+#define CONTROL_DONE 0 >+ > static void test_stream_connection_reset(const struct test_opts *opts) > { > union { >@@ -1474,6 +1478,49 @@ static void test_stream_cred_upd_on_set_rcvlowat(const struct test_opts *opts) > test_stream_credit_update_test(opts, false); > } > >+/* The goal of test leak_acceptq is to stress the race between connect() and >+ * close(listener). Implementation of client/server loops boils down to: >+ * >+ * client server >+ * ------ ------ >+ * write(CONTINUE) >+ * expect(CONTINUE) >+ * listen() >+ * write(LISTENING) >+ * expect(LISTENING) >+ * connect() close() >+ */ >+#define ACCEPTQ_LEAK_RACE_TIMEOUT 2 /* seconds */ >+ >+static void test_stream_leak_acceptq_client(const struct test_opts *opts) >+{ >+ time_t tout; >+ int fd; >+ >+ tout = current_nsec() + ACCEPTQ_LEAK_RACE_TIMEOUT * NSEC_PER_SEC; >+ do { >+ control_writeulong(CONTROL_CONTINUE); >+ >+ fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); >+ if (fd >= 0) >+ close(fd); >+ } while (current_nsec() < tout); >+ >+ control_writeulong(CONTROL_DONE); >+} >+ >+/* Test for a memory leak. User is expected to run kmemleak scan, see README. */ >+static void test_stream_leak_acceptq_server(const struct test_opts *opts) >+{ >+ int fd; >+ >+ while (control_readulong() == CONTROL_CONTINUE) { >+ fd = vsock_stream_listen(VMADDR_CID_ANY, opts->peer_port); >+ control_writeln("LISTENING"); >+ close(fd); >+ } >+} >+ > static struct test_case test_cases[] = { > { > .name = "SOCK_STREAM connection reset", >@@ -1604,6 +1651,11 @@ static struct test_case test_cases[] = { > .run_client = test_seqpacket_unsent_bytes_client, > .run_server = test_seqpacket_unsent_bytes_server, > }, >+ { >+ .name = "SOCK_STREAM leak accept queue", >+ .run_client = test_stream_leak_acceptq_client, >+ .run_server = test_stream_leak_acceptq_server, >+ }, > {}, > }; > > >-- >2.47.1 >
diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index 8bb2ab41c55f5c4d76e89903f80411915296c44e..2a8fcb062d9d207be988da5dd350e503ca20a143 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -29,6 +29,10 @@ #include "control.h" #include "util.h" +/* Basic messages for control_writeulong(), control_readulong() */ +#define CONTROL_CONTINUE 1 +#define CONTROL_DONE 0 + static void test_stream_connection_reset(const struct test_opts *opts) { union { @@ -1474,6 +1478,49 @@ static void test_stream_cred_upd_on_set_rcvlowat(const struct test_opts *opts) test_stream_credit_update_test(opts, false); } +/* The goal of test leak_acceptq is to stress the race between connect() and + * close(listener). Implementation of client/server loops boils down to: + * + * client server + * ------ ------ + * write(CONTINUE) + * expect(CONTINUE) + * listen() + * write(LISTENING) + * expect(LISTENING) + * connect() close() + */ +#define ACCEPTQ_LEAK_RACE_TIMEOUT 2 /* seconds */ + +static void test_stream_leak_acceptq_client(const struct test_opts *opts) +{ + time_t tout; + int fd; + + tout = current_nsec() + ACCEPTQ_LEAK_RACE_TIMEOUT * NSEC_PER_SEC; + do { + control_writeulong(CONTROL_CONTINUE); + + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); + if (fd >= 0) + close(fd); + } while (current_nsec() < tout); + + control_writeulong(CONTROL_DONE); +} + +/* Test for a memory leak. User is expected to run kmemleak scan, see README. */ +static void test_stream_leak_acceptq_server(const struct test_opts *opts) +{ + int fd; + + while (control_readulong() == CONTROL_CONTINUE) { + fd = vsock_stream_listen(VMADDR_CID_ANY, opts->peer_port); + control_writeln("LISTENING"); + close(fd); + } +} + static struct test_case test_cases[] = { { .name = "SOCK_STREAM connection reset", @@ -1604,6 +1651,11 @@ static struct test_case test_cases[] = { .run_client = test_seqpacket_unsent_bytes_client, .run_server = test_seqpacket_unsent_bytes_server, }, + { + .name = "SOCK_STREAM leak accept queue", + .run_client = test_stream_leak_acceptq_client, + .run_server = test_stream_leak_acceptq_server, + }, {}, };
Attempt to enqueue a child after the queue was flushed, but before SOCK_DONE flag has been set. Test tries to produce a memory leak, kmemleak should be employed. Dealing with a race condition, test by its very nature may lead to a false negative. Fixed by commit d7b0ff5a8667 ("virtio/vsock: Fix accept_queue memory leak"). Signed-off-by: Michal Luczaj <mhal@rbox.co> --- tools/testing/vsock/vsock_test.c | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)