From f8cef5c74d8b5a982f49cc40d13cd5c3ea2eacf6 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 15 Oct 2026 16:07:01 +0200 Subject: [PATCH] fuse: fix NULL pointer dereference in fuse_request_find MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fuse_dev_install_with_pq() publishes fud->chan before it stores fud->pq.processing. The write/splice_write and read paths treat a non-NULL fud->chan as "installed" and then walk fpq->processing[] without taking fch->lock, so they can see the new chan while processing is still NULL and oops in fuse_request_find(). Fix by taking fpq->lock around the cmpxchg + fud->pq.processing assignment. This protects all call sites that dereference fpq->processing, since these have fpq->lock held. Fixes: 48649c0603bd ("fuse: alloc pqueue before installing fch in fuse_dev") Reported-by: Cen Zhang Closes: https://lore.kernel.org/fuse-devel/pm-fuse-full-objects-candidate-0002-v2-17d6013e5066de33396c@gmail.com/ Reported-by: 马云龙 Closes: https://lore.kernel.org/all/5ddc8efe.1e6d2.1a11fbec860.Coremail.yunlong_ma@buaa.edu.cn/ Signed-off-by: Miklos Szeredi --- fs/fuse/dev.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 2d7ee5498f1c..adffa0e3b607 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -466,24 +466,27 @@ static bool fuse_dev_install_with_pq(struct fuse_dev *fud, struct fuse_chan *fch struct fuse_chan *old_fch; guard(spinlock)(&fch->lock); - /* - * Pairs with: - * - xchg() in fuse_dev_release() - * - smp_load_acquire() in fuse_dev_fc_get() - */ - old_fch = cmpxchg(&fud->chan, NULL, fch); - if (old_fch) { + /* protect fud->pq.processing assignment */ + scoped_guard(spinlock, &fud->pq.lock) { /* - * failed to set fud->chan because - * - it was already set to a different fc - * - it was set to disconneted + * Pairs with: + * - xchg() in fuse_dev_release() + * - smp_load_acquire() in fuse_dev_fc_get() */ - kfree(pq); - return false; - } - if (pq) { - WARN_ON(fud->pq.processing); - fud->pq.processing = pq; + old_fch = cmpxchg(&fud->chan, NULL, fch); + if (old_fch) { + /* + * failed to set fud->chan because + * - it was already set to a different fc + * - it was set to disconneted + */ + kfree(pq); + return false; + } + if (pq) { + WARN_ON(fud->pq.processing); + fud->pq.processing = pq; + } } list_add_tail(&fud->entry, &fch->devices); fuse_conn_get(fch->conn);