* [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown [not found] ` <2026051703-equinox-multitude-91e2@gregkh> @ 2026-05-17 12:59 ` Berkant Koc 2026-05-17 12:59 ` [PATCH 1/2] fuse: io-uring: clear ent->fuse_req in commit_fetch error path Berkant Koc ` (2 more replies) 0 siblings, 3 replies; 20+ messages in thread From: Berkant Koc @ 2026-05-17 12:59 UTC (permalink / raw) To: Greg KH, Miklos Szeredi, Bernd Schubert Cc: security, Joanne Koong, linux-fuse, linux-kernel Applied on top of 6916d5703ddf. Thanks Greg for asking to take this on-list; the original off-list report to security@kernel.org included a defensive third patch that added cancel_delayed_work_sync() in fuse_conn_put(), but it triggered a WARN_ON in queue_work() because the work item is not always initialized at that point. That patch is dropped from this series. Patch 1/2 is the static-analysis fix: fuse_uring_commit_fetch() leaks a dangling ent->fuse_req on the set_commit error branch. The patch routes that branch through the existing fuse_uring_req_end() helper so ent->fuse_req is cleared under queue->lock. Patch 2/2 is the KASAN-reproducible fix: fuse_dev_release() on the last fuse_dev drops the connection ref before the io-uring async_teardown_work has stopped, so delayed_release() can kfree() ring entries the work is still walking. Adding fuse_wait_aborted() between fuse_abort_conn() and fuse_conn_put() drains queue_refs first. KASAN-tested at HEAD 6916d5703ddf + this series, 50 iterations x 16 worker threads against an io-uring fuse daemon: 0 KASAN trips, 0 warnings. KASAN log on request. Joanne Koong's [PATCH v2 0/3] (Message-ID <20260516021138.2759874-1-joannelkoong@gmail.com>) is in flight on a separate fuse-next base; this series targets mainline 6916d5703ddf and does not overlap with hers in code or fix scope. CCing linux-fuse and linux-kernel now per the on-list workflow. Berkant Koc (2): fuse: io-uring: clear ent->fuse_req in commit_fetch error path fuse: wait for aborted connection before releasing last fuse_dev fs/fuse/dev.c | 1 + fs/fuse/dev_uring.c | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) -- 2.47.3 ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/2] fuse: io-uring: clear ent->fuse_req in commit_fetch error path 2026-05-17 12:59 ` [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown Berkant Koc @ 2026-05-17 12:59 ` Berkant Koc 2026-05-17 14:11 ` Bernd Schubert 2026-05-17 12:59 ` [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev Berkant Koc 2026-05-17 13:14 ` [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown Berkant Koc 2 siblings, 1 reply; 20+ messages in thread From: Berkant Koc @ 2026-05-17 12:59 UTC (permalink / raw) To: Greg KH, Miklos Szeredi, Bernd Schubert Cc: security, Joanne Koong, linux-fuse, linux-kernel From: Berkant Koc <me@berkoc.com> fuse_uring_commit_fetch() locates a request, removes it from the processing queue, clears req->ring_entry, then calls fuse_ring_ent_set_commit() under queue->lock. On the error branch (set_commit returning non-zero because the entry is not in FRRS_USERSPACE) the function unlocks the queue and ends the request directly with fuse_request_end(), but it never clears ent->fuse_req. ent->fuse_req then keeps pointing at the freed fuse_req while the entry remains on a queue list. Subsequent teardown via fuse_uring_entry_teardown() reads ent->fuse_req under queue->lock and hands the dangling pointer to fuse_uring_stop_fuse_req_end(), which dereferences it and calls fuse_request_end() a second time on freed memory. Route the error branch through fuse_uring_req_end() instead. That helper acquires queue->lock, clears ent->fuse_req under the lock, removes the request from any list it is still on, drops the lock, sets req->out.h.error, clears FR_SENT and ends the request. The ent->fuse_req = NULL store under the lock is what closes the window for the later teardown reader. Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") Cc: stable@vger.kernel.org # 6.14+ Signed-off-by: Berkant Koc <me@berkoc.com> --- fs/fuse/dev_uring.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c index 7b9822e8837b..7523569ffdce 100644 --- a/fs/fuse/dev_uring.c +++ b/fs/fuse/dev_uring.c @@ -924,9 +924,7 @@ static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags, pr_info_ratelimited("qid=%d commit_id %llu state %d", queue->qid, commit_id, ent->state); spin_unlock(&queue->lock); - req->out.h.error = err; - clear_bit(FR_SENT, &req->flags); - fuse_request_end(req); + fuse_uring_req_end(ent, req, err); return err; } -- 2.47.3 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] fuse: io-uring: clear ent->fuse_req in commit_fetch error path 2026-05-17 12:59 ` [PATCH 1/2] fuse: io-uring: clear ent->fuse_req in commit_fetch error path Berkant Koc @ 2026-05-17 14:11 ` Bernd Schubert 2026-05-17 14:24 ` Berkant Koc 0 siblings, 1 reply; 20+ messages in thread From: Bernd Schubert @ 2026-05-17 14:11 UTC (permalink / raw) To: Berkant Koc, Greg KH, Miklos Szeredi Cc: security, Joanne Koong, linux-fuse, linux-kernel, Zhenghang Xiao On 5/17/26 14:59, Berkant Koc wrote: > [You don't often get email from me@berkoc.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ] > > From: Berkant Koc <me@berkoc.com> > > fuse_uring_commit_fetch() locates a request, removes it from the > processing queue, clears req->ring_entry, then calls > fuse_ring_ent_set_commit() under queue->lock. On the error branch > (set_commit returning non-zero because the entry is not in > FRRS_USERSPACE) the function unlocks the queue and ends the request > directly with fuse_request_end(), but it never clears ent->fuse_req. > > ent->fuse_req then keeps pointing at the freed fuse_req while the entry > remains on a queue list. Subsequent teardown via > fuse_uring_entry_teardown() reads ent->fuse_req under queue->lock and > hands the dangling pointer to fuse_uring_stop_fuse_req_end(), which > dereferences it and calls fuse_request_end() a second time on freed > memory. > > Route the error branch through fuse_uring_req_end() instead. That > helper acquires queue->lock, clears ent->fuse_req under the lock, > removes the request from any list it is still on, drops the lock, sets > req->out.h.error, clears FR_SENT and ends the request. The > ent->fuse_req = NULL store under the lock is what closes the window > for the later teardown reader. > > Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") > Cc: stable@vger.kernel.org # 6.14+ > Signed-off-by: Berkant Koc <me@berkoc.com> > --- > fs/fuse/dev_uring.c | 4 +--- > 1 file changed, 1 insertion(+), 3 deletions(-) > > diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c > index 7b9822e8837b..7523569ffdce 100644 > --- a/fs/fuse/dev_uring.c > +++ b/fs/fuse/dev_uring.c > @@ -924,9 +924,7 @@ static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags, > pr_info_ratelimited("qid=%d commit_id %llu state %d", > queue->qid, commit_id, ent->state); > spin_unlock(&queue->lock); > - req->out.h.error = err; > - clear_bit(FR_SENT, &req->flags); > - fuse_request_end(req); > + fuse_uring_req_end(ent, req, err); > return err; > } > > -- > 2.47.3 We already had a security report for that on Friday > > [You don't often get email from kipreyyy@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ] > > fuse_uring_commit_fetch() error path calls fuse_request_end(req) without > clearing ent->fuse_req when fuse_ring_ent_set_commit() fails. The > still-pending fuse_uring_send_in_task() task-work later dereferences the > dangling pointer through fuse_uring_prepare_send(), causing a > use-after-free. > > Clear ent->fuse_req under queue->lock in the error path, matching the > pattern in fuse_uring_req_end(). Add a NULL check in > fuse_uring_send_in_task() so the entry is gracefully recycled if the > request was detached. > > Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") > Signed-off-by: Zhenghang Xiao > --- > fs/fuse/dev_uring.c | 16 ++++++++++++++++ > 1 file changed, 16 insertions(+) > > diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c > index 7b9822e8837b..5e51c36ae2a0 100644 > --- a/fs/fuse/dev_uring.c > +++ b/fs/fuse/dev_uring.c > @@ -921,6 +921,13 @@ static int fuse_uring_commit_fetch(struct io_uring_cmd *cmd, int issue_flags, > > err = fuse_ring_ent_set_commit(ent); > if (err != 0) { > + /* > + * Entry is not in FRRS_USERSPACE state. Clear the > + * back-pointer to prevent the still-pending > + * fuse_uring_send_in_task() from dereferencing a request > + * that is about to be freed. > + */ > + ent->fuse_req = NULL; > pr_info_ratelimited("qid=%d commit_id %llu state %d", > queue->qid, commit_id, ent->state); > spin_unlock(&queue->lock); > @@ -1220,6 +1227,15 @@ static void fuse_uring_send_in_task(struct io_tw_req tw_req, io_tw_token_t tw) > int err; > > if (!tw.cancel) { > + /* > + * If the request was detached (e.g. by fuse_uring_commit_fetch > + * error path), fuse_req will be NULL. Bail out and recycle the > + * entry for the next request. > + */ > + if (!ent->fuse_req) { > + fuse_uring_next_fuse_req(ent, queue, issue_flags); > + return; > + } > err = fuse_uring_prepare_send(ent, ent->fuse_req); > if (err) { > fuse_uring_next_fuse_req(ent, queue, issue_flags); > -- I had already replied to Zhenghang on Friday, I don't think it is enough. This condition > err = fuse_ring_ent_set_commit(ent); > if (err != 0) { can also be triggered by a bad fuse-server / user-space and a teardown race. The tear down race is easy, I think. Fuse-server that wants to trick us is harder, as checking for ent->fuse_req == NULL in fuse_uring_send_in_task() is not enough, the race is valid all over the copy operation (fuse_uring_prepare_send()). I didn't come to it yesterday (was working for main work), going to look into it a bit later today. Thanks, Bernd ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] fuse: io-uring: clear ent->fuse_req in commit_fetch error path 2026-05-17 14:11 ` Bernd Schubert @ 2026-05-17 14:24 ` Berkant Koc 0 siblings, 0 replies; 20+ messages in thread From: Berkant Koc @ 2026-05-17 14:24 UTC (permalink / raw) To: Bernd Schubert Cc: Miklos Szeredi, Greg KH, security, Joanne Koong, fuse-devel, linux-fsdevel, linux-kernel On 2026-05-17 16:11, Bernd Schubert wrote: > We already had a security report for that on Friday [...] I had > already replied to Zhenghang on Friday, I don't think it is enough. > [...] valid all over the copy operation (fuse_uring_prepare_send()) Thanks for the context. P1 is a duplicate of Zhenghang's Friday report, please consider it withdrawn. You are right that clearing ent->fuse_req only in the commit_fetch error path is not sufficient. The same window is reachable across the whole copy path in fuse_uring_prepare_send(), so a single-point clear leaves the race open on the other exits. I will not push a v2 for this one and leave the scope call to you. P2 ([PATCH 2/2] serialize ring teardown and per-ent setup against ent->state writers) is a separate path: ent->state being written without the queue lock while teardown frees the ring. If that overlaps with what you are looking at today, I will hold off on P2 as well. If it is out of scope for your work, a short note is enough and I will keep tracking it independently. KASAN config and the repro harness (qemu + libfuse uring example with abort-on-mount) are set up here, happy to test your fix once it is on the list. Thanks, Berkant ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-17 12:59 ` [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown Berkant Koc 2026-05-17 12:59 ` [PATCH 1/2] fuse: io-uring: clear ent->fuse_req in commit_fetch error path Berkant Koc @ 2026-05-17 12:59 ` Berkant Koc 2026-05-17 15:00 ` Bernd Schubert 2026-05-17 13:14 ` [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown Berkant Koc 2 siblings, 1 reply; 20+ messages in thread From: Berkant Koc @ 2026-05-17 12:59 UTC (permalink / raw) To: Greg KH, Miklos Szeredi, Bernd Schubert Cc: security, Joanne Koong, linux-fuse, linux-kernel From: Berkant Koc <me@berkoc.com> fuse_dev_release() on the last fuse_dev of a connection calls fuse_abort_conn(fc) and then immediately fuse_conn_put(fc). For io-uring backed connections fuse_abort_conn() reaches fuse_uring_abort(), which runs fuse_uring_teardown_all_queues() synchronously once and then schedules ring->async_teardown_work to run after FUSE_URING_TEARDOWN_INTERVAL (HZ/20). If the synchronous pass left queue_refs > 0 the work owns further accesses to ring->queues[*]-> ent_avail_queue and ent_in_userspace entries. Meanwhile fuse_conn_put() can drop the last reference and arm delayed_release() via call_rcu(). After the RCU grace period delayed_release() calls fuse_uring_destruct(), which kfree()s the ring entries on each queue->ent_released list. The previously scheduled async_teardown_work then runs and walks per-queue lists that contain freed entries, producing a slab-use-after-free reported by KASAN at fuse_uring_teardown_all_queues+0xee reading ent->list.next from a freed kmalloc-192 region. fuse_wait_aborted() already exists for this purpose: it waits on fc->blocked_waitq for num_waiting to drain and then calls fuse_uring_wait_stopped_queues(), which waits for ring->queue_refs to reach zero. Call it between fuse_abort_conn() and fuse_conn_put() on the last-device path so the io-uring teardown work has fully drained before the connection can be torn down. Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") Cc: stable@vger.kernel.org # 6.14+ Tested-by: Berkant Koc <me@berkoc.com> Signed-off-by: Berkant Koc <me@berkoc.com> --- fs/fuse/dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 5dda7080f4a9..7d9c06654a98 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2566,6 +2566,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) if (last) { WARN_ON(fc->iq.fasync != NULL); fuse_abort_conn(fc); + fuse_wait_aborted(fc); } fuse_conn_put(fc); } -- 2.47.3 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-17 12:59 ` [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev Berkant Koc @ 2026-05-17 15:00 ` Bernd Schubert 2026-05-18 1:13 ` Berkant Koc 2026-05-18 9:06 ` Pavel Begunkov 0 siblings, 2 replies; 20+ messages in thread From: Bernd Schubert @ 2026-05-17 15:00 UTC (permalink / raw) To: Berkant Koc, Greg KH, Miklos Szeredi Cc: security@kernel.org, Joanne Koong, linux-fuse@vger.kernel.org, linux-kernel@vger.kernel.org, io-uring@vger.kernel.org, Jens Axboe, Pavel Begunkov, fuse-devel On 5/17/26 14:59, Berkant Koc wrote: > [You don't often get email from me@berkoc.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ] > > From: Berkant Koc <me@berkoc.com> > > fuse_dev_release() on the last fuse_dev of a connection calls > fuse_abort_conn(fc) and then immediately fuse_conn_put(fc). For io-uring > backed connections fuse_abort_conn() reaches fuse_uring_abort(), which > runs fuse_uring_teardown_all_queues() synchronously once and then > schedules ring->async_teardown_work to run after > FUSE_URING_TEARDOWN_INTERVAL (HZ/20). If the synchronous pass left > queue_refs > 0 the work owns further accesses to ring->queues[*]-> > ent_avail_queue and ent_in_userspace entries. > > Meanwhile fuse_conn_put() can drop the last reference and arm > delayed_release() via call_rcu(). After the RCU grace period > delayed_release() calls fuse_uring_destruct(), which kfree()s the ring > entries on each queue->ent_released list. The previously scheduled > async_teardown_work then runs and walks per-queue lists that contain > freed entries, producing a slab-use-after-free reported by KASAN at > fuse_uring_teardown_all_queues+0xee reading ent->list.next from a > freed kmalloc-192 region. > > fuse_wait_aborted() already exists for this purpose: it waits on > fc->blocked_waitq for num_waiting to drain and then calls > fuse_uring_wait_stopped_queues(), which waits for ring->queue_refs to > reach zero. Call it between fuse_abort_conn() and fuse_conn_put() on > the last-device path so the io-uring teardown work has fully drained > before the connection can be torn down. > > Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") > Cc: stable@vger.kernel.org # 6.14+ > Tested-by: Berkant Koc <me@berkoc.com> > Signed-off-by: Berkant Koc <me@berkoc.com> > --- > fs/fuse/dev.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c > index 5dda7080f4a9..7d9c06654a98 100644 > --- a/fs/fuse/dev.c > +++ b/fs/fuse/dev.c > @@ -2566,6 +2566,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) > if (last) { > WARN_ON(fc->iq.fasync != NULL); > fuse_abort_conn(fc); > + fuse_wait_aborted(fc); > } > fuse_conn_put(fc); > } I might be wrong, but I don't think it is possible, Maybe Pavel or Jens could help (added to CC). Basically as long as fuse_uring_async_stop_queues() runs we do not have completed all io-uring commands via io_uring_cmd_done() and as long as we do not have completed these io-uring commands. References are taken here io_issue_sqe io_assign_file io_file_get_normal fget __io_uring_cmd_done() req->io_task_work.func = io_req_task_complete io_req_task_work_add(req) io_uring/uring_cmd.c:179 io_req_task_complete io_req_complete_defer wq_list_add_tail __io_submit_flush_completions io_free_batch_list io_put_file fput I also look it up for fixed file and for fixed file it needs io_ring_ctx_free(), which is then only one after completing all uring_cmd objects (io_uring_cmd_done). I don't mind adding fuse_wait_aborted() here, but IMHO it is a no-op and no security issue. Thanks Bernd ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-17 15:00 ` Bernd Schubert @ 2026-05-18 1:13 ` Berkant Koc 2026-05-18 9:55 ` Bernd Schubert 2026-05-18 9:06 ` Pavel Begunkov 1 sibling, 1 reply; 20+ messages in thread From: Berkant Koc @ 2026-05-18 1:13 UTC (permalink / raw) To: Bernd Schubert, Greg KH, Miklos Szeredi Cc: security, Joanne Koong, linux-fuse, linux-kernel, io-uring, Jens Axboe, Pavel Begunkov, fuse-devel [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 1867 bytes --] Bernd, thanks for pushing back. Stepping through this against the trace: fuse_conn_destroy() in fs/fuse/inode.c calls fuse_wait_aborted() between fuse_abort_conn() and the eventual fuse_conn_put() (from fuse_sb_destroy). fuse_dev_release() in fs/fuse/dev.c does not wait between its fuse_abort_conn() and fuse_conn_put(). That asymmetry is the race. On topologies where the last fud release IS the last conn ref (no superblock mount, no other fud open — exactly the PoC setup), fuse_conn_put() drops the count to zero, call_rcu schedules delayed_release, and fuse_uring_destruct kfrees ring/queue/ent_released slabs. async_teardown_work, scheduled by fuse_uring_async_stop_queues via the teardown-interval delayed_work, then runs on freed memory. The KASAN trace at top-finding/kasan-trace.txt shows exactly that interleaving: free site: fuse_uring_destruct ← delayed_release ← rcu_core use site: fuse_uring_teardown_all_queues ← async_teardown_work (workqueue), reading ent->list.next from kmalloc-192 freed by destruct Your in-flight cmd ref invariant holds on both fixed and non-fixed paths (non-fixed via per-cmd io_put_file in io_free_batch_list, fixed via the io_uring file table slot pinning struct file → fud → fuse_conn). But neither covers the gap between fuse_abort_conn (which schedules the async work and returns immediately) and the RCU callback. The PoC topology removes every other ref-holder, so that gap becomes the last conn ref. The patch restores symmetry with fuse_conn_destroy by waiting on ring->queue_refs == 0 (via fuse_wait_aborted → fuse_uring_wait_stopped_queues) before the put. That guarantees async_teardown_work has finished before RCU is armed. The race is reproducible with mdelay-widening; without widening I see 0 trips in 50 iter, but the window is in the code paths. Berkant ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-18 1:13 ` Berkant Koc @ 2026-05-18 9:55 ` Bernd Schubert 2026-05-18 11:47 ` Bernd Schubert 0 siblings, 1 reply; 20+ messages in thread From: Bernd Schubert @ 2026-05-18 9:55 UTC (permalink / raw) To: Berkant Koc, Greg KH, Miklos Szeredi Cc: security@kernel.org, Joanne Koong, linux-fuse@vger.kernel.org, linux-kernel@vger.kernel.org, io-uring@vger.kernel.org, Jens Axboe, Pavel Begunkov, fuse-devel On 5/18/26 03:13, Berkant Koc wrote: > [You don't often get email from me@berkoc.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ] > > Bernd, thanks for pushing back. Stepping through this against the trace: > > fuse_conn_destroy() in fs/fuse/inode.c calls fuse_wait_aborted() > between fuse_abort_conn() and the eventual fuse_conn_put() (from > fuse_sb_destroy). fuse_dev_release() in fs/fuse/dev.c does not wait > between its fuse_abort_conn() and fuse_conn_put(). That asymmetry is > the race. > > On topologies where the last fud release IS the last conn ref > (no superblock mount, no other fud open — exactly the PoC setup), > fuse_conn_put() drops the count to zero, call_rcu schedules > delayed_release, and fuse_uring_destruct kfrees ring/queue/ent_released > slabs. async_teardown_work, scheduled by fuse_uring_async_stop_queues > via the teardown-interval delayed_work, then runs on freed memory. > > The KASAN trace at top-finding/kasan-trace.txt shows exactly that > interleaving: > > free site: fuse_uring_destruct ← delayed_release ← rcu_core > use site: fuse_uring_teardown_all_queues ← async_teardown_work > (workqueue), reading ent->list.next from > kmalloc-192 freed by destruct > > Your in-flight cmd ref invariant holds on both fixed and non-fixed > paths (non-fixed via per-cmd io_put_file in io_free_batch_list, fixed > via the io_uring file table slot pinning struct file → fud → fuse_conn). > But neither covers the gap between fuse_abort_conn (which schedules > the async work and returns immediately) and the RCU callback. The > PoC topology removes every other ref-holder, so that gap becomes the > last conn ref. > > The patch restores symmetry with fuse_conn_destroy by waiting on > ring->queue_refs == 0 (via fuse_wait_aborted → fuse_uring_wait_stopped_queues) > before the put. That guarantees async_teardown_work has finished > before RCU is armed. > > The race is reproducible with mdelay-widening; without widening I see > 0 trips in 50 iter, but the window is in the code paths. I think I see what the actual issue is, we need an fc (or in linux-next struct fuse_chan) reference as long as fuse_uring_async_stop_queues() runs. Patch follows. Thanks, Bernd ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-18 9:55 ` Bernd Schubert @ 2026-05-18 11:47 ` Bernd Schubert 2026-05-18 14:32 ` Berkant Koc 0 siblings, 1 reply; 20+ messages in thread From: Bernd Schubert @ 2026-05-18 11:47 UTC (permalink / raw) To: Berkant Koc, Greg KH, Miklos Szeredi Cc: security@kernel.org, Joanne Koong, linux-kernel@vger.kernel.org, io-uring@vger.kernel.org, Jens Axboe, Pavel Begunkov, fuse-devel [-- Attachment #1: Type: text/plain, Size: 2480 bytes --] On 5/18/26 11:55, Bernd Schubert wrote: > On 5/18/26 03:13, Berkant Koc wrote: >> [You don't often get email from me@berkoc.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ] >> >> Bernd, thanks for pushing back. Stepping through this against the trace: >> >> fuse_conn_destroy() in fs/fuse/inode.c calls fuse_wait_aborted() >> between fuse_abort_conn() and the eventual fuse_conn_put() (from >> fuse_sb_destroy). fuse_dev_release() in fs/fuse/dev.c does not wait >> between its fuse_abort_conn() and fuse_conn_put(). That asymmetry is >> the race. >> >> On topologies where the last fud release IS the last conn ref >> (no superblock mount, no other fud open — exactly the PoC setup), >> fuse_conn_put() drops the count to zero, call_rcu schedules >> delayed_release, and fuse_uring_destruct kfrees ring/queue/ent_released >> slabs. async_teardown_work, scheduled by fuse_uring_async_stop_queues >> via the teardown-interval delayed_work, then runs on freed memory. >> >> The KASAN trace at top-finding/kasan-trace.txt shows exactly that >> interleaving: >> >> free site: fuse_uring_destruct ← delayed_release ← rcu_core >> use site: fuse_uring_teardown_all_queues ← async_teardown_work >> (workqueue), reading ent->list.next from >> kmalloc-192 freed by destruct >> >> Your in-flight cmd ref invariant holds on both fixed and non-fixed >> paths (non-fixed via per-cmd io_put_file in io_free_batch_list, fixed >> via the io_uring file table slot pinning struct file → fud → fuse_conn). >> But neither covers the gap between fuse_abort_conn (which schedules >> the async work and returns immediately) and the RCU callback. The >> PoC topology removes every other ref-holder, so that gap becomes the >> last conn ref. >> >> The patch restores symmetry with fuse_conn_destroy by waiting on >> ring->queue_refs == 0 (via fuse_wait_aborted → fuse_uring_wait_stopped_queues) >> before the put. That guarantees async_teardown_work has finished >> before RCU is armed. >> >> The race is reproducible with mdelay-widening; without widening I see >> 0 trips in 50 iter, but the window is in the code paths. > > I think I see what the actual issue is, we need an fc (or in linux-next > struct fuse_chan) reference as long as fuse_uring_async_stop_queues() > runs. Patch follows. > Would it be possible for you to test the attached patch? Thanks, Bernd [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: fuse_uring_async_stop_queues.patch --] [-- Type: text/x-patch; name="fuse_uring_async_stop_queues.patch", Size: 1561 bytes --] commit b6f63cc1d2f7b8d690835c965d600fda47ffd79b Author: Bernd Schubert <bernd@bsbernd.com> Date: Mon May 18 13:30:30 2026 +0200 fuse: Avoid use-after-free in fuse_uring_async_stop_queues fuse_uring_async_stop_queues() might run when the last reference on ring->queue_refs was already dropped. In order to avoid an early destruction a reference on struct fuse_conn is now taken before starting fuse_uring_async_stop_queues() and that reference is only released when that delayed work queue terminates. Fixes: 4a9bfb9b6850 ("fuse: {io-uring} Handle teardown of ring entries") Cc: stable@kernel.org # 6.14 Reported-by: Berkant Koc <me@berkoc.com> Signed-off-by: Bernd Schubert <bernd@bsbernd.com> diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c index e467b23e6895..c96d72250830 100644 --- a/fs/fuse/dev_uring.c +++ b/fs/fuse/dev_uring.c @@ -465,7 +465,10 @@ static void fuse_uring_async_stop_queues(struct work_struct *work) schedule_delayed_work(&ring->async_teardown_work, FUSE_URING_TEARDOWN_INTERVAL); } else { + struct fuse_chan *chan = ring->chan; + wake_up_all(&ring->stop_waitq); + fuse_conn_put(chan->conn); } } @@ -477,6 +480,9 @@ void fuse_uring_stop_queues(struct fuse_ring *ring) fuse_uring_teardown_all_queues(ring); if (atomic_read(&ring->queue_refs) > 0) { + struct fuse_chan *chan = ring->chan; + + fuse_conn_get(chan->conn); ring->teardown_time = jiffies; INIT_DELAYED_WORK(&ring->async_teardown_work, fuse_uring_async_stop_queues); ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-18 11:47 ` Bernd Schubert @ 2026-05-18 14:32 ` Berkant Koc 2026-05-18 14:46 ` Bernd Schubert 0 siblings, 1 reply; 20+ messages in thread From: Berkant Koc @ 2026-05-18 14:32 UTC (permalink / raw) To: Bernd Schubert Cc: Greg KH, Miklos Szeredi, security, Joanne Koong, linux-kernel, io-uring, Jens Axboe, Pavel Begunkov, fuse-devel On Mon, 18 May 2026 11:47:00 +0000, Bernd Schubert <bschubert@ddn.com> wrote: > Would it be possible for you to test the attached patch? Reproducer and KASAN harness from the PATCH 2/2 series are staged. Two-arm plan: revert vs apply, race-widening debug hunk kept in both arms, 2x50 iterations each against torvalds/master tip, KASAN + lockdep + kmemleak enabled. Results back within the day once the base resolves. Blocker before I build. The patch references ring->chan and chan->conn. On mainline fs/fuse/dev_uring_i.h declares struct fuse_ring with struct fuse_conn *fc at line 110, no chan member; grep fuse_chan across fs/fuse/ returns zero hits. As-is the patch fails to compile with "struct fuse_ring has no member named chan". Is this based on a DDN topic branch that introduces a fuse_chan abstraction not yet upstream? If so, point me at the base tree or branch URL and I will rebase the test against that. If the references were meant to be ring->fc and fc against current mainline, confirm and I will adjust before the run. Assisted-by: Claude:claude-opus-4-7 berkoc-pipeline ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-18 14:32 ` Berkant Koc @ 2026-05-18 14:46 ` Bernd Schubert 2026-05-18 15:35 ` Joanne Koong 2026-05-18 15:47 ` Berkant Koc 0 siblings, 2 replies; 20+ messages in thread From: Bernd Schubert @ 2026-05-18 14:46 UTC (permalink / raw) To: Berkant Koc, Bernd Schubert Cc: Greg KH, Miklos Szeredi, security, Joanne Koong, linux-kernel, io-uring, Jens Axboe, Pavel Begunkov, fuse-devel On 5/18/26 16:32, Berkant Koc wrote: > On Mon, 18 May 2026 11:47:00 +0000, Bernd Schubert <bschubert@ddn.com> wrote: >> Would it be possible for you to test the attached patch? > > Reproducer and KASAN harness from the PATCH 2/2 series are staged. > Two-arm plan: revert vs apply, race-widening debug hunk kept in both > arms, 2x50 iterations each against torvalds/master tip, KASAN + lockdep > + kmemleak enabled. Results back within the day once the base resolves. > > Blocker before I build. The patch references ring->chan and chan->conn. > On mainline fs/fuse/dev_uring_i.h declares struct fuse_ring with > struct fuse_conn *fc at line 110, no chan member; grep fuse_chan > across fs/fuse/ returns zero hits. As-is the patch fails to compile > with "struct fuse_ring has no member named chan". > > Is this based on a DDN topic branch that introduces a fuse_chan > abstraction not yet upstream? If so, point me at the base tree or > branch URL and I will rebase the test against that. If the references > were meant to be ring->fc and fc against current mainline, confirm and > I will adjust before the run. > > Assisted-by: Claude:claude-opus-4-7 berkoc-pipeline > Ah, it is based on Miklos' for-next branch, which is also in linux-next (I think). Yeah, we have a bit back port headache here. Thanks, Bernd ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-18 14:46 ` Bernd Schubert @ 2026-05-18 15:35 ` Joanne Koong 2026-05-18 17:49 ` Berkant Koc 2026-05-18 15:47 ` Berkant Koc 1 sibling, 1 reply; 20+ messages in thread From: Joanne Koong @ 2026-05-18 15:35 UTC (permalink / raw) To: Bernd Schubert Cc: Berkant Koc, Bernd Schubert, Greg KH, Miklos Szeredi, security, linux-kernel, io-uring, Jens Axboe, Pavel Begunkov, fuse-devel On Mon, May 18, 2026 at 7:46 AM Bernd Schubert <bernd@bsbernd.com> wrote: > > > > On 5/18/26 16:32, Berkant Koc wrote: > > On Mon, 18 May 2026 11:47:00 +0000, Bernd Schubert <bschubert@ddn.com> wrote: > >> Would it be possible for you to test the attached patch? The fix looks right to me. Reviewed-by: Joanne Koong <joannelkoong@gmail.com> > > > > Reproducer and KASAN harness from the PATCH 2/2 series are staged. > > Two-arm plan: revert vs apply, race-widening debug hunk kept in both > > arms, 2x50 iterations each against torvalds/master tip, KASAN + lockdep > > + kmemleak enabled. Results back within the day once the base resolves. > > > > Blocker before I build. The patch references ring->chan and chan->conn. > > On mainline fs/fuse/dev_uring_i.h declares struct fuse_ring with > > struct fuse_conn *fc at line 110, no chan member; grep fuse_chan > > across fs/fuse/ returns zero hits. As-is the patch fails to compile > > with "struct fuse_ring has no member named chan". > > > > Is this based on a DDN topic branch that introduces a fuse_chan > > abstraction not yet upstream? If so, point me at the base tree or > > branch URL and I will rebase the test against that. If the references > > were meant to be ring->fc and fc against current mainline, confirm and > > I will adjust before the run. Yes, on mainline the references are meant to be ring->fc, eg diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c index 5c00fd047c8b..27c417fd9451 100644 --- a/fs/fuse/dev_uring.c +++ b/fs/fuse/dev_uring.c @@ -570,6 +570,7 @@ static void fuse_uring_async_stop_queues(struct work_struct *work) FUSE_URING_TEARDOWN_INTERVAL); } else { wake_up_all(&ring->stop_waitq); + fuse_conn_put(ring->fc); } } @@ -599,6 +600,7 @@ void fuse_uring_stop_queues(struct fuse_ring *ring) if (atomic_read(&ring->queue_refs) > 0) { ring->teardown_time = jiffies; + fuse_conn_get(ring->fc); INIT_DELAYED_WORK(&ring->async_teardown_work, fuse_uring_async_stop_queues); schedule_delayed_work(&ring->async_teardown_work, Thanks, Joanne > > > > Assisted-by: Claude:claude-opus-4-7 berkoc-pipeline > > > > Ah, it is based on Miklos' for-next branch, which is also in linux-next > (I think). Yeah, we have a bit back port headache here. > > > Thanks, > Bernd ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-18 15:35 ` Joanne Koong @ 2026-05-18 17:49 ` Berkant Koc 0 siblings, 0 replies; 20+ messages in thread From: Berkant Koc @ 2026-05-18 17:49 UTC (permalink / raw) To: Joanne Koong Cc: Bernd Schubert, Bernd Schubert, Greg KH, Miklos Szeredi, security, linux-kernel, io-uring, Jens Axboe, Pavel Begunkov, fuse-devel On Mon, 18 May 2026 08:35:16 -0700, Joanne Koong <joannelkoong@gmail.com> wrote: > Yes, on mainline the references are meant to be ring->fc, eg Confirmed, ring->fc on mainline. Reviewed-by recorded for Bernd's v6.14 backport path. Bernd has since published the full 4-patch series via B4-Relay at 18:37 CEST, rebased onto Miklos' for-next (base-commit 040d71ac6470). On that branch the fuse_chan abstraction is in place, so the teardown path uses ring->chan / chan->conn rather than ring->fc. The series stays as-is for for-next. Your inline diff is the basis for the mainline stable-backport once for-next lands. I will run the two-arm Tested-by against for-next-base 040d71ac6470 (KASAN + lockdep + kmemleak, async-teardown race + baseline) and report numbers on-thread. Assisted-by: Claude:claude-opus-4-7 berkoc-pipeline ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-18 14:46 ` Bernd Schubert 2026-05-18 15:35 ` Joanne Koong @ 2026-05-18 15:47 ` Berkant Koc 1 sibling, 0 replies; 20+ messages in thread From: Berkant Koc @ 2026-05-18 15:47 UTC (permalink / raw) To: Bernd Schubert Cc: Bernd Schubert, Greg KH, Miklos Szeredi, security, Joanne Koong, linux-kernel, io-uring, Jens Axboe, Pavel Begunkov, fuse-devel On Mon, 18 May 2026 16:46:08 +0200, Bernd Schubert <bernd@bsbernd.com> wrote: > Ah, it is based on Miklos' for-next branch, which is also in linux-next > (I think). Yeah, we have a bit back port headache here. Got it, that resolves the field-name confusion on my side. I will rebase the test harness onto Miklos' fuse.git for-next tip (and cross-check against linux-next), then rerun the two-arm comparison against that base: revert vs apply with the abort/release race-widening kept in place, 2x50 iterations each under KASAN + lockdep + kmemleak, with full splats and reproducer attached on report-back. The stable-backport question is parked until the for-next arm lands clean. Once the trace set is in hand I will fold the v6.14 field-name delta into a separate backport note rather than mixing it into the mainline result. Assisted-by: Claude:claude-opus-4-7 berkoc-pipeline ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-17 15:00 ` Bernd Schubert 2026-05-18 1:13 ` Berkant Koc @ 2026-05-18 9:06 ` Pavel Begunkov 2026-05-18 9:50 ` Bernd Schubert 1 sibling, 1 reply; 20+ messages in thread From: Pavel Begunkov @ 2026-05-18 9:06 UTC (permalink / raw) To: Bernd Schubert, Berkant Koc, Greg KH, Miklos Szeredi Cc: security@kernel.org, Joanne Koong, linux-fuse@vger.kernel.org, linux-kernel@vger.kernel.org, io-uring@vger.kernel.org, Jens Axboe, fuse-devel On 5/17/26 16:00, Bernd Schubert wrote: > On 5/17/26 14:59, Berkant Koc wrote: >> [You don't often get email from me@berkoc.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ] >> >> From: Berkant Koc <me@berkoc.com> >> >> fuse_dev_release() on the last fuse_dev of a connection calls >> fuse_abort_conn(fc) and then immediately fuse_conn_put(fc). For io-uring >> backed connections fuse_abort_conn() reaches fuse_uring_abort(), which >> runs fuse_uring_teardown_all_queues() synchronously once and then >> schedules ring->async_teardown_work to run after >> FUSE_URING_TEARDOWN_INTERVAL (HZ/20). If the synchronous pass left >> queue_refs > 0 the work owns further accesses to ring->queues[*]-> >> ent_avail_queue and ent_in_userspace entries. >> >> Meanwhile fuse_conn_put() can drop the last reference and arm >> delayed_release() via call_rcu(). After the RCU grace period >> delayed_release() calls fuse_uring_destruct(), which kfree()s the ring >> entries on each queue->ent_released list. The previously scheduled >> async_teardown_work then runs and walks per-queue lists that contain >> freed entries, producing a slab-use-after-free reported by KASAN at >> fuse_uring_teardown_all_queues+0xee reading ent->list.next from a >> freed kmalloc-192 region. >> >> fuse_wait_aborted() already exists for this purpose: it waits on >> fc->blocked_waitq for num_waiting to drain and then calls >> fuse_uring_wait_stopped_queues(), which waits for ring->queue_refs to >> reach zero. Call it between fuse_abort_conn() and fuse_conn_put() on >> the last-device path so the io-uring teardown work has fully drained >> before the connection can be torn down. >> >> Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") >> Cc: stable@vger.kernel.org # 6.14+ >> Tested-by: Berkant Koc <me@berkoc.com> >> Signed-off-by: Berkant Koc <me@berkoc.com> >> --- >> fs/fuse/dev.c | 1 + >> 1 file changed, 1 insertion(+) >> >> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c >> index 5dda7080f4a9..7d9c06654a98 100644 >> --- a/fs/fuse/dev.c >> +++ b/fs/fuse/dev.c >> @@ -2566,6 +2566,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) >> if (last) { >> WARN_ON(fc->iq.fasync != NULL); >> fuse_abort_conn(fc); >> + fuse_wait_aborted(fc); >> } >> fuse_conn_put(fc); >> } > > I might be wrong, but I don't think it is possible, Maybe Pavel or Jens > could help (added to CC). Basically as long as > fuse_uring_async_stop_queues() runs we do not have completed all > io-uring commands via io_uring_cmd_done() and as long as we do not have > completed these io-uring commands. If I understand the question right, yes, fuse io_uring cmd requests hold a reference to the fuse file, so until you complete them the file will not get released. -- Pavel Begunkov ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-18 9:06 ` Pavel Begunkov @ 2026-05-18 9:50 ` Bernd Schubert 2026-05-18 10:32 ` Pavel Begunkov 0 siblings, 1 reply; 20+ messages in thread From: Bernd Schubert @ 2026-05-18 9:50 UTC (permalink / raw) To: Pavel Begunkov, Bernd Schubert, Berkant Koc, Greg KH, Miklos Szeredi Cc: security@kernel.org, Joanne Koong, linux-kernel@vger.kernel.org, io-uring@vger.kernel.org, Jens Axboe, fuse-devel On 5/18/26 11:06, Pavel Begunkov wrote: > On 5/17/26 16:00, Bernd Schubert wrote: >> On 5/17/26 14:59, Berkant Koc wrote: >>> [You don't often get email from me@berkoc.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ] >>> >>> From: Berkant Koc <me@berkoc.com> >>> >>> fuse_dev_release() on the last fuse_dev of a connection calls >>> fuse_abort_conn(fc) and then immediately fuse_conn_put(fc). For io-uring >>> backed connections fuse_abort_conn() reaches fuse_uring_abort(), which >>> runs fuse_uring_teardown_all_queues() synchronously once and then >>> schedules ring->async_teardown_work to run after >>> FUSE_URING_TEARDOWN_INTERVAL (HZ/20). If the synchronous pass left >>> queue_refs > 0 the work owns further accesses to ring->queues[*]-> >>> ent_avail_queue and ent_in_userspace entries. >>> >>> Meanwhile fuse_conn_put() can drop the last reference and arm >>> delayed_release() via call_rcu(). After the RCU grace period >>> delayed_release() calls fuse_uring_destruct(), which kfree()s the ring >>> entries on each queue->ent_released list. The previously scheduled >>> async_teardown_work then runs and walks per-queue lists that contain >>> freed entries, producing a slab-use-after-free reported by KASAN at >>> fuse_uring_teardown_all_queues+0xee reading ent->list.next from a >>> freed kmalloc-192 region. >>> >>> fuse_wait_aborted() already exists for this purpose: it waits on >>> fc->blocked_waitq for num_waiting to drain and then calls >>> fuse_uring_wait_stopped_queues(), which waits for ring->queue_refs to >>> reach zero. Call it between fuse_abort_conn() and fuse_conn_put() on >>> the last-device path so the io-uring teardown work has fully drained >>> before the connection can be torn down. >>> >>> Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") >>> Cc: stable@vger.kernel.org # 6.14+ >>> Tested-by: Berkant Koc <me@berkoc.com> >>> Signed-off-by: Berkant Koc <me@berkoc.com> >>> --- >>> fs/fuse/dev.c | 1 + >>> 1 file changed, 1 insertion(+) >>> >>> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c >>> index 5dda7080f4a9..7d9c06654a98 100644 >>> --- a/fs/fuse/dev.c >>> +++ b/fs/fuse/dev.c >>> @@ -2566,6 +2566,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) >>> if (last) { >>> WARN_ON(fc->iq.fasync != NULL); >>> fuse_abort_conn(fc); >>> + fuse_wait_aborted(fc); >>> } >>> fuse_conn_put(fc); >>> } >> >> I might be wrong, but I don't think it is possible, Maybe Pavel or Jens >> could help (added to CC). Basically as long as >> fuse_uring_async_stop_queues() runs we do not have completed all >> io-uring commands via io_uring_cmd_done() and as long as we do not have >> completed these io-uring commands. > > If I understand the question right, yes, fuse io_uring cmd requests hold > a reference to the fuse file, so until you complete them the file will > not get released. Sorry, had totally messed up the phrase, can't read it myself. What I mean is that the io-uring was set up with /dev/fuse as file and as long as fuse holds non-completed 'struct io_uring_cmd *cmd' objects there is a reference on the /dev/fuse fd, which blocks the call of fuse_dev_release(). Thanks, Bernd ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev 2026-05-18 9:50 ` Bernd Schubert @ 2026-05-18 10:32 ` Pavel Begunkov 0 siblings, 0 replies; 20+ messages in thread From: Pavel Begunkov @ 2026-05-18 10:32 UTC (permalink / raw) To: Bernd Schubert, Bernd Schubert, Berkant Koc, Greg KH, Miklos Szeredi Cc: security@kernel.org, Joanne Koong, linux-kernel@vger.kernel.org, io-uring@vger.kernel.org, Jens Axboe, fuse-devel On 5/18/26 10:50, Bernd Schubert wrote: >>>> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c >>>> index 5dda7080f4a9..7d9c06654a98 100644 >>>> --- a/fs/fuse/dev.c >>>> +++ b/fs/fuse/dev.c >>>> @@ -2566,6 +2566,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) >>>> if (last) { >>>> WARN_ON(fc->iq.fasync != NULL); >>>> fuse_abort_conn(fc); >>>> + fuse_wait_aborted(fc); >>>> } >>>> fuse_conn_put(fc); >>>> } >>> >>> I might be wrong, but I don't think it is possible, Maybe Pavel or Jens >>> could help (added to CC). Basically as long as >>> fuse_uring_async_stop_queues() runs we do not have completed all >>> io-uring commands via io_uring_cmd_done() and as long as we do not have >>> completed these io-uring commands. >> >> If I understand the question right, yes, fuse io_uring cmd requests hold >> a reference to the fuse file, so until you complete them the file will >> not get released. > > > Sorry, had totally messed up the phrase, can't read it myself. > > What I mean is that the io-uring was set up with /dev/fuse as file and > as long as fuse holds non-completed 'struct io_uring_cmd *cmd' objects > there is a reference on the /dev/fuse fd, which blocks the call of > fuse_dev_release(). Yep, that's right -- Pavel Begunkov ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown 2026-05-17 12:59 ` [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown Berkant Koc 2026-05-17 12:59 ` [PATCH 1/2] fuse: io-uring: clear ent->fuse_req in commit_fetch error path Berkant Koc 2026-05-17 12:59 ` [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev Berkant Koc @ 2026-05-17 13:14 ` Berkant Koc 2026-05-17 13:43 ` Bernd Schubert 2 siblings, 1 reply; 20+ messages in thread From: Berkant Koc @ 2026-05-17 13:14 UTC (permalink / raw) To: Greg KH, Miklos Szeredi, Bernd Schubert Cc: linux-fsdevel, linux-kernel, security, Joanne Koong Quick correction on the Cc list of this series: linux-fuse@vger.kernel.org does not exist as a vger list and the three patch mails bounced from it (550 5.1.1 User unknown). Per MAINTAINERS, the FUSE list is linux-fsdevel@vger.kernel.org; adding it now so the series shows up in the lore.kernel.org archive for the FUSE-fsdevel readership. The original patches and KASAN context are in this thread via In-Reply-To. No content change to the patches; this is purely a list-routing fix. Apologies for the noise. Berkant ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown 2026-05-17 13:14 ` [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown Berkant Koc @ 2026-05-17 13:43 ` Bernd Schubert 2026-05-17 14:02 ` Berkant Koc 0 siblings, 1 reply; 20+ messages in thread From: Bernd Schubert @ 2026-05-17 13:43 UTC (permalink / raw) To: Berkant Koc, Greg KH, Miklos Szeredi, Bernd Schubert Cc: linux-fsdevel, linux-kernel, security, Joanne Koong On 5/17/26 15:14, Berkant Koc wrote: > Quick correction on the Cc list of this series: > > linux-fuse@vger.kernel.org does not exist as a vger list and the > three patch mails bounced from it (550 5.1.1 User unknown). The right list is fuse-devel@lists.linux.dev. MAINTAINERS file is in the process to get updated. > Per MAINTAINERS, the FUSE list is linux-fsdevel@vger.kernel.org; > adding it now so the series shows up in the lore.kernel.org archive > for the FUSE-fsdevel readership. The original patches and KASAN > context are in this thread via In-Reply-To. > > No content change to the patches; this is purely a list-routing fix. > > Apologies for the noise. > > Berkant > Thanks, Bernd ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown 2026-05-17 13:43 ` Bernd Schubert @ 2026-05-17 14:02 ` Berkant Koc 0 siblings, 0 replies; 20+ messages in thread From: Berkant Koc @ 2026-05-17 14:02 UTC (permalink / raw) To: Bernd Schubert Cc: Miklos Szeredi, Greg KH, security, Joanne Koong, linux-fsdevel, linux-kernel, fuse-devel Thanks Bernd, adding fuse-devel@lists.linux.dev to Cc now so this subthread lands in the right archive. Will use that as the FUSE mailing list going forward. Berkant ^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2026-05-18 17:51 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260517095846.fuse-iouring-uaf.dc5f5dbb71dc@berkoc.com>
[not found] ` <2026051703-equinox-multitude-91e2@gregkh>
2026-05-17 12:59 ` [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown Berkant Koc
2026-05-17 12:59 ` [PATCH 1/2] fuse: io-uring: clear ent->fuse_req in commit_fetch error path Berkant Koc
2026-05-17 14:11 ` Bernd Schubert
2026-05-17 14:24 ` Berkant Koc
2026-05-17 12:59 ` [PATCH 2/2] fuse: wait for aborted connection before releasing last fuse_dev Berkant Koc
2026-05-17 15:00 ` Bernd Schubert
2026-05-18 1:13 ` Berkant Koc
2026-05-18 9:55 ` Bernd Schubert
2026-05-18 11:47 ` Bernd Schubert
2026-05-18 14:32 ` Berkant Koc
2026-05-18 14:46 ` Bernd Schubert
2026-05-18 15:35 ` Joanne Koong
2026-05-18 17:49 ` Berkant Koc
2026-05-18 15:47 ` Berkant Koc
2026-05-18 9:06 ` Pavel Begunkov
2026-05-18 9:50 ` Bernd Schubert
2026-05-18 10:32 ` Pavel Begunkov
2026-05-17 13:14 ` [PATCH 0/2] fuse: io-uring: fix two UAFs in dev_uring.c teardown Berkant Koc
2026-05-17 13:43 ` Bernd Schubert
2026-05-17 14:02 ` Berkant Koc
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.