diff options
| author | Fang Xieyan <fangxy@xiaopeng.com> | 2026-09-22 20:29:54 +0800 |
|---|---|---|
| committer | Michael S. Tsirkin <mst@redhat.com> | 2026-11-02 09:07:01 -0500 |
| commit | f898439ace7f89922e853b43bcbfcd26ea2e0a98 (patch) | |
| tree | 533f844c59198e12f04190bfa474c255257bb372 | |
| parent | cf0a5805d43236e308f14188f9737ddcf83fb53a (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.c | 22 |
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 { |
