[Devel] [PATCH RHEL10 COMMIT] vhost-blk: fix out-of-bounds req[] access on vhost_get_vq_desc() error

Konstantin Khorenko khorenko at virtuozzo.com
Fri Jun 19 21:33:02 MSK 2026


The commit is pushed to "branch-rh10-6.12.0-211.16.1.12.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-211.16.1.12.4.vz10
------>
commit adbeece02a09abd566e075b420161f6d7952c718
Author: Konstantin Khorenko <khorenko at virtuozzo.com>
Date:   Fri Jun 5 19:49:07 2026 +0200

    vhost-blk: fix out-of-bounds req[] access on vhost_get_vq_desc() error
    
    vhost_blk_handle_guest_kick() declares the descriptor head as
    
            u16 head;
    
    and then does
    
            head = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
                                     &out, &in, NULL, NULL);
            if (unlikely(head < 0))
                    break;
            if (unlikely(head == vq->num)) {
                    ...
    
    vhost_get_vq_desc() returns an int with three distinct outcomes:
    
      - a negative errno (-EFAULT / -EINVAL) when the avail ring or a
        descriptor is malformed,
      - vq->num when there is nothing available right now,
      - the descriptor head index (0 .. vq->num - 1) on success.
    
    Storing that int into a u16 breaks the error case in two ways:
    
      1. The negative errno is truncated to a large positive 16-bit value
         (e.g. -EINVAL (-22) becomes 0xffea == 65514).
      2. "head < 0" is therefore a comparison of an unsigned value against
         zero, which is always false (the compiler folds it away under
         -Wtype-limits).  The error branch is dead code.
    
    So on a vhost_get_vq_desc() failure we neither break nor hit the
    "head == vq->num" branch (65514 does not equal the ring size).  Control
    falls through and the bogus value is used as an array index in
    vhost_blk_req_handle():
    
            req = &blk_vq->req[head];       /* blk_vq->req has vq->num entries */
    
    blk_vq->req is allocated with vq->num elements, so indexing it with
    ~65514 is a wild out-of-bounds access tens of megabytes past the
    allocation; the subsequent stores to req->blk_vq, req->head, etc.
    corrupt unrelated kernel memory.
    
    The bug is only reachable when vhost_get_vq_desc() actually returns an
    error, i.e. when the guest presents a corrupted avail ring or descriptor
    chain.  Normal operation is unaffected because a valid head (0 ..
    vq->num - 1) fits in a u16 and the "head == vq->num" empty-ring sentinel
    also fits, which is why this has gone unnoticed.
    
    Declare head as int.  Then the "head < 0" error check works, the
    "head == vq->num" comparison is unchanged (head is non-negative there),
    and assigning it to req->head (u16) stays safe because a valid head is
    always < vq->num <= 0xffff.
    
    Fixes: 40a5928ec730 ("drivers/vhost: vhost-blk accelerator for virtio-blk guests")
    
    Feature: vhost-blk: in-kernel accelerator for virtio-blk guests
    Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
    Reviewed-by: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
---
 drivers/vhost/blk.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/vhost/blk.c b/drivers/vhost/blk.c
index 8bb83ae39f5c8..16a0a93678def 100644
--- a/drivers/vhost/blk.c
+++ b/drivers/vhost/blk.c
@@ -515,7 +515,7 @@ static void vhost_blk_handle_guest_kick(struct vhost_work *work)
 	struct iov_iter iter;
 	int in, out, ret;
 	struct file *f;
-	u16 head;
+	int head;
 
 	vq = container_of(work, struct vhost_virtqueue, poll.work);
 	blk = container_of(vq->dev, struct vhost_blk, dev);


More information about the Devel mailing list