From: Anvik Loitongbam <permissiontogallop@gmail.com>
To: Jens Axboe <axboe@kernel.dk>
Cc: Pavel Begunkov <asml.silence@gmail.com>,
Olivier Langlois <olivier@trillion01.com>,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
io-uring@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-rt-devel@lists.linux.dev, stable@vger.kernel.org,
Anvik Loitongbam <permissiontogallop@gmail.com>
Subject: [PATCH] io_uring/napi: fix list use-after-free on PREEMPT_RT
Date: Thu, 29 Oct 2026 15:52:44 +0530 [thread overview]
Message-ID: <20261029102244.141621-1-permissiontogallop@gmail.com> (raw)
Commit 45b3941d09d1 ("io_uring/napi: fix io_napi_entry RCU accesses")
converted the NAPI list teardown to list_for_each_entry() and
kfree_rcu(), with a comment claiming that list_for_each_entry_safe()
is not necessary because kfree_rcu() defers the free to the next
quiescent state.
This assumption only holds while the surrounding spinlock section is
non-preemptible. On PREEMPT_RT, spinlock_t is an rtmutex and the task
can be preempted while holding ctx->napi_lock. The raw lock inside
kfree_rcu() only defers the preemption until it is released, and the
release still happens before the iterator advances. Once the task is
switched out, the context switch is an RCU quiescent state, if the
preemption lasts long enough for the batch to be flushed and a grace
period to complete, the callback frees the entry, and the iterator
then reads e->list.next from freed memory. The same pattern exists
in io_napi_free(). I did try to produce a uaf on an rt kernel
build, but it did not work.
All list mutators are serialized by ctx->napi_lock, so the entry after
the current one cannot be freed before its own iteration. Caching it
first with list_for_each_entry_safe() in both loops might be a more
safer and correct approach.
Fixes: 45b3941d09d1 ("io_uring/napi: fix io_napi_entry RCU accesses")
Cc: stable@vger.kernel.org
Signed-off-by: Anvik Loitongbam <permissiontogallop@gmail.com>
---
io_uring/napi.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/io_uring/napi.c b/io_uring/napi.c
index 7e698720cd51..d299c89cfc3d 100644
--- a/io_uring/napi.c
+++ b/io_uring/napi.c
@@ -110,16 +110,10 @@ static int __io_napi_del_id(struct io_ring_ctx *ctx, unsigned int napi_id)
static void __io_napi_remove_stale(struct io_ring_ctx *ctx)
{
- struct io_napi_entry *e;
+ struct io_napi_entry *e, *next;
guard(spinlock)(&ctx->napi_lock);
- /*
- * list_for_each_entry_safe() is not required as long as:
- * 1. list_del_rcu() does not reset the deleted node next pointer
- * 2. kfree_rcu() delays the memory freeing until the next quiescent
- * state
- */
- list_for_each_entry(e, &ctx->napi_list, list) {
+ list_for_each_entry_safe(e, next, &ctx->napi_list, list) {
if (time_after(jiffies, READ_ONCE(e->timeout))) {
list_del_rcu(&e->list);
hash_del_rcu(&e->node);
@@ -264,10 +258,10 @@ void io_napi_init(struct io_ring_ctx *ctx)
*/
void io_napi_free(struct io_ring_ctx *ctx)
{
- struct io_napi_entry *e;
+ struct io_napi_entry *e, *next;
guard(spinlock)(&ctx->napi_lock);
- list_for_each_entry(e, &ctx->napi_list, list) {
+ list_for_each_entry_safe(e, next, &ctx->napi_list, list) {
hash_del_rcu(&e->node);
kfree_rcu(e, rcu);
}
--
2.56.0
next reply other threads:[~2026-10-29 10:31 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-29 10:22 Anvik Loitongbam [this message]
2026-10-29 13:35 ` Steven Rostedt
2026-10-29 13:42 ` Jens Axboe
2026-10-29 13:48 ` Steven Rostedt
2026-10-29 14:28 ` Jens Axboe
2026-10-29 14:31 ` Steven Rostedt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261029102244.141621-1-permissiontogallop@gmail.com \
--to=permissiontogallop@gmail.com \
--cc=asml.silence@gmail.com \
--cc=axboe@kernel.dk \
--cc=bigeasy@linutronix.de \
--cc=io-uring@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rt-devel@lists.linux.dev \
--cc=olivier@trillion01.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®