diff options
author | Jason Wang <jasowang@redhat.com> | 2024-01-02 11:29:01 +0800 |
---|---|---|
committer | Michael Tokarev <mjt@tls.msk.ru> | 2024-01-26 16:20:04 +0300 |
commit | dd1d3c8c29144e8e3bb89d18fd7feed4b65d328d (patch) | |
tree | 44d1a8c37818542e15225fbd0b08df1b8e33f268 | |
parent | c173670033940211980fb78653f777fa1307d2a6 (diff) | |
download | qemu-dd1d3c8c29144e8e3bb89d18fd7feed4b65d328d.zip qemu-dd1d3c8c29144e8e3bb89d18fd7feed4b65d328d.tar.gz qemu-dd1d3c8c29144e8e3bb89d18fd7feed4b65d328d.tar.bz2 |
virtio-net: correctly copy vnet header when flushing TX
When HASH_REPORT is negotiated, the guest_hdr_len might be larger than
the size of the mergeable rx buffer header. Using
virtio_net_hdr_mrg_rxbuf during the header swap might lead a stack
overflow in this case. Fixing this by using virtio_net_hdr_v1_hash
instead.
Reported-by: Xiao Lei <leixiao.nop@zju.edu.cn>
Cc: Yuri Benditovich <yuri.benditovich@daynix.com>
Cc: qemu-stable@nongnu.org
Cc: Mauro Matteo Cascella <mcascell@redhat.com>
Fixes: CVE-2023-6693
Fixes: e22f0603fb2f ("virtio-net: reference implementation of hash report")
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit 2220e8189fb94068dbad333228659fbac819abb0)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
-rw-r--r-- | hw/net/virtio-net.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 9a93a2d..fbed66e 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -667,6 +667,11 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs, n->mergeable_rx_bufs = mergeable_rx_bufs; + /* + * Note: when extending the vnet header, please make sure to + * change the vnet header copying logic in virtio_net_flush_tx() + * as well. + */ if (version_1) { n->guest_hdr_len = hash_report ? sizeof(struct virtio_net_hdr_v1_hash) : @@ -2674,7 +2679,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) ssize_t ret; unsigned int out_num; struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg; - struct virtio_net_hdr_mrg_rxbuf mhdr; + struct virtio_net_hdr_v1_hash vhdr; elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement)); if (!elem) { @@ -2691,7 +2696,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) } if (n->has_vnet_hdr) { - if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) < + if (iov_to_buf(out_sg, out_num, 0, &vhdr, n->guest_hdr_len) < n->guest_hdr_len) { virtio_error(vdev, "virtio-net header incorrect"); virtqueue_detach_element(q->tx_vq, elem, 0); @@ -2699,8 +2704,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) return -EINVAL; } if (n->needs_vnet_hdr_swap) { - virtio_net_hdr_swap(vdev, (void *) &mhdr); - sg2[0].iov_base = &mhdr; + virtio_net_hdr_swap(vdev, (void *) &vhdr); + sg2[0].iov_base = &vhdr; sg2[0].iov_len = n->guest_hdr_len; out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1, out_sg, out_num, |