aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2024-01-02 11:29:01 +0800
committerMichael Tokarev <mjt@tls.msk.ru>2024-01-26 16:20:04 +0300
commitdd1d3c8c29144e8e3bb89d18fd7feed4b65d328d (patch)
tree44d1a8c37818542e15225fbd0b08df1b8e33f268
parentc173670033940211980fb78653f777fa1307d2a6 (diff)
downloadqemu-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.c13
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,