The previous cq.head validation treats head past cached_cq_tail as an empty ring. When head is rewound so the unsigned distance exceeds cq_entries, we still used min() and reported a full ring. Posting then fails into overflow without advancing cq.tail, and io_cqring_wait() keeps retrying on the overflow bit. A valid distance is only [0, cq_entries]; reject anything outside that range the same way as head-past-tail. Fixes: f44d38a31f18 ("io_uring: validate user-controlled cq.head in io_cqe_cache_refill()") Assisted-by: Cursor:Composer Signed-off-by: Yang Xiuwei --- io_uring/io_uring.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index 1ea2fca34a36..da9f5971e0c9 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -688,16 +688,17 @@ static struct io_overflow_cqe *io_alloc_ocqe(struct io_ring_ctx *ctx, } /* - * Compute queued CQEs for free-space calculation, clamped to cq_entries. + * cq.head is controlled by userspace. Only a distance of [0, cq_entries] is + * valid; anything outside that range is a bogus head, treat as empty. */ static unsigned int io_cqring_queued(struct io_ring_ctx *ctx) { struct io_rings *rings = io_get_rings(ctx); - int diff; + unsigned int head = READ_ONCE(rings->cq.head); + unsigned int diff = ctx->cached_cq_tail - head; - diff = (int)(ctx->cached_cq_tail - READ_ONCE(rings->cq.head)); - if (diff >= 0) - return min((unsigned int)diff, ctx->cq_entries); + if (diff <= ctx->cq_entries) + return diff; return 0; } -- 2.25.1