Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 1 · Low: 1

- [Medium] The new consumer in vsock_connect() reads the poison flag with
  READ_ONCE(vsk->peer_shutdown) (net/vmw_vsock/af_vsock.c:1747), but the…
- [Low] Undeclared intra-series dependency: the new guard in
  vsock_connect() (net/vmw_vsock/af_vsock.c:1747) only *reads*…

--

vsock: Handle sudden TCP_CLOSE during connect

This adds a check in vsock_connect() that refuses a fresh connect attempt
with -ECONNRESET when vsk->peer_shutdown is already set, so that a socket
poisoned by a lockless virtio/PM/vhost/VMCI reset event cannot be handed a
new transport or pushed back into TCP_SYN_SENT.

> diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
> index adf3f018347ea..972952d04a81a 100644
> --- a/net/vmw_vsock/af_vsock.c
> +++ b/net/vmw_vsock/af_vsock.c
> @@ -1743,6 +1743,12 @@ static int vsock_connect(struct socket *sock, struct 
> sockaddr_unsized *addr,
>                       goto out;
>               }
>
> +             /* Virtio/PM events are serviced locklessly. */
> +             if (READ_ONCE(vsk->peer_shutdown)) {
> +                     err = -ECONNRESET;
> +                     goto out;
> +             }
> +

[Severity: Low]
The comment mentions virtio/PM events, but this hunk only reads
vsk->peer_shutdown.  For the virtio/PM path the flag is published by
virtio_vsock_reset_sock() in net/vmw_vsock/virtio_transport.c:

        vsk->peer_shutdown = SHUTDOWN_MASK;
        sk->sk_state = TCP_CLOSE;
        sk->sk_err = ECONNRESET;

That store comes from the immediately preceding patch in this series
("vsock/virtio: Streamline socket reset on transport/PM event"); at the
parent commit virtio_vsock_reset_sock() only sets sk_state and sk_err.

Given the Fixes: d021c344051a tag reaching back to 2013, would it be worth
spelling out the dependency so that a stable/AUTOSEL pick does not take this
commit alone?  On its own the new check would be a no-op for exactly the
virtio/PM scenario the changelog leads with, and only vhost's
vhost_vsock_reset_orphans() and VMCI's vmci_transport_handle_detach() (which
already set the flag) would be covered.

[Severity: Medium]
Should the writers of this flag be marked to match the new READ_ONCE()
reader?  The two handlers named in the changelog store it plainly:

net/vmw_vsock/virtio_transport.c:virtio_vsock_reset_sock() {
        vsk->peer_shutdown = SHUTDOWN_MASK;
        sk->sk_state = TCP_CLOSE;
        sk->sk_err = ECONNRESET;
        sk_error_report(sk);
}

drivers/vhost/vsock.c:vhost_vsock_reset_orphans() {
        sock_set_flag(sk, SOCK_DONE);
        vsk->peer_shutdown = SHUTDOWN_MASK;
        sk->sk_state = TCP_CLOSE;
        sk->sk_err = ECONNRESET;
}

Both run from vsock_for_each_connected_socket() under
spin_lock_bh(&vsock_table_lock) only, never under lock_sock(), so they share
no lock with vsock_connect().  Every other lockless writer of the field uses
WRITE_ONCE(), for example vmci_transport_handle_detach(),
virtio_transport_recv_pkt() in virtio_transport_common.c and
hvs_close_connection() in hyperv_transport.c.  Is the plain store racing the
new marked read something KCSAN would flag here?

There is also no barrier pairing the poison store with the sk_state/sk_err
stores that connect() actually leaves its wait loop on.  Can the following
still happen on a weakly ordered machine?

        connect() wait loop exits on timeout/signal:
                sk->sk_state = TCP_CLOSE;
                sock->state = SS_UNCONNECTED;
                vsock_transport_cancel_pkt(vsk);

        userspace retries connect(), reads peer_shutdown == 0,
        falls through to vsock_assign_transport() and
                sk->sk_state = TCP_SYN_SENT;

while the socket is still hashed in connected_table.  A later OP_RESPONSE
then reaches virtio_transport_recv_connecting(), which calls
vsock_insert_connected() unconditionally, and __vsock_insert_connected() does
a bare list_add() on an already-linked node.  That is the list_add double add
splat described in the sibling commit 6f06a44e.

Would a WRITE_ONCE() for both stores, plus explicit ordering between the
peer_shutdown store and the sk_state/sk_err stores, close that window?

-- 
Sashiko AI review · 
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260915-vsock-connect-reset-closing-v2-0-a1d9abb472f7%40rbox.co

Reply via email to