From 60a792b97933a686316737838cd007d27963011e Mon Sep 17 00:00:00 2001 From: Fang Xieyan Date: Sun, 27 Sep 2026 00:07:55 +0800 Subject: [PATCH] vringh: reject empty / undersized indirect descriptor tables move_to_indirect() validates an indirect descriptor table only with "len % sizeof(struct vring_desc)". A descriptor flagged VRING_DESC_F_INDIRECT with len == 0 passes that test, so *desc_max is set to 0 while *descs points at the empty table. __vringh_iov() then copies one struct vring_desc from descs[0] -- 16 bytes past the end of the table -- before the "indirect_count > desc_max" loop detection aborts the walk. The over-read value is discarded when the walk aborts and is never used to map anything, but the access itself is out of bounds. Reject any len smaller than one descriptor, alongside the existing stride check, so an empty table is refused with -EINVAL and no descriptor is ever fetched from it. Fixes: f87d0fbb5798 ("vringh: host-side implementation of virtio rings.") Cc: stable@vger.kernel.org Assisted-by: Hawkeye:GLM-5.3-flash Assisted-by: Qoder:Qwen3.8-Max Signed-off-by: Fang Xieyan Message-ID: <20260926160755.21485-1-fangxy@xiaopeng.com> Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vringh.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index e242ae0c1e16..5094715dd8bc 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -197,8 +197,9 @@ static int move_to_indirect(const struct vringh *vrh, } len = vringh32_to_cpu(vrh, desc->len); - if (unlikely(len % sizeof(struct vring_desc))) { - vringh_bad("Strange indirect len %u", desc->len); + if (unlikely(len < sizeof(struct vring_desc) || + len % sizeof(struct vring_desc))) { + vringh_bad("Invalid indirect len %u", desc->len); return -EINVAL; }