virtio-devices: block: cap submit-loop iterations to virtqueue size

process_queue_submit's drain loop builds a fresh queue.iter() per
iteration, which re-reads the guest avail index on every call and has
no per-call cap (the per-iter gap check in virtio-queue only protects
against avail_idx jumping more than queue_size between two reads).
In theory, a malicous or buggy guest could keep adding descriptors and
cause this loop to overflow the iouring submit queue.

Cap a single drain at queue_size. A spec-compliant driver never
produces more than queue_size outstanding entries simultaneously, so
the cap is invisible to well-behaved guests.

Signed-off-by: Dylan Reid <dgreid@fb.com>
This commit is contained in:
Dylan Reid
2026-04-24 17:05:27 -07:00
committed by Rob Bradford
parent 48e671011c
commit fbcf2fd6b0

View File

@@ -235,10 +235,18 @@ Setting device status to 'NEEDS_RESET' and stopping processing queues until rese
return Ok(());
}
let queue = &mut self.queue;
let queue_size = queue.size();
let mut batch_requests = Vec::new();
let mut batch_inflight_requests = Vec::new();
let mut processed = 0;
loop {
// Cap a single drain at the virtqueue size. A compliant driver won't submit more that
// queue_size, but a buggy or malicious one can keep adding as the VMM is reading.
if processed >= queue_size {
break;
}
processed += 1;
let mut desc_chain = match queue.iter(self.mem.memory()) {
Ok(mut iter) => match iter.next() {
Some(c) => c,