]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
vsock/virtio: reset connection on receiving queue overflow
authorStefano Garzarella <sgarzare@redhat.com>
Mon, 18 May 2026 09:06:55 +0000 (11:06 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 21 May 2026 11:14:01 +0000 (13:14 +0200)
When there is no more space to queue an incoming packet, the packet is
silently dropped. This causes data loss without any notification to
either peer, since there is no retransmission.

Under normal circumstances, this should never happen. However, it could
happen if the other peer doesn't respect the credit, or if the skb
overhead, which we recently began to take into account with commit
059b7dbd20a6 ("vsock/virtio: fix potential unbounded skb queue"),
is too high.

Fix this by resetting the connection and setting the local socket error
to ENOBUFS when virtio_transport_recv_enqueue() can no longer queue a
packet, so both peers are explicitly notified of the failure rather than
silently losing data.

Fixes: ae6fcfbf5f03 ("vsock/virtio: discard packets if credit is not respected")
Cc: stable@vger.kernel.org
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Link: https://patch.msgid.link/20260518090656.134588-2-sgarzare@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/vmw_vsock/virtio_transport_common.c

index 1e3409d28164e8e2f95a1996c1df32ab0ee792cd..5028ff5348887c21015bc96444790f939229ca9d 100644 (file)
@@ -1335,7 +1335,7 @@ destroy:
        return err;
 }
 
-static void
+static bool
 virtio_transport_recv_enqueue(struct vsock_sock *vsk,
                              struct sk_buff *skb)
 {
@@ -1350,10 +1350,8 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk,
        spin_lock_bh(&vvs->rx_lock);
 
        can_enqueue = virtio_transport_inc_rx_pkt(vvs, len);
-       if (!can_enqueue) {
-               free_pkt = true;
+       if (!can_enqueue)
                goto out;
-       }
 
        if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM)
                vvs->msg_count++;
@@ -1393,6 +1391,8 @@ out:
        spin_unlock_bh(&vvs->rx_lock);
        if (free_pkt)
                kfree_skb(skb);
+
+       return can_enqueue;
 }
 
 static int
@@ -1405,7 +1405,17 @@ virtio_transport_recv_connected(struct sock *sk,
 
        switch (le16_to_cpu(hdr->op)) {
        case VIRTIO_VSOCK_OP_RW:
-               virtio_transport_recv_enqueue(vsk, skb);
+               if (!virtio_transport_recv_enqueue(vsk, skb)) {
+                       /* There is no more space to queue the packet, so let's
+                        * close the connection; otherwise, we'll lose data.
+                        */
+                       (void)virtio_transport_reset(vsk, skb);
+                       virtio_transport_do_close(vsk, true);
+                       sk->sk_err = ENOBUFS;
+                       sk_error_report(sk);
+                       vsock_remove_sock(vsk);
+                       break;
+               }
                vsock_data_ready(sk);
                return err;
        case VIRTIO_VSOCK_OP_CREDIT_REQUEST: