[Devel] [PATCH hci-8.1 v2] drivers/vhost/blk: reject a head that is still in flight

Alexander Ivanov alexander.ivanov at virtuozzo.com
Thu Oct 29 16:48:22 MSK 2026


vhost_blk_req_handle() takes the request slot by head and overwrites it
without checking that it is free. A guest that puts a head into the
avail ring again while its request is in flight makes the slot get
submitted twice: req_inflight is raised for each submission, but the
completion path sees one slot and calls forget_request() once.
req_inflight never drops to zero, and vhost_blk_flush() on backend drop
leaves QEMU in D state forever with the block device pinned. The second
submission also overwrites bio[], bio_nr and the iovecs of bios that
are still in flight, and frees the bounce buffer and bio[] of the first
submission under them, which is a use-after-free.

Mark a slot in flight from bio submission until its completion is
handled, both under vq->mutex, and fail the request if the guest posts
an in-flight head. Log the head and let the caller report the error on
the vq error eventfd and stop processing the ring. Allocate the slots
zeroed so the flag starts clear.

Fixes: d8722ff88c5d ("drivers/vhost: vhost-blk accelerator for virtio-blk guests")
Feature: vhost-blk: in-kernel accelerator for virtio-blk guests

Signed-off-by: Alexander Ivanov <alexander.ivanov at virtuozzo.com>
---
v2:
- note that the second submission frees buffers under in-flight bios
  (use-after-free)
- log the reused head with vhostblk_vq_err()

 drivers/vhost/blk.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/vhost/blk.c b/drivers/vhost/blk.c
index b170439a1806..aa646a598586 100644
--- a/drivers/vhost/blk.c
+++ b/drivers/vhost/blk.c
@@ -79,6 +79,7 @@ struct vhost_blk_req {
 	u16 head;
 	size_t len;
 	int bio_err;
+	bool inflight;
 
 	struct vhost_blk *blk;
 	struct vhost_blk_vq *blk_vq;
@@ -434,6 +435,7 @@ static int vhost_blk_req_submit(struct vhost_blk_req *req)
 	if (ret < 0)
 		goto out;
 
+	req->inflight = true;
 	vhost_blk_bio_send(req);
 	return ret;
 
@@ -457,6 +459,11 @@ static int vhost_blk_req_handle(struct vhost_virtqueue *vq,
 	u8 status;
 
 	req		= &blk_vq->req[head];
+	if (unlikely(req->inflight)) {
+		vhostblk_vq_err(blk, vq, "Guest reused in-flight head %d", head);
+		return -EBUSY;
+	}
+
 	req->blk_vq	= blk_vq;
 	req->head	= head;
 	req->blk	= blk;
@@ -628,6 +635,7 @@ static void vhost_blk_handle_host_kick(struct vhost_work *work)
 			added = true;
 		}
 
+		req->inflight = false;
 		forget_request(req);
 	}
 
@@ -703,8 +711,8 @@ static int vhost_blk_setup_vqs(struct vhost_blk *blk)
 		if (!vhost_vq_is_setup(vq))
 			continue;
 
-		blk->vqs[i].req = kvmalloc_array(vq->num, sizeof(struct vhost_blk_req),
-						 GFP_KERNEL);
+		blk->vqs[i].req = kvcalloc(vq->num, sizeof(struct vhost_blk_req),
+					   GFP_KERNEL);
 		if (!blk->vqs[i].req)
 			return -ENOMEM;
 
-- 
2.53.0



More information about the Devel mailing list