Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vsock/test: fix test for null ptr deref when transport changes

In test_stream_transport_change_client(), the client sends CONTROL_CONTINUE
on each iteration, even when connect() is unsuccessful. This causes a flood
of control messages in the server that hangs around for more than 10
seconds after the test finishes, triggering several timeouts and causing
subsequent tests to fail. This was discovered in testing a newly proposed
test that failed in this way on the client side:
...
33 - SOCK_STREAM transport change null-ptr-deref...ok
34 - SOCK_STREAM ioctl(SIOCINQ) functionality...recv timed out

The CONTROL_CONTINUE message is used only to tell to the server to call
accept() to consume successful connections, so that subsequent connect()
will not fail for finding the queue full.

Send CONTROL_CONTINUE message only when the connect() has succeeded, or
found the queue full. Note that the second connect() can also succeed if
the first one was interrupted after sending the request.

Fixes: 3a764d93385c ("vsock/test: Add test for null ptr deref when transport changes")
Cc: leonardi@redhat.com
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Reviewed-by: Luigi Leonardi <leonardi@redhat.com>
Link: https://patch.msgid.link/20250708111701.129585-1-sgarzare@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Stefano Garzarella and committed by
Jakub Kicinski
5d6fc6b4 b9274abe

+16 -5
+16 -5
tools/testing/vsock/vsock_test.c
··· 2006 2006 .svm_cid = opts->peer_cid, 2007 2007 .svm_port = opts->peer_port, 2008 2008 }; 2009 + bool send_control = false; 2009 2010 int s; 2010 2011 2011 2012 s = socket(AF_VSOCK, SOCK_STREAM, 0); ··· 2027 2026 exit(EXIT_FAILURE); 2028 2027 } 2029 2028 2029 + /* Notify the server if the connect() is successful or the 2030 + * receiver connection queue is full, so it will do accept() 2031 + * to drain it. 2032 + */ 2033 + if (!ret || errno == ECONNRESET) 2034 + send_control = true; 2035 + 2030 2036 /* Set CID to 0 cause a transport change. */ 2031 2037 sa.svm_cid = 0; 2032 2038 2033 - /* Ignore return value since it can fail or not. 2034 - * If the previous connect is interrupted while the 2035 - * connection request is already sent, the second 2039 + /* There is a case where this will not fail: 2040 + * if the previous connect() is interrupted while the 2041 + * connection request is already sent, this second 2036 2042 * connect() will wait for the response. 2037 2043 */ 2038 - connect(s, (struct sockaddr *)&sa, sizeof(sa)); 2044 + ret = connect(s, (struct sockaddr *)&sa, sizeof(sa)); 2045 + if (!ret || errno == ECONNRESET) 2046 + send_control = true; 2039 2047 2040 2048 close(s); 2041 2049 2042 - control_writeulong(CONTROL_CONTINUE); 2050 + if (send_control) 2051 + control_writeulong(CONTROL_CONTINUE); 2043 2052 2044 2053 } while (current_nsec() < tout); 2045 2054