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
prev 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®