Skip to content

Commit 3ef3d52

Browse files
melbinkmPaolo Abeni
authored andcommitted
vsock/virtio: fix potential underflow in virtio_transport_get_credit()
The credit calculation in virtio_transport_get_credit() uses unsigned arithmetic: ret = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); If the peer shrinks its advertised buffer (peer_buf_alloc) while bytes are in flight, the subtraction can underflow and produce a large positive value, potentially allowing more data to be queued than the peer can handle. Reuse virtio_transport_has_space() which already handles this case and add a comment to make it clear why we are doing that. Fixes: 06a8fc7 ("VSOCK: Introduce virtio_vsock_common.ko") Suggested-by: Stefano Garzarella <sgarzare@redhat.com> Signed-off-by: Melbin K Mathew <mlbnkm1@gmail.com> [Stefano: use virtio_transport_has_space() instead of duplicating the code] [Stefano: tweak the commit message] Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> Reviewed-by: Luigi Leonardi <leonardi@redhat.com> Link: https://patch.msgid.link/20260121093628.9941-2-sgarzare@redhat.com Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent ca1bb3f commit 3ef3d52

1 file changed

Lines changed: 9 additions & 7 deletions

File tree

net/vmw_vsock/virtio_transport_common.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
static void virtio_transport_cancel_close_work(struct vsock_sock *vsk,
3030
bool cancel_timeout);
31+
static s64 virtio_transport_has_space(struct virtio_vsock_sock *vvs);
3132

3233
static const struct virtio_transport *
3334
virtio_transport_get_ops(struct vsock_sock *vsk)
@@ -499,9 +500,7 @@ u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 credit)
499500
return 0;
500501

501502
spin_lock_bh(&vvs->tx_lock);
502-
ret = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt);
503-
if (ret > credit)
504-
ret = credit;
503+
ret = min_t(u32, credit, virtio_transport_has_space(vvs));
505504
vvs->tx_cnt += ret;
506505
vvs->bytes_unsent += ret;
507506
spin_unlock_bh(&vvs->tx_lock);
@@ -877,11 +876,14 @@ u32 virtio_transport_seqpacket_has_data(struct vsock_sock *vsk)
877876
}
878877
EXPORT_SYMBOL_GPL(virtio_transport_seqpacket_has_data);
879878

880-
static s64 virtio_transport_has_space(struct vsock_sock *vsk)
879+
static s64 virtio_transport_has_space(struct virtio_vsock_sock *vvs)
881880
{
882-
struct virtio_vsock_sock *vvs = vsk->trans;
883881
s64 bytes;
884882

883+
/* Use s64 arithmetic so if the peer shrinks peer_buf_alloc while
884+
* we have bytes in flight (tx_cnt - peer_fwd_cnt), the subtraction
885+
* does not underflow.
886+
*/
885887
bytes = (s64)vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt);
886888
if (bytes < 0)
887889
bytes = 0;
@@ -895,7 +897,7 @@ s64 virtio_transport_stream_has_space(struct vsock_sock *vsk)
895897
s64 bytes;
896898

897899
spin_lock_bh(&vvs->tx_lock);
898-
bytes = virtio_transport_has_space(vsk);
900+
bytes = virtio_transport_has_space(vvs);
899901
spin_unlock_bh(&vvs->tx_lock);
900902

901903
return bytes;
@@ -1492,7 +1494,7 @@ static bool virtio_transport_space_update(struct sock *sk,
14921494
spin_lock_bh(&vvs->tx_lock);
14931495
vvs->peer_buf_alloc = le32_to_cpu(hdr->buf_alloc);
14941496
vvs->peer_fwd_cnt = le32_to_cpu(hdr->fwd_cnt);
1495-
space_available = virtio_transport_has_space(vsk);
1497+
space_available = virtio_transport_has_space(vvs);
14961498
spin_unlock_bh(&vvs->tx_lock);
14971499
return space_available;
14981500
}

0 commit comments

Comments
 (0)