From: Jun Yang <littleddfu@gmail.com>
To: Miklos Szeredi <miklos@szeredi.hu>, fuse-devel@lists.linux.dev
Cc: Zhao Chen <winters.zc@antgroup.com>,
linux-kernel@vger.kernel.org, Jun Yang <junvyyang@tencent.com>,
stable@kernel.org, TencentOS Corvus AI <corvus@tencent.com>
Subject: [PATCH 1/2] fuse: set FR_PENDING under fiq->lock in fuse_chan_resend()
Date: Tue, 4 Aug 2026 17:17:08 +0800 [thread overview]
Message-ID: <20260804091757.503476-2-junvyyang@tencent.com> (raw)
In-Reply-To: <20260804091757.503476-1-junvyyang@tencent.com>
FR_PENDING means "queued on fiq->pending, protected by fiq->lock". It is
the sole predicate fuse_remove_pending_req() uses to unlink a request and
drop the queue's reference.
fuse_chan_resend() breaks that invariant. It splices every fpq->processing
list onto a stack-local to_queue and drops fch->lock, then sets FR_PENDING
on each request while holding no lock at all. From that moment the request
advertises "I am on fiq->pending" while it is in fact reachable only
through the caller's stack. A waiter whose wait is interrupted takes
fiq->lock, sees FR_PENDING, unlinks the request from to_queue and drops its
reference, and fuse_chan_send() then drops the last one -- so the request
can be released while fuse_chan_resend() is still iterating over it.
fiq->lock serialises nothing here, because the request is not on an
fiq-protected list.
fuse_chan_resend() then walks that same list, and on the !fiq->connected
path it drops fiq->lock and walks it with a non-safe list_for_each_entry().
Publish FR_PENDING under fiq->lock, immediately before the splice that
actually puts the requests on fiq->pending, and fold the intr_entry cleanup
into the same locked walk. A waiter that arrives while the requests are
still on the stack now sees FR_PENDING clear, so fuse_remove_pending_req()
returns false and it falls through to wait_event(FR_FINISHED) -- the same
handling a request already handed to userspace gets. The !fiq->connected
path no longer needs to clear the bit, because it was never set.
Confirmed on v7.2-rc6 (075b74841bd0).
Fixes: 760eac73f9f6 ("fuse: Introduce a new notification type for resend pending requests")
Cc: stable@kernel.org
Reported-by: TencentOS Corvus AI <corvus@tencent.com>
Assisted-by: tencentos-corvus-ai:kimi-k3
Signed-off-by: Jun Yang <junvyyang@tencent.com>
---
A KASAN reproducer for this issue is available if requested.
fs/fuse/dev.c | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 5763a7cd3b37..e62c7ed8bcf4 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1781,26 +1781,22 @@ void fuse_chan_resend(struct fuse_chan *fch)
}
spin_unlock(&fch->lock);
- list_for_each_entry_safe(req, next, &to_queue, list) {
- set_bit(FR_PENDING, &req->flags);
- clear_bit(FR_SENT, &req->flags);
- /* mark the request as resend request */
- req->in.h.unique |= FUSE_UNIQUE_RESEND;
- }
-
spin_lock(&fiq->lock);
if (!fiq->connected) {
spin_unlock(&fiq->lock);
- list_for_each_entry(req, &to_queue, list)
- clear_bit(FR_PENDING, &req->flags);
fuse_dev_end_requests(&to_queue);
return;
}
- /*
- * Remove interrupt entries for resent requests to prevent stale
- * intr_entry on fiq->interrupts after the request is re-queued.
- */
- list_for_each_entry(req, &to_queue, list) {
+ list_for_each_entry_safe(req, next, &to_queue, list) {
+ /* must be set under fiq->lock, see fuse_remove_pending_req() */
+ set_bit(FR_PENDING, &req->flags);
+ clear_bit(FR_SENT, &req->flags);
+ /* mark the request as resend request */
+ req->in.h.unique |= FUSE_UNIQUE_RESEND;
+ /*
+ * Remove interrupt entries for resent requests to prevent stale
+ * intr_entry on fiq->interrupts after the request is re-queued.
+ */
if (test_bit(FR_INTERRUPTED, &req->flags))
list_del_init(&req->intr_entry);
}
--
2.43.7
next prev parent reply other threads:[~2026-08-04 9:18 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 9:17 [PATCH 0/2] fuse: fix request lifetime races in the resend path Jun Yang
2026-08-04 9:17 ` Jun Yang [this message]
2026-08-14 7:23 ` [PATCH 1/2] fuse: set FR_PENDING under fiq->lock in fuse_chan_resend() Tang Yizhou
2026-08-17 10:25 ` Jun Yang
2026-08-17 13:30 ` Tang Yizhou
2026-08-18 8:39 ` Miklos Szeredi
2026-08-18 9:55 ` Yizhou Tang
2026-08-04 9:17 ` [PATCH 2/2] fuse: don't queue an interrupt for a request that is back on fiq->pending Jun Yang
2026-08-14 8:49 ` Tang Yizhou
2026-08-14 6:19 ` [PATCH 0/2] fuse: fix request lifetime races in the resend path Tang Yizhou
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=20260804091757.503476-2-junvyyang@tencent.com \
--to=littleddfu@gmail.com \
--cc=corvus@tencent.com \
--cc=fuse-devel@lists.linux.dev \
--cc=junvyyang@tencent.com \
--cc=linux-kernel@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=stable@kernel.org \
--cc=winters.zc@antgroup.com \
/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 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.