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é <[email protected]> Fixes: CVE-2026-3842 Signed-off-by: Paolo Bonzini <[email protected]> --- hw/hyperv/syndbg.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c index 1e177f9dd82..10171b19e8f 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; } -- 2.53.0
