| From 0dab92484474587b82e8e0455839eaf5ac7bf894 Mon Sep 17 00:00:00 2001 |
| From: Will Deacon <will@kernel.org> |
| Date: Thu, 17 Jul 2025 10:01:09 +0100 |
| Subject: vsock/virtio: Validate length in packet header before skb_put() |
| |
| From: Will Deacon <will@kernel.org> |
| |
| commit 0dab92484474587b82e8e0455839eaf5ac7bf894 upstream. |
| |
| When receiving a vsock packet in the guest, only the virtqueue buffer |
| size is validated prior to virtio_vsock_skb_rx_put(). Unfortunately, |
| virtio_vsock_skb_rx_put() uses the length from the packet header as the |
| length argument to skb_put(), potentially resulting in SKB overflow if |
| the host has gone wonky. |
| |
| Validate the length as advertised by the packet header before calling |
| virtio_vsock_skb_rx_put(). |
| |
| Cc: <stable@vger.kernel.org> |
| Fixes: 71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with sk_buff") |
| Signed-off-by: Will Deacon <will@kernel.org> |
| Message-Id: <20250717090116.11987-3-will@kernel.org> |
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> |
| Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/vmw_vsock/virtio_transport.c | 12 ++++++++++-- |
| 1 file changed, 10 insertions(+), 2 deletions(-) |
| |
| --- a/net/vmw_vsock/virtio_transport.c |
| +++ b/net/vmw_vsock/virtio_transport.c |
| @@ -497,8 +497,9 @@ static void virtio_transport_rx_work(str |
| do { |
| virtqueue_disable_cb(vq); |
| for (;;) { |
| + unsigned int len, payload_len; |
| + struct virtio_vsock_hdr *hdr; |
| struct sk_buff *skb; |
| - unsigned int len; |
| |
| if (!virtio_transport_more_replies(vsock)) { |
| /* Stop rx until the device processes already |
| @@ -515,11 +516,18 @@ static void virtio_transport_rx_work(str |
| vsock->rx_buf_nr--; |
| |
| /* Drop short/long packets */ |
| - if (unlikely(len < sizeof(struct virtio_vsock_hdr) || |
| + if (unlikely(len < sizeof(*hdr) || |
| len > virtio_vsock_skb_len(skb))) { |
| kfree_skb(skb); |
| continue; |
| } |
| + |
| + hdr = virtio_vsock_hdr(skb); |
| + payload_len = le32_to_cpu(hdr->len); |
| + if (unlikely(payload_len > len - sizeof(*hdr))) { |
| + kfree_skb(skb); |
| + continue; |
| + } |
| |
| virtio_vsock_skb_rx_put(skb); |
| virtio_transport_deliver_tap_pkt(skb); |