summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFang Xieyan <fangxy@xiaopeng.com>2026-09-22 20:29:54 +0800
committerMichael S. Tsirkin <mst@redhat.com>2026-11-02 09:07:01 -0500
commitf898439ace7f89922e853b43bcbfcd26ea2e0a98 (patch)
tree533f844c59198e12f04190bfa474c255257bb372
parentcf0a5805d43236e308f14188f9737ddcf83fb53a (diff)
vringh: bound top-level re-entry into indirect tables
In __vringh_iov(), the F_INDIRECT branch descends into the indirect table and continues before the descriptor accounting runs. A top-level indirect descriptor is therefore never charged to count. If such a descriptor sets NEXT to point back at itself, returning from the indirect table resumes at the same top-level descriptor, which is again not counted, so the walk never makes forward progress. Because count stays flat and indirect_count is reset to 0 on every return to the top-level table, neither bound in the loop check trips. A guest can spin the vringh worker at 100% CPU inside __vringh_iov(), an uninterruptible host DoS. Move the descriptor accounting above the indirect switch so that a top-level indirect descriptor is charged one top-level traversal step before the walk descends into its table, bringing this re-entry under the existing vrh->vring.num bound. Each top-level descriptor is still charged at most one step and indirect_count still bounds a single table, so legitimate chains (including the multiple-indirect case in tools/virtio/vringh_test.c) stay within vring.num, while a cyclic indirect descriptor is now rejected with -ELOOP. Fixes: dbd29e075228 ("vringh: Fix loop descriptors check in the indirect cases") Cc: Xie Yongji <xieyongji@bytedance.com> Cc: stable@vger.kernel.org Assisted-by: Hawkeye:GLM-5.3-flash Assisted-by: Qoder:Qwen3.8-Max Signed-off-by: Fang Xieyan <fangxy@xiaopeng.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <20260922122955.69433-2-fangxy@xiaopeng.com>
-rw-r--r--drivers/vhost/vringh.c22
1 files changed, 11 insertions, 11 deletions
diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c
index 51edd54f7107..e242ae0c1e16 100644
--- a/drivers/vhost/vringh.c
+++ b/drivers/vhost/vringh.c
@@ -333,6 +333,17 @@ __vringh_iov(struct vringh *vrh, u16 i,
if (unlikely(err))
goto fail;
+ if (up_next == -1)
+ count++;
+ else
+ indirect_count++;
+
+ if (count > vrh->vring.num || indirect_count > desc_max) {
+ vringh_bad("Descriptor loop in %p", descs);
+ err = -ELOOP;
+ goto fail;
+ }
+
if (unlikely(desc.flags &
cpu_to_vringh16(vrh, VRING_DESC_F_INDIRECT))) {
u64 a = vringh64_to_cpu(vrh, desc.addr);
@@ -358,17 +369,6 @@ __vringh_iov(struct vringh *vrh, u16 i,
continue;
}
- if (up_next == -1)
- count++;
- else
- indirect_count++;
-
- if (count > vrh->vring.num || indirect_count > desc_max) {
- vringh_bad("Descriptor loop in %p", descs);
- err = -ELOOP;
- goto fail;
- }
-
if (desc.flags & cpu_to_vringh16(vrh, VRING_DESC_F_WRITE))
iov = wiov;
else {