@samitouri / QOSamiQemu / commits / 4f28b87fdd

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