Skip to content

Commit

Permalink
vsock/virtio: remove socket from connected/bound list on shutdown
Browse files Browse the repository at this point in the history
If the same remote peer, using the same port, tries to connect
to a server on a listening port more than once, the server will
reject the connection, causing a "connection reset by peer"
error on the remote peer. This is due to the presence of a
dangling socket from a previous connection in both the connected
and bound socket lists.
The inconsistency of the above lists only occurs when the remote
peer disconnects and the server remains active.

This bug does not occur when the server socket is closed:
virtio_transport_release() will eventually schedule a call to
virtio_transport_do_close() and the latter will remove the socket
from the bound and connected socket lists and clear the sk_buff.

However, virtio_transport_do_close() will only perform the above
actions if it has been scheduled, and this will not happen
if the server is processing the shutdown message from a remote peer.

To fix this, introduce a call to vsock_remove_sock()
when the server is handling a client disconnect.
This is to remove the socket from the bound and connected socket
lists without clearing the sk_buff.

Fixes: 06a8fc7 ("VSOCK: Introduce virtio_vsock_common.ko")
Reported-by: Daan De Meyer <[email protected]>
Tested-by: Daan De Meyer <[email protected]>
Co-developed-by: Luigi Leonardi <[email protected]>
Signed-off-by: Luigi Leonardi <[email protected]>
Signed-off-by: Filippo Storniolo <[email protected]>
Reviewed-by: Stefano Garzarella <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
fstorniolo authored and davem330 committed Nov 7, 2023
1 parent 7425627 commit 3a5cc90
Showing 1 changed file with 11 additions and 5 deletions.
16 changes: 11 additions & 5 deletions net/vmw_vsock/virtio_transport_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1369,11 +1369,17 @@ virtio_transport_recv_connected(struct sock *sk,
vsk->peer_shutdown |= RCV_SHUTDOWN;
if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_SEND)
vsk->peer_shutdown |= SEND_SHUTDOWN;
if (vsk->peer_shutdown == SHUTDOWN_MASK &&
vsock_stream_has_data(vsk) <= 0 &&
!sock_flag(sk, SOCK_DONE)) {
(void)virtio_transport_reset(vsk, NULL);
virtio_transport_do_close(vsk, true);
if (vsk->peer_shutdown == SHUTDOWN_MASK) {
if (vsock_stream_has_data(vsk) <= 0 && !sock_flag(sk, SOCK_DONE)) {
(void)virtio_transport_reset(vsk, NULL);
virtio_transport_do_close(vsk, true);
}
/* Remove this socket anyway because the remote peer sent
* the shutdown. This way a new connection will succeed
* if the remote peer uses the same source port,
* even if the old socket is still unreleased, but now disconnected.
*/
vsock_remove_sock(vsk);
}
if (le32_to_cpu(virtio_vsock_hdr(skb)->flags))
sk->sk_state_change(sk);
Expand Down

0 comments on commit 3a5cc90

Please sign in to comment.