diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2026-03-09 13:20:35 +0100 |
|---|---|---|
| committer | Michael Tokarev <mjt@tls.msk.ru> | 2026-03-13 10:16:27 +0300 |
| commit | 82600ca4073c4dcb20aa348b8c1f5b2db21683a7 (patch) | |
| tree | 265fc7441d719b3c90b5df3d068455b5df578af0 | |
| parent | 561ddd82ea06e3ef78ca043f3929924df012a2f5 (diff) | |
| download | qemu-82600ca4073c4dcb20aa348b8c1f5b2db21683a7.tar.gz qemu-82600ca4073c4dcb20aa348b8c1f5b2db21683a7.zip | |
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>
(cherry picked from commit 4f28b87fdd24df2049626106b7c24d0180952115)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
| -rw-r--r-- | hw/hyperv/syndbg.c | 23 |
1 files changed, 11 insertions, 12 deletions
diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c index ac7e15f6f1..11f66aedf1 100644 --- a/hw/hyperv/syndbg.c +++ b/hw/hyperv/syndbg.c @@ -193,7 +193,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; @@ -222,29 +222,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; } |
