[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