mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
net_util: queue_pair: Handle RX readv EINVAL gracefully
When readv from the TAP returns EINVAL the guest posted a buffer too small for the vnet_hdr. Return len 0 to the used ring and continue instead of killing the worker thread. Also move go_to_previous_position into the appropriate error branches only. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
committed by
Rob Bradford
parent
02ea839838
commit
c71a8ea8dd
+27
-19
@@ -272,33 +272,41 @@ impl RxVirtio {
|
|||||||
};
|
};
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
let e = std::io::Error::last_os_error();
|
let e = std::io::Error::last_os_error();
|
||||||
exhausted_descs = false;
|
|
||||||
queue.go_to_previous_position();
|
|
||||||
|
|
||||||
/* EAGAIN */
|
/* EAGAIN */
|
||||||
if e.kind() == std::io::ErrorKind::WouldBlock {
|
if e.kind() == std::io::ErrorKind::WouldBlock {
|
||||||
|
exhausted_descs = false;
|
||||||
|
queue.go_to_previous_position();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
error!("net: rx: failed reading from tap: {e}");
|
if e.raw_os_error() == Some(libc::EINVAL) {
|
||||||
return Err(NetQueuePairError::ReadTap(e));
|
error!("net: rx: dropping undersized buffer: {e}");
|
||||||
}
|
desc_chain
|
||||||
|
.memory()
|
||||||
if (result as usize) < vnet_hdr_len() {
|
.write_obj(0u16, num_buffers_addr)
|
||||||
|
.map_err(NetQueuePairError::GuestMemory)?;
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
queue.go_to_previous_position();
|
||||||
|
error!("net: rx: failed reading from tap: {e}");
|
||||||
|
return Err(NetQueuePairError::ReadTap(e));
|
||||||
|
}
|
||||||
|
} else if (result as usize) < vnet_hdr_len() {
|
||||||
return Err(NetQueuePairError::InvalidVirtioNetHeader);
|
return Err(NetQueuePairError::InvalidVirtioNetHeader);
|
||||||
|
} else {
|
||||||
|
// Write num_buffers to guest memory. Always 1 because the
|
||||||
|
// frame is never spread over more than one descriptor chain.
|
||||||
|
desc_chain
|
||||||
|
.memory()
|
||||||
|
.write_obj(1u16, num_buffers_addr)
|
||||||
|
.map_err(NetQueuePairError::GuestMemory)?;
|
||||||
|
|
||||||
|
self.counter_bytes += Wrapping(result as u64 - vnet_hdr_len() as u64);
|
||||||
|
self.counter_frames += Wrapping(1);
|
||||||
|
|
||||||
|
result as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write num_buffers to guest memory. We simply write 1 as we
|
|
||||||
// never spread the frame over more than one descriptor chain.
|
|
||||||
desc_chain
|
|
||||||
.memory()
|
|
||||||
.write_obj(1u16, num_buffers_addr)
|
|
||||||
.map_err(NetQueuePairError::GuestMemory)?;
|
|
||||||
|
|
||||||
self.counter_bytes += Wrapping(result as u64 - vnet_hdr_len() as u64);
|
|
||||||
self.counter_frames += Wrapping(1);
|
|
||||||
|
|
||||||
result as u32
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// For the sake of simplicity (keeping the handling of RX_QUEUE_EVENT and
|
// For the sake of simplicity (keeping the handling of RX_QUEUE_EVENT and
|
||||||
|
|||||||
Reference in New Issue
Block a user