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>
Paolo Bonzini committed
Mar 9, 2026 at 13:20 UTC
4f28b87fdd24df2049626106b7c24d0180952115
1 file changed
+11
-12
hw/hyperv/syndbg.c
+11
-12
@@ -194,7 +194,7 @@ static uint16_t handle_recv_msg(HvSynDbg *syndbg, uint64_t outgpa,
194
uint16_t ret;
195
g_assert(MSG_BUFSZ >= qemu_target_page_size());
196
QEMU_UNINITIALIZED uint8_t data_buf[MSG_BUFSZ];
197
- hwaddr out_len;
197
+ hwaddr out_len, out_requested_len;
198
void *out_data;
199
ssize_t recv_byte_count;
200
@@ -223,29 +223,28 @@ static uint16_t handle_recv_msg(HvSynDbg *syndbg, uint64_t outgpa,
223
if (is_raw) {
224
out_len += UDP_PKT_HEADER_SIZE;
225
}
226
+ out_requested_len = out_len;
227
out_data = cpu_physical_memory_map(outgpa, &out_len, 1);
227
- if (!out_data) {
228
- return HV_STATUS_INSUFFICIENT_MEMORY;
228
+ ret = HV_STATUS_INSUFFICIENT_MEMORY;
229
+ if (!out_data || out_len < out_requested_len) {
230
+ goto cleanup_out_data;
231
}
232
233
if (is_raw &&
232
- !create_udp_pkt(syndbg, out_data,
233
- recv_byte_count + UDP_PKT_HEADER_SIZE,
234
+ !create_udp_pkt(syndbg, out_data, out_len,
235
data_buf, recv_byte_count)) {
235
- ret = HV_STATUS_INSUFFICIENT_MEMORY;
236
goto cleanup_out_data;
237
} else if (!is_raw) {
238
- memcpy(out_data, data_buf, recv_byte_count);
238
+ memcpy(out_data, data_buf, out_len);
239
}
240
241
- *retrieved_count = recv_byte_count;
242
- if (is_raw) {
243
- *retrieved_count += UDP_PKT_HEADER_SIZE;
244
- }
241
+ *retrieved_count = out_len;
242
ret = HV_STATUS_SUCCESS;
243
244
cleanup_out_data:
248
- cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
245
+ if (out_data) {
246
+ cpu_physical_memory_unmap(out_data, out_len, 1, out_len);
247
+ }
248
return ret;
249
}
250