From fc96fcccdce3a6bf85e00239db7a6150d32f2400 Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Thu, 5 Mar 2026 01:24:41 +0000 Subject: [PATCH] virtio_net: fix write_data delivering corrupt packets on guest memory failure write_data previously set the packet length unconditionally, even when the guest memory write failed. This caused corrupt or partial data to be delivered to the guest. Additionally, write_header would panic on its length assertion since the stored length didn't match reality. Fix write_data to only update the packet length on success. Add an early return in write_header when len is 0, allowing the packet to complete with zero length so the guest discards it. --- vm/devices/virtio/virtio_net/src/buffers.rs | 22 ++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/vm/devices/virtio/virtio_net/src/buffers.rs b/vm/devices/virtio/virtio_net/src/buffers.rs index 3733e5c5ae..b0e80a9f9d 100644 --- a/vm/devices/virtio/virtio_net/src/buffers.rs +++ b/vm/devices/virtio/virtio_net/src/buffers.rs @@ -77,14 +77,18 @@ impl BufferAccess for VirtioWorkPool { fn write_data(&mut self, id: RxId, data: &[u8]) { let mut locked_packet = self.rx_packets[id.0 as usize].lock(); let work = locked_packet.work.as_ref().expect("invalid buffer index"); - if let Err(err) = work.write_at_offset(header_size() as u64, &self.mem, data) { - tracing::warn!( - len = data.len(), - error = &err as &dyn std::error::Error, - "rx memory write failure" - ); + match work.write_at_offset(header_size() as u64, &self.mem, data) { + Ok(()) => { + locked_packet.len = (header_size() + data.len()) as u32; + } + Err(err) => { + tracing::warn!( + len = data.len(), + error = &err as &dyn std::error::Error, + "rx memory write failure" + ); + } } - locked_packet.len = (header_size() + data.len()) as u32; } fn guest_addresses(&mut self, id: RxId) -> &[RxBufferSegment] { @@ -124,6 +128,10 @@ impl BufferAccess for VirtioWorkPool { ..FromZeros::new_zeroed() }; let locked_packet = self.rx_packets[id.0 as usize].lock(); + if locked_packet.len == 0 { + // write_data failed; skip header and let the packet complete with zero length. + return; + } let work = locked_packet.work.as_ref().expect("invalid buffer index"); assert_eq!(metadata.len + header_size(), locked_packet.len as usize); if let Err(err) = work.write(&self.mem, &virtio_net_header.as_bytes()[..header_size()]) {