summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2026-03-09 13:20:35 +0100
committerMichael Tokarev <mjt@tls.msk.ru>2026-03-13 10:16:27 +0300
commit82600ca4073c4dcb20aa348b8c1f5b2db21683a7 (patch)
tree265fc7441d719b3c90b5df3d068455b5df578af0
parent561ddd82ea06e3ef78ca043f3929924df012a2f5 (diff)
downloadqemu-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.c23
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;
}