[PATCH 0/2] vringh: fix infinite loop on cyclic top-level indirect descriptor
From: Fang Xieyan
Date: Tue Sep 22 2026 - 08:39:43 EST
__vringh_iov()'s F_INDIRECT branch does `continue` before the descriptor
accounting block, so a top-level indirect descriptor is never charged to
`count`. When such a descriptor also carries NEXT pointing to itself,
returning from the indirect table resumes at the same uncharged descriptor;
`count` stays flat and `indirect_count` is reset to 0 on every return, so
neither bound in the loop check can ever trip. A guest can keep the host
vringh worker spinning inside __vringh_iov(), causing a host DoS.
Patch 1/2 moves the accounting block above the INDIRECT switch so each
top-level descriptor, including INDIRECT ones, is charged one traversal step
before the walk descends. Legitimate chains and indirect descriptors stay
within vring.num; a cyclic indirect descriptor is now rejected with -ELOOP.
Patch 1 carries the Fixes tag and is Cc'd to stable.
Patch 2/2 appends a regression test to tools/virtio/vringh_test.c. It builds
the offending ring: top-level desc[1].flags = VRING_DESC_F_INDIRECT |
VRING_DESC_F_NEXT and desc[1].next = 1, with a single-entry indirect table,
and asserts that vringh_getdesc_user() returns -ELOOP.
Verified against v7.3-rc3: both patches pass git apply --check. With the fix,
vringh_test --indirect observes -ELOOP and exits 0. With the fix reverted, the
walk re-enters the same descriptor without making forward progress and never
returns -ELOOP, so the assertion does not hold and the regression is caught
either way.
Fang Xieyan (2):
vringh: bound top-level re-entry into indirect tables
vringh: add regression test for cyclic indirect descriptor
drivers/vhost/vringh.c | 22 ++++++++++----------
tools/virtio/vringh_test.c | 41 ++++++++++++++++++++++++++++++++++++++
2 files changed, 52 insertions(+), 11 deletions(-)
--
2.50.1