[PATCH 1/2] nvmet: pci-epf: fix subsysnqn configfs buffer overflow
shao.mingyin at zte.com.cn
shao.mingyin at zte.com.cn
Tue Nov 3 11:07:12 PST 2026
nvmet_pci_epf_subsysnqn_store() passes the length of the configfs write
to strscpy() as the destination size:
strscpy(nvme_epf->subsysnqn, page, len);
The third argument of strscpy() is the size of the destination buffer,
not the length of the source string. The destination is
subsysnqn[NVMF_NQN_SIZE], i.e. 223 bytes, while a configfs attribute
store can carry up to 4095 bytes. A longer NQN therefore overflows
subsysnqn into the following mdts_kb field and past the nvmet_pci_epf
object, corrupting the heap.
Using the write length also silently dropped the last byte of the value:
configfs terminates the buffer after the trailing newline that echo(1)
writes, so a normal write stored the right NQN while a write without a
newline lost its last character.
Take the length of the value up to the newline, reject a value that does
not fit and copy the NQN explicitly.
Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver")
Cc: stable at vger.kernel.org
Signed-off-by: Shao Mingyin <shao.mingyin at zte.com.cn>
---
Tested on 7.3.0-next-20261030 (QEMU/TCG guest) with configfs and
nvmet-pci-epf; the attribute store does not need a PCI endpoint
controller.
Writing 230 bytes to the subsysnqn attribute of an nvmet_pci_epf
instance runs past subsysnqn[NVMF_NQN_SIZE] (223) and overwrites the
following mdts_kb field:
unpatched patched
write accepted write rejected (-EINVAL)
mdts_kb 512 -> 4276545 (0x414141) mdts_kb stays 512
diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index a8df176c1a57..38c210cac961 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -2531,15 +2531,18 @@ static ssize_t nvmet_pci_epf_subsysnqn_store(struct config_item *item,
{
struct config_group *group = to_config_group(item);
struct nvmet_pci_epf *nvme_epf = to_nvme_epf(group);
+ size_t nqn_len;
/* Do not allow setting this when the function is already started. */
if (nvme_epf->ctrl.tctrl)
return -EBUSY;
- if (!len)
+ nqn_len = strcspn(page, "\n");
+ if (!nqn_len || nqn_len >= sizeof(nvme_epf->subsysnqn))
return -EINVAL;
- strscpy(nvme_epf->subsysnqn, page, len);
+ memcpy(nvme_epf->subsysnqn, page, nqn_len);
+ nvme_epf->subsysnqn[nqn_len] = '\0';
return len;
}
More information about the Linux-nvme
mailing list