[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