A crash found while fuzzing device virtio-net-socket-check-used. Assertion "offset == 0" in iov_copy() fails if less than guest_hdr_len bytes were transmited.
Signed-off-by: Dmitry Frolov <fro...@swemel.ru> --- v1: https://patchew.org/QEMU/20240527133140.218300-2-fro...@swemel.ru/ v2: replaced repeating code with goto --- hw/net/virtio-net.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 24e5e7d347..424bada8cf 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -2749,18 +2749,14 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) out_sg = elem->out_sg; if (out_num < 1) { virtio_error(vdev, "virtio-net header not in first element"); - virtqueue_detach_element(q->tx_vq, elem, 0); - g_free(elem); - return -EINVAL; + goto error; } if (n->has_vnet_hdr) { 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); - g_free(elem); - return -EINVAL; + goto error; } if (n->needs_vnet_hdr_swap) { virtio_net_hdr_swap(vdev, (void *) &vhdr); @@ -2783,6 +2779,10 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) */ assert(n->host_hdr_len <= n->guest_hdr_len); if (n->host_hdr_len != n->guest_hdr_len) { + if (iov_size(out_sg, out_num) < n->guest_hdr_len) { + virtio_error(vdev, "virtio-net header is invalid"); + goto error; + } unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg), out_sg, out_num, 0, n->host_hdr_len); @@ -2811,6 +2811,11 @@ drop: } } return num_packets; + +error: + virtqueue_detach_element(q->tx_vq, elem, 0); + g_free(elem); + return -EINVAL; } static void virtio_net_tx_timer(void *opaque); -- 2.43.0