mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: syzbot <syzbot+77955102efac681ec73b@syzkaller.appspotmail.com>
To: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com
Subject: Forwarded: [PATCH] nvmet-fc: fix use-after-free of nvmet_fc_ls_req_op
Date: Sun, 20 Sep 2026 07:09:55 -0700	[thread overview]
Message-ID: <6aafe933.e548f532.1ca396.000b.GAE@google.com> (raw)
In-Reply-To: <6aaf3eb5.3179f8cd.1e36b2.0006.GAE@google.com>

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] nvmet-fc: fix use-after-free of nvmet_fc_ls_req_op
Author: kartikey406@gmail.com

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master


nvmet_fc_free_pending_reqs() unconditionally frees each queued
nvmet_fc_ls_req_op (lsop) when a targetport is unregistered, but an
LLDD (e.g. fcloop) may still hold a pointer to that request queued on
its own async work, with no way for the target core to know.

If the targetport is torn down while such a request is still in
flight, the LLDD later dereferences the freed lsop when its completion
work runs, causing a slab-use-after-free.

Fix this by refcounting nvmet_fc_ls_req_op: one reference for the
core's ls_req_list, and one for the in-flight request handed to the
LLDD via ->ls_req(). The object is only freed once both the normal
completion path (__nvmet_fc_finish_ls_req) and teardown
(nvmet_fc_free_pending_reqs) have dropped their reference, whichever
runs last.

Reported-by: syzbot+77955102efac681ec73b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=77955102efac681ec73b
Signed-off-by: Deepanshu kartikey <kartikey406@gmail.com>
---
 drivers/nvme/target/fc.c | 38 ++++++++++++++++++++++++--------------
 1 file changed, 24 insertions(+), 14 deletions(-)

diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c
index 1b557775e033..a25f7579049d 100644
--- a/drivers/nvme/target/fc.c
+++ b/drivers/nvme/target/fc.c
@@ -56,6 +56,7 @@ struct nvmet_fc_ls_req_op {		/* for an LS RQST XMT */
 	bool				req_queued;
 
 	struct work_struct		put_work;
+	struct kref                     ref;
 };
 
 
@@ -339,6 +340,22 @@ fc_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
 		dma_unmap_sg(dev, sg, nents, dir);
 }
 
+static void
+nvmet_fc_ls_req_op_release(struct kref *ref)
+{
+    struct nvmet_fc_ls_req_op *lsop =
+        container_of(ref, struct nvmet_fc_ls_req_op, ref);
+    struct nvmet_fc_tgtport *tgtport = lsop->tgtport;
+    struct nvmefc_ls_req *lsreq = &lsop->ls_req;
+
+    if (lsop->req_queued)
+        fc_dma_unmap_single(tgtport->dev, lsreq->rqstdma,
+                    (lsreq->rqstlen + lsreq->rsplen),
+                    DMA_BIDIRECTIONAL);
+    queue_work(nvmet_wq, &lsop->put_work);
+}
+
+
 
 /* ********************** FC-NVME LS XMT Handling ************************* */
 
@@ -347,7 +364,6 @@ static void
 __nvmet_fc_finish_ls_req(struct nvmet_fc_ls_req_op *lsop)
 {
 	struct nvmet_fc_tgtport *tgtport = lsop->tgtport;
-	struct nvmefc_ls_req *lsreq = &lsop->ls_req;
 	unsigned long flags;
 
 	spin_lock_irqsave(&tgtport->lock, flags);
@@ -363,12 +379,8 @@ __nvmet_fc_finish_ls_req(struct nvmet_fc_ls_req_op *lsop)
 
 	spin_unlock_irqrestore(&tgtport->lock, flags);
 
-	fc_dma_unmap_single(tgtport->dev, lsreq->rqstdma,
-				  (lsreq->rqstlen + lsreq->rsplen),
-				  DMA_BIDIRECTIONAL);
-
 out_putwork:
-	queue_work(nvmet_wq, &lsop->put_work);
+	kref_put(&lsop->ref, nvmet_fc_ls_req_op_release);
 }
 
 static int
@@ -406,12 +418,16 @@ __nvmet_fc_send_ls_req(struct nvmet_fc_tgtport *tgtport,
 
 	lsop->req_queued = true;
 
+	kref_init(&lsop->ref);
+	kref_get(&lsop->ref);
 	spin_unlock_irqrestore(&tgtport->lock, flags);
 
 	ret = tgtport->ops->ls_req(&tgtport->fc_target_port, lsop->hosthandle,
 				   lsreq);
-	if (ret)
+	if (ret) {
+		kref_put(&lsop->ref, nvmet_fc_ls_req_op_release);
 		goto out_unlink;
+	}
 
 	return 0;
 
@@ -1591,7 +1607,6 @@ static void
 nvmet_fc_free_pending_reqs(struct nvmet_fc_tgtport *tgtport)
 {
 	struct nvmet_fc_ls_req_op *lsop;
-	struct nvmefc_ls_req *lsreq;
 	struct nvmet_fc_ls_iod *iod;
 	int i;
 
@@ -1611,12 +1626,7 @@ nvmet_fc_free_pending_reqs(struct nvmet_fc_tgtport *tgtport)
 		if (!lsop->req_queued)
 			continue;
 
-		lsreq = &lsop->ls_req;
-		fc_dma_unmap_single(tgtport->dev, lsreq->rqstdma,
-				    (lsreq->rqstlen + lsreq->rsplen),
-				    DMA_BIDIRECTIONAL);
-		nvmet_fc_tgtport_put(tgtport);
-		kfree(lsop);
+		kref_put(&lsop->ref, nvmet_fc_ls_req_op_release);
 	}
 }
 
-- 
2.43.0


      parent reply	other threads:[~2026-09-20 14:10 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-20  2:02 [syzbot] KASAN: slab-use-after-free Read in fcloop_rport_lsrqst_work syzbot
2026-09-20 14:06 ` Forwarded: [PATCH] nvmet-fc: fix use-after-free of nvmet_fc_ls_req_op syzbot
2026-09-20 14:09 ` syzbot [this message]

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=6aafe933.e548f532.1ca396.000b.GAE@google.com \
    --to=syzbot+77955102efac681ec73b@syzkaller.appspotmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=syzkaller-bugs@googlegroups.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®