From 4725a997cce8f3f0f3226a92919eaf74478c594e Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Wed, 6 May 2026 15:08:48 +0100 Subject: [PATCH] virtio-devices: console: Handle input queue errors gracefully Address translation or guest memory write failures on the receiveq propagated errors that killed the console device thread. Log a warning and break out of the descriptor loop instead. Also fix a data-loss bug: bytes were drained from the input buffer before the write to guest memory, so a failed write would silently discard the data. Copy first, write, then drain only on success. Signed-off-by: Rob Bradford Assisted-by: Claude:claude-opus-4-6 --- virtio-devices/src/console.rs | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/virtio-devices/src/console.rs b/virtio-devices/src/console.rs index 4e157a55a..9900a6164 100644 --- a/virtio-devices/src/console.rs +++ b/virtio-devices/src/console.rs @@ -53,8 +53,6 @@ const VIRTIO_CONSOLE_F_SIZE: u64 = 0; enum Error { #[error("Failed to read from guest memory")] GuestMemoryRead(#[source] vm_memory::guest_memory::Error), - #[error("Failed to write to guest memory")] - GuestMemoryWrite(#[source] vm_memory::guest_memory::Error), #[error("Failed to write_all output")] OutputWriteAll(#[source] io::Error), #[error("Failed to flush output")] @@ -217,22 +215,24 @@ impl ConsoleEpollHandler { warn!("Skipping device-readable descriptor on receiveq"); continue; } - let len = cmp::min(desc.len(), in_buffer.len() as u32); - let source_slice = in_buffer.drain(..len as usize).collect::>(); - - desc_chain - .memory() - .write_slice( - &source_slice[..], - desc.addr() - .translate_gva(self.access_platform.as_deref(), desc.len() as usize) - .map_err(|e| { - Error::GuestMemoryWrite(vm_memory::GuestMemoryError::IOError(e)) - })?, - ) - .map_err(Error::GuestMemoryWrite)?; - - total_len += len; + let len = cmp::min(desc.len() as usize, in_buffer.len()); + let addr = match desc + .addr() + .translate_gva(self.access_platform.as_deref(), desc.len() as usize) + { + Ok(a) => a, + Err(e) => { + warn!("Failed to translate receiveq descriptor address: {e}"); + break; + } + }; + let source: Vec = in_buffer.range(..len).copied().collect(); + if let Err(e) = desc_chain.memory().write_slice(&source, addr) { + warn!("Failed to write to receiveq descriptor: {e}"); + break; + } + in_buffer.drain(..len); + total_len += len as u32; } recv_queue