From: Yogesh Gaur <yogeshgaur.83@gmail.com>
To: Keith Busch <kbusch@kernel.org>, Christoph Hellwig <hch@lst.de>,
Sagi Grimberg <sagi@grimberg.me>, Jens Axboe <axboe@kernel.dk>
Cc: stable@vger.kernel.org, linux-nvme@lists.infradead.org,
linux-kernel@vger.kernel.org,
Yogesh Gaur <yogeshgaur.83@gmail.com>,
syzbot+76c0f0ce8f1e846b4f84@syzkaller.appspotmail.com
Subject: [PATCH] nvme: keep a private copy of the effects log in the ns head
Date: Sun, 4 Oct 2026 12:50:52 +0530 [thread overview]
Message-ID: <20261004072052.1574-1-yogeshgaur.83@gmail.com> (raw)
nvme_alloc_ns_head() points head->effects at the creating controller's
Commands Supported and Effects log, which lives in ctrl->cels and is
freed by nvme_free_ctrl(). The head is owned by the subsystem, though:
with several controllers on one subsystem it is shared between them
and stays around after the controller that allocated it is gone. When
another controller then (re)scans the namespace, nvme_query_zone_info()
and nvme_command_effects() read the freed log:
BUG: KASAN: slab-use-after-free in nvme_query_zone_info+0x4fd/0x6f0 drivers/nvme/host/zns.c:47
Read of size 4 at addr ffff88802ab9e5f4 by task kworker/u8:2/43
Workqueue: async async_run_entry_fn
nvme_query_zone_info+0x4fd/0x6f0 drivers/nvme/host/zns.c:47
nvme_update_ns_info_block+0x1b2e/0x2af0 drivers/nvme/host/core.c:2430
nvme_update_ns_info+0xc6/0xd90 drivers/nvme/host/core.c:2553
nvme_alloc_ns+0x1a9f/0x3e50 drivers/nvme/host/core.c:4293
nvme_scan_ns+0x79d/0x910 drivers/nvme/host/core.c:4483
Allocated by task 6345:
nvme_get_effects_log+0x13a/0x280 drivers/nvme/host/core.c:3422
nvme_alloc_ns_head drivers/nvme/host/core.c:4037 [inline]
nvme_init_ns_head drivers/nvme/host/core.c:4153 [inline]
Freed by task 14867:
nvme_free_cels drivers/nvme/host/core.c:5165 [inline]
nvme_free_ctrl+0x1e4/0x6b0 drivers/nvme/host/core.c:5183
syzbot hits this with nvme-loop by connecting the same zoned subsystem
several times with duplicate_connect while deleting and rescanning the
controllers. The NVM command set case (head->effects = ctrl->effects)
has the same lifetime problem, as ctrl->effects is also stored in
ctrl->cels.
Give the head its own copy of the log, taken when the head is created
and freed together with it. That keeps today's behaviour of using the
first controller's log for the whole head, but no longer ties the
head's lifetime to that controller.
Fixes: be93e87e7802 ("nvme: support for multiple Command Sets Supported and Effects log pages")
Cc: stable@vger.kernel.org
Reported-by: syzbot+76c0f0ce8f1e846b4f84@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=34a8e8b643a20c2cbde3
Assisted-by: LLM
Signed-off-by: Yogesh Gaur <yogeshgaur.83@gmail.com>
---
drivers/nvme/host/core.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 5d7dfd7a63d4..f0df4c204e52 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -694,6 +694,7 @@ static void nvme_free_ns_head(struct kref *ref)
cleanup_srcu_struct(&head->srcu);
nvme_put_subsystem(head->subsys);
kfree(head->plids);
+ kfree(head->effects);
kfree(head);
}
@@ -4022,6 +4023,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ns *ns,
__must_hold(&ns->ctrl->subsys->lock)
{
struct nvme_ctrl *ctrl = ns->ctrl;
+ struct nvme_effects_log *effects;
struct nvme_ns_head *head;
size_t size = sizeof(*head);
int ret = -ENOMEM;
@@ -4052,11 +4054,22 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ns *ns,
ns->head = head;
if (head->ids.csi) {
- ret = nvme_get_effects_log(ctrl, head->ids.csi, &head->effects);
+ ret = nvme_get_effects_log(ctrl, head->ids.csi, &effects);
if (ret)
goto out_cleanup_srcu;
} else
- head->effects = ctrl->effects;
+ effects = ctrl->effects;
+
+ /*
+ * The effects log belongs to the controller and is freed with it, but
+ * the head can outlive this controller and be shared with others, so
+ * keep a private copy.
+ */
+ head->effects = kmemdup(effects, sizeof(*effects), GFP_KERNEL);
+ if (!head->effects) {
+ ret = -ENOMEM;
+ goto out_cleanup_srcu;
+ }
if (ctrl->ctratt & NVME_CTRL_ATTR_FDPS) {
ret = nvme_query_fdp_info(ns, info);
@@ -4076,6 +4089,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ns *ns,
out_cleanup_fdp:
kfree(head->plids);
out_cleanup_srcu:
+ kfree(head->effects);
cleanup_srcu_struct(&head->srcu);
out_ida_remove:
ida_free(&ctrl->subsys->ns_ida, head->instance);
--
2.55.0.windows.5
reply other threads:[~2026-10-04 7:21 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261004072052.1574-1-yogeshgaur.83@gmail.com \
--to=yogeshgaur.83@gmail.com \
--cc=axboe@kernel.dk \
--cc=hch@lst.de \
--cc=kbusch@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=sagi@grimberg.me \
--cc=stable@vger.kernel.org \
--cc=syzbot+76c0f0ce8f1e846b4f84@syzkaller.appspotmail.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®