It is necessary to copy the header only for byte swapping. Worse, when
byte swapping is not needed, the header can be larger than the buffer
due to VIRTIO_NET_F_HASH_REPORT, which results in buffer overflow.
Copy the header only when byte swapping is needed.
Fixes: e22f0603fb ("virtio-net: reference implementation of hash report")
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
hw/net/virtio-net.c | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index e12176acb1..b6223031e1 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -359,7 +359,8 @@ static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status)
* can't do it, we fallback onto fixing the headers in the core
* virtio-net code.
*/
- n->needs_vnet_hdr_swap = virtio_net_set_vnet_endian(vdev, n->nic->ncs,
+ n->needs_vnet_hdr_swap = n->has_vnet_hdr &&
+ virtio_net_set_vnet_endian(vdev, n->nic->ncs,
queue_pairs, true);
} else if (virtio_net_started(n, vdev->status)) {
/* After using the device, we need to reset the network backend to
@@ -2709,7 +2710,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
return -EINVAL;
}
- if (n->has_vnet_hdr) {
+ if (n->needs_vnet_hdr_swap) {
if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) <
n->guest_hdr_len) {
virtio_error(vdev, "virtio-net header incorrect");
@@ -2717,19 +2718,16 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
g_free(elem);
return -EINVAL;
}
- if (n->needs_vnet_hdr_swap) {
- virtio_net_hdr_swap(vdev, (void *) &mhdr);
- sg2[0].iov_base = &mhdr;
- sg2[0].iov_len = n->guest_hdr_len;
- out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
- out_sg, out_num,
- n->guest_hdr_len, -1);
- if (out_num == VIRTQUEUE_MAX_SIZE) {
- goto drop;
- }
- out_num += 1;
- out_sg = sg2;
+ virtio_net_hdr_swap(vdev, (void *) &mhdr);
+ sg2[0].iov_base = &mhdr;
+ sg2[0].iov_len = n->guest_hdr_len;
+ out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1, out_sg, out_num,
+ n->guest_hdr_len, -1);
+ if (out_num == VIRTQUEUE_MAX_SIZE) {
+ goto drop;
}
+ out_num += 1;
+ out_sg = sg2;
}
/*
* If host wants to see the guest header as is, we can
--
2.42.1