Linux io-uring development
 help / color / mirror / Atom feed
* [BUG] io_uring: 13 remaining unprotected ctx->rings accesses after 61a11cf481272
@ 2026-04-09  9:14 asaf meizner
  2026-04-09 11:39 ` Jens Axboe
  0 siblings, 1 reply; 2+ messages in thread
From: asaf meizner @ 2026-04-09  9:14 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, linux-kernel

Hi Jens,

Commit 61a11cf481272 ("io_uring: protect remaining lockless ctx->rings
accesses with RCU") introduced RCU protection for ctx->rings during
ring resize, but at least 13 dereferences were not converted. The
most concerning is fdinfo.c:63 which reads ctx->rings with no lock
and no RCU protection at all.

Unprotected accesses found:

  io_uring/fdinfo.c:63
    struct io_rings *r = ctx->rings;
    (no lock, no RCU — TOCTOU with concurrent resize)

  io_uring/tw.c:41, 253, 291, 326
    atomic_andnot/atomic_or on ctx->rings->sq_flags
    (lines 249-253 have a comment justifying no RCU for
    !DEFER_TASKRUN, but lines 41 and 291 have no such comment
    and appear to be in contexts where resize could race)

  io_uring/sqpoll.c:380, 407, 421
    atomic_or/atomic_andnot on ctx->rings->sq_flags
    (under sqd->lock, but resize takes uring_lock — different locks)

  io_uring/io_uring.c:574, 647, 690, 1985, 1986
    CQ overflow flags and sq_dropped counter

The fdinfo case is the clearest bug: a read of
/proc/<pid>/fdinfo/<fd> concurrent with
IORING_REGISTER_RESIZE_RINGS can dereference a stale ctx->rings
pointer after the old rings are freed via RCU. This is a UAF read
that could leak kernel heap data.

The sqpoll case is also concerning because sqd->lock and uring_lock
are different locks, so the SQPOLL thread can see a stale pointer
during resize.

Minimal fix for fdinfo:

  void io_uring_show_fdinfo(struct io_ring_ctx *ctx)
  {
  -    struct io_rings *r = ctx->rings;
  +    struct io_rings *r;
  +    rcu_read_lock();
  +    r = rcu_dereference(ctx->rings);
       /* ... use r ... */
  +    rcu_read_unlock();
  }

I haven't written a full patch for all 13 sites because the right
fix depends on whether io_get_rings() or raw rcu_read_lock() is
preferred for each site, and some of the tw.c accesses may be
intentionally unprotected for !DEFER_TASKRUN. Happy to write the
full patch if you can clarify which sites actually need fixing.

Reproducer:
  Thread A: cat /proc/$(pidof target)/fdinfo/$(target_uring_fd)
  Thread B: io_uring_register(fd, IORING_REGISTER_RESIZE_RINGS, ...)

Tested against: current HEAD (7.0-rc series)

Thanks,
Asaf Meizner

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [BUG] io_uring: 13 remaining unprotected ctx->rings accesses after 61a11cf481272
  2026-04-09  9:14 [BUG] io_uring: 13 remaining unprotected ctx->rings accesses after 61a11cf481272 asaf meizner
@ 2026-04-09 11:39 ` Jens Axboe
  0 siblings, 0 replies; 2+ messages in thread
From: Jens Axboe @ 2026-04-09 11:39 UTC (permalink / raw)
  To: asaf meizner; +Cc: io-uring, linux-kernel

On 4/9/26 3:14 AM, asaf meizner wrote:
> Hi Jens,
> 
> Commit 61a11cf481272 ("io_uring: protect remaining lockless ctx->rings
> accesses with RCU") introduced RCU protection for ctx->rings during
> ring resize, but at least 13 dereferences were not converted. The
> most concerning is fdinfo.c:63 which reads ctx->rings with no lock
> and no RCU protection at all.
> 
> Unprotected accesses found:
> 
>   io_uring/fdinfo.c:63
>     struct io_rings *r = ctx->rings;
>     (no lock, no RCU ? TOCTOU with concurrent resize)
> 
>   io_uring/tw.c:41, 253, 291, 326
>     atomic_andnot/atomic_or on ctx->rings->sq_flags
>     (lines 249-253 have a comment justifying no RCU for
>     !DEFER_TASKRUN, but lines 41 and 291 have no such comment
>     and appear to be in contexts where resize could race)
> 
>   io_uring/sqpoll.c:380, 407, 421
>     atomic_or/atomic_andnot on ctx->rings->sq_flags
>     (under sqd->lock, but resize takes uring_lock ? different locks)
> 
>   io_uring/io_uring.c:574, 647, 690, 1985, 1986
>     CQ overflow flags and sq_dropped counter
> 
> The fdinfo case is the clearest bug: a read of
> /proc/<pid>/fdinfo/<fd> concurrent with
> IORING_REGISTER_RESIZE_RINGS can dereference a stale ctx->rings
> pointer after the old rings are freed via RCU. This is a UAF read
> that could leak kernel heap data.

The "clearest bug" isn't a bug at all. What you are seemingly missing
here is that rings can't go away if inside ->uring_lock OR
->completion_lock, which is actually documented in io_get_rings().

> The sqpoll case is also concerning because sqd->lock and uring_lock
> are different locks, so the SQPOLL thread can see a stale pointer
> during resize.

And you are also missing that ring resizing isn't supported for SQPOLL,
it's a DEFER_TASKRUN only feature.

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-04-09 11:39 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-09  9:14 [BUG] io_uring: 13 remaining unprotected ctx->rings accesses after 61a11cf481272 asaf meizner
2026-04-09 11:39 ` Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox