Commit fa9e186ab6 for qemu.org

commit fa9e186ab673f0f2d08b4202f0e06367998cd75c
Author: Michael S. Tsirkin <mst@redhat.com>
Date:   Fri Sep 4 18:18:56 2026 -0400

    virtio-net: validate IHL in virtio_net_rsc_extract_unit4 before use

    virtio_net_rsc_extract_unit4() uses the IPv4 IHL nibble from the
    wire to compute the TCP header offset, but the caller's length
    check only guarantees space for a minimum 20-byte IP header. A
    crafted IHL of 15 causes a read 32 bytes past a 66-byte buffer
    when the frame was parked in net/queue.c's exact-size allocation.

    virtio_net_rsc_sanity_check4() rejects IHL != 5 on the next line,
    but runs after the OOB read already happened.

    Validate IHL before using it as an offset. Since
    virtio_net_rsc_sanity_check4() only accepts IHL == 5 anyway, reject
    anything else early and let the caller fall through to the bypass
    path.

    Fixes: 2974e916df ("virtio-net: support RSC v4/v6 tcp traffic for Windows HCK")
    Cc: Jason Wang <jasowangio@gmail.com>
    Cc: Yuri Benditovich <yuri.benditovich@daynix.com>
    Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4166
    Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 986ceff514..19f453fb7d 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -2104,6 +2104,14 @@ static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain,
     unit->ip = (void *)ip;
     ip_hdrlen = (ip->ip_ver_len & 0xF) << 2;
     unit->ip_plen = &ip->ip_len;
+
+    if (ip_hdrlen != sizeof(struct ip_header)) {
+        unit->tcp = NULL;
+        unit->tcp_hdrlen = 0;
+        unit->payload = 0;
+        return;
+    }
+
     unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen);
     unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10;
     unit->payload = read_unit_ip_len(unit) - ip_hdrlen - unit->tcp_hdrlen;