From: Guixin Liu <kanie@linux.alibaba.com>
To: Keith Busch <kbusch@kernel.org>, Jens Axboe <axboe@kernel.dk>,
Christoph Hellwig <hch@lst.de>, Sagi Grimberg <sagi@grimberg.me>,
Nilay Shroff <nilay@linux.ibm.com>,
Daniel Wagner <dwagner@suse.de>, Hannes Reinecke <hare@suse.de>
Cc: linux-nvme@lists.infradead.org
Subject: [PATCH v2 2/5] nvme-fc: fix use-after-free in nvme_fc_match_disconn_ls()
Date: Mon, 9 Nov 2026 10:26:43 +0800 [thread overview]
Message-ID: <20261109022646.290792-3-kanie@linux.alibaba.com> (raw)
In-Reply-To: <20261109022646.290792-1-kanie@linux.alibaba.com>
Commit b71cbcf7d170e ("nvme-fc: don't hold rport lock when putting ctrl")
dropped the rport lock inside the loop to put the reference of a
non-matching controller, because nvme_fc_ctrl_free() takes the rport
lock to unlink the controller. But no iterator is sound across that
drop: with list_for_each_entry_safe() the prefetched next entry can be
freed in the window, and with a plain iterator the loop's own
nvme_fc_ctrl_put() can be the final reference, freeing the current
entry before the iterator reads its ->next pointer.
The reference dance is unnecessary in the first place. An entry cannot
leave ctrl_list while rport->lock is held, as the final put unlinks it
under that very lock, so association_id can be inspected under
ctrl->lock without holding a reference. Take a reference only for the
matching controller, still under the rport lock, and hand it to the
caller as before. The loop then no longer needs to drop the lock at
all, which also removes the reason the lock was dropped for in the
first place.
Fixes: b71cbcf7d170e ("nvme-fc: don't hold rport lock when putting ctrl")
Cc: stable@vger.kernel.org
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
---
Reproduced under KASAN in a VM through fcloop with several controllers
on one remote port and a tbkas force-reconnect racing concurrent
controller disconnects; the lock-drop window was widened with a
test-only mdelay(200) to make the microsecond window deterministic:
BUG: KASAN: slab-use-after-free in nvme_fc_match_disconn_ls
Read of size 8 by task kworker
Workqueue: events nvme_fc_handle_ls_rqst_work
Call Trace:
nvme_fc_match_disconn_ls
nvme_fc_ls_disconnect_assoc
nvme_fc_handle_ls_rqst_work
process_one_work
The freed object was the prefetched next entry, allocated by
nvme_fc_alloc_ctrl() on connect and freed by nvme_free_ctrl() on the
concurrent teardown. The loop increment dereferences it before
nvme_fc_ctrl_get() gets a chance to reject it, which is why the
get-unless-zero check in the loop body does not help. The reworked
loop does not drop the lock, so no such window is left to widen.
---
drivers/nvme/host/fc.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 0b9ff50d26ff..e28eafc362db 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -1470,29 +1470,31 @@ nvme_fc_match_disconn_ls(struct nvme_fc_rport *rport,
{
struct fcnvme_ls_disconnect_assoc_rqst *rqst =
&lsop->rqstbuf->rq_dis_assoc;
- struct nvme_fc_ctrl *ctrl, *tmp, *ret = NULL;
+ struct nvme_fc_ctrl *ctrl, *ret = NULL;
struct nvmefc_ls_rcv_op *oldls = NULL;
u64 association_id = be64_to_cpu(rqst->associd.association_id);
unsigned long flags;
spin_lock_irqsave(&rport->lock, flags);
- list_for_each_entry_safe(ctrl, tmp, &rport->ctrl_list, ctrl_list) {
- if (!nvme_fc_ctrl_get(ctrl))
- continue;
+ list_for_each_entry(ctrl, &rport->ctrl_list, ctrl_list) {
spin_lock(&ctrl->lock);
if (association_id == ctrl->association_id) {
- oldls = ctrl->rcv_disconn;
- ctrl->rcv_disconn = lsop;
- ret = ctrl;
+ /*
+ * Entries cannot leave the list while rport->lock is
+ * held, so they can be inspected without a reference.
+ * Only the match needs one, for the caller.
+ */
+ if (nvme_fc_ctrl_get(ctrl)) {
+ oldls = ctrl->rcv_disconn;
+ ctrl->rcv_disconn = lsop;
+ ret = ctrl;
+ }
}
spin_unlock(&ctrl->lock);
if (ret)
/* leave the ctrl get reference */
break;
- spin_unlock_irqrestore(&rport->lock, flags);
- nvme_fc_ctrl_put(ctrl);
- spin_lock_irqsave(&rport->lock, flags);
}
spin_unlock_irqrestore(&rport->lock, flags);
--
2.43.7
next prev parent reply other threads:[~2026-11-09 2:27 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 2:26 [PATCH v2 0/5] nvme: fabrics and target fixes Guixin Liu
2026-11-09 2:26 ` [PATCH v2 1/5] nvme: reject a reconnect_delay of 0 through sysfs Guixin Liu
2026-11-09 17:54 ` Keith Busch
2026-11-10 2:36 ` Guixin Liu
2026-11-09 2:26 ` Guixin Liu [this message]
2026-11-09 2:26 ` [PATCH v2 3/5] nvme-auth: fix data race on ctrl->transaction Guixin Liu
2026-11-09 2:31 ` sashiko-bot
2026-11-09 17:10 ` Keith Busch
2026-11-10 2:34 ` Guixin Liu
2026-11-09 2:26 ` [PATCH v2 4/5] nvmet: take subsys->lock in nvmet_subsys_attr_tbkas_store() Guixin Liu
2026-11-09 2:26 ` [PATCH v2 5/5] nvmet: use GFP_KERNEL for PR allocations Guixin Liu
2026-11-09 17:47 ` (subset) [PATCH v2 0/5] nvme: fabrics and target fixes Keith Busch
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=20261109022646.290792-3-kanie@linux.alibaba.com \
--to=kanie@linux.alibaba.com \
--cc=axboe@kernel.dk \
--cc=dwagner@suse.de \
--cc=hare@suse.de \
--cc=hch@lst.de \
--cc=kbusch@kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=nilay@linux.ibm.com \
--cc=sagi@grimberg.me \
/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