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;