All of lore.kernel.org
 help / color / mirror / Atom feed
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 2/6] nvme-fc: fix iterator over rport->ctrl_list in nvme_fc_match_disconn_ls()
Date: Fri,  6 Nov 2026 09:58:38 +0800	[thread overview]
Message-ID: <20261106015842.3534898-3-kanie@linux.alibaba.com> (raw)
In-Reply-To: <20261106015842.3534898-1-kanie@linux.alibaba.com>

Commit b71cbcf7d170e ("nvme-fc: don't hold rport lock when putting ctrl")
switched the loop to list_for_each_entry_safe() to allow dropping the
rport lock for the nvme_fc_ctrl_put() of a non-matching controller.
But the safe iterator only protects the current entry within one
iteration: the next entry is cached before the body runs, and while
the lock is dropped that entry can run through its own final put into
nvme_fc_ctrl_free(), which removes it from the list and frees it.
The next iteration then dereferences freed memory.

The safe variant is not needed here at all. The reference the loop
takes on the current entry pins it on the list until the iteration
moves on, so a plain list_for_each_entry() tolerates the lock drop:
while the lock is held the current entry cannot be unlinked, and once
the lock is dropped the cached ->next of the pinned entry still points
at a valid list member or the head.

Switch back to the plain iterator.

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 three or more
controllers on one remote port, a tbkas force-reconnect racing
concurrent controller disconnects.  The lock-drop window was widened
with a test-only mdelay(200) inserted at the same place in both the
buggy and the fixed version so the iterator is the only variable; the
stock microsecond window did not trigger in 400 iterations of the
same workload.

  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 object was allocated by nvme_fc_alloc_ctrl() on connect and freed
by nvme_free_ctrl() on the concurrent teardown of the cached next
entry.  With the plain iterator the identical amplified sequence
reports nothing and survives; the read hits the pinned current entry,
which cannot be freed while the loop holds its reference.
---
 drivers/nvme/host/fc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 0b9ff50d26ff..edf192055618 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -1470,14 +1470,14 @@ 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) {
+	list_for_each_entry(ctrl, &rport->ctrl_list, ctrl_list) {
 		if (!nvme_fc_ctrl_get(ctrl))
 			continue;
 		spin_lock(&ctrl->lock);
-- 
2.43.7



  parent reply	other threads:[~2026-11-06  1:58 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-06  1:58 [PATCH 0/6] nvme: fabrics and target fixes Guixin Liu
2026-11-06  1:58 ` [PATCH 1/6] nvme: reject a reconnect_delay of 0 through sysfs Guixin Liu
2026-11-06  2:09   ` sashiko-bot
2026-11-06  7:39   ` Hannes Reinecke
2026-11-06 10:33   ` Christoph Hellwig
2026-11-06 13:32   ` Nilay Shroff
2026-11-06  1:58 ` Guixin Liu [this message]
2026-11-06  2:06   ` [PATCH 2/6] nvme-fc: fix iterator over rport->ctrl_list in nvme_fc_match_disconn_ls() sashiko-bot
2026-11-06  7:38   ` Hannes Reinecke
2026-11-06 10:49     ` Guixin Liu
2026-11-06  1:58 ` [PATCH 3/6] nvme-auth: fix data race on ctrl->transaction Guixin Liu
2026-11-06  7:27   ` Hannes Reinecke
2026-11-06  9:28     ` Guixin Liu
2026-11-06  1:58 ` [PATCH 4/6] nvmet: take subsys->lock in nvmet_subsys_attr_tbkas_store() Guixin Liu
2026-11-06  7:27   ` Hannes Reinecke
2026-11-06 10:34   ` Christoph Hellwig
2026-11-06 13:32   ` Nilay Shroff
2026-11-06  1:58 ` [PATCH 5/6] nvmet: fix controller reference leak in nvmet_install_queue() error paths Guixin Liu
2026-11-06  7:31   ` Hannes Reinecke
2026-11-06  9:29     ` Guixin Liu
2026-11-06  1:58 ` [PATCH 6/6] nvmet: use GFP_KERNEL for PR allocations Guixin Liu
2026-11-06  7:31   ` Hannes Reinecke
2026-11-06 10:35   ` Christoph Hellwig
2026-11-06 13:35   ` Nilay Shroff

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=20261106015842.3534898-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 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.