summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Deacon <will@kernel.org>2025-07-17 10:01:09 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-08-28 16:30:59 +0200
commitfaf332a10372390ce65d0b803888f4b25a388335 (patch)
tree877a55bb8be34aad44f06590415e5e287edd3975
parent7c001febe46a5df88aa893cf02d41a1048ad07f0 (diff)
vsock/virtio: Validate length in packet header before skb_put()
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>
-rw-r--r--net/vmw_vsock/virtio_transport.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index f01f9e878106..1ef6f7829d29 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -624,8 +624,9 @@ static void virtio_transport_rx_work(struct work_struct *work)
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
@@ -642,12 +643,19 @@ static void virtio_transport_rx_work(struct work_struct *work)
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);
virtio_transport_recv_pkt(&virtio_transport, skb);