mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
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: dbd29e0752 ("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>
This commit is contained in:
parent
cf0a5805d4
commit
f898439ace
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user