Commit 4f28b87fdd for qemu.org

commit 4f28b87fdd24df2049626106b7c24d0180952115
Author: Paolo Bonzini <pbonzini@redhat.com>
Date:   Mon Mar 9 13:20:35 2026 +0100

    hyperv/syndbg: check length returned by cpu_physical_memory_map()

    If cpu_physical_memory_map() returns a length shorter than the one
    that was passed into the function, writing the full out_len bytes
    causes an access beyond the memory allocated to the guest; or in
    the case of the MMIO bounce buffer, an out-of-bounds access in a
    heap-allocated object.

    Add a check similar to the one already in handle_send_msg(),
    and take the occasion to remove repeated computations of
    recv_byte_count + UDP_PKT_HEADER_SIZE and clarify that the
    code does not write past out_len bytes.

    Reported-by: Oleh Konko <https://github.com/1seal>
    Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
    Fixes: CVE-2026-3842
    Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c
index 1e177f9dd8..10171b19e8 100644
--- a/hw/hyperv/syndbg.c
+++ b/hw/hyperv/syndbg.c
@@ -194,7 +194,7 @@ static uint16_t handle_recv_msg(HvSynDbg *syndbg, uint64_t outgpa,
     uint16_t ret;
     g_assert(MSG_BUFSZ >= qemu_target_page_size());
     QEMU_UNINITIALIZED uint8_t data_buf[MSG_BUFSZ];
-    hwaddr out_len;
+    hwaddr out_len, out_requested_len;
     void *out_data;
     ssize_t recv_byte_count;

@@ -223,29 +223,28 @@ static uint16_t handle_recv_msg(HvSynDbg *syndbg, uint64_t outgpa,
     if (is_raw) {
         out_len += UDP_PKT_HEADER_SIZE;
     }
+    out_requested_len = out_len;
     out_data = cpu_physical_memory_map(outgpa, &out_len, 1);
-    if (!out_data) {
-        return HV_STATUS_INSUFFICIENT_MEMORY;
+    ret = HV_STATUS_INSUFFICIENT_MEMORY;
+    if (!out_data || out_len < out_requested_len) {
+        goto cleanup_out_data;
     }

     if (is_raw &&
-        !create_udp_pkt(syndbg, out_data,
-                        recv_byte_count + UDP_PKT_HEADER_SIZE,
+        !create_udp_pkt(syndbg, out_data, out_len,
                         data_buf, recv_byte_count)) {
-        ret = HV_STATUS_INSUFFICIENT_MEMORY;
         goto cleanup_out_data;
     } else if (!is_raw) {
-        memcpy(out_data, data_buf, recv_byte_count);
+        memcpy(out_data, data_buf, out_len);
     }

-    *retrieved_count = recv_byte_count;
-    if (is_raw) {
-        *retrieved_count += UDP_PKT_HEADER_SIZE;
-    }
+    *retrieved_count = out_len;
     ret = HV_STATUS_SUCCESS;

 cleanup_out_data:
-    cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
+    if (out_data) {
+        cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
+    }
     return ret;
 }