[PATCH] nvmet: pci-epf: reject too-short SGL segments

Daehyeon Ko posted 1 patch 1 week, 3 days ago
drivers/nvme/target/pci-epf.c | 3 +++
1 file changed, 3 insertions(+)
[PATCH] nvmet: pci-epf: reject too-short SGL segments
Posted by Daehyeon Ko 1 week, 3 days ago
The host controls an SGL segment's length. A nonzero length smaller than
one SGL descriptor makes nr_descs zero, so
nvmet_pci_epf_get_sgl_segment() reads the type byte of sgls[-1] outside
the allocated buffer. If that byte contains a segment descriptor type,
the function also copies the preceding 16 bytes and returns a negative
descriptor count.

The read was reproduced in 3/3 KASAN boots with only the host transfer
mocked by a KUnit test:

  BUG: KASAN: slab-out-of-bounds in nvmet_pci_epf_get_sgl_segment
  Read of size 1 by task kunit_try_catch
  Call Trace:
   nvmet_pci_epf_get_sgl_segment
   nvmet_pci_epf_short_sgl_test
  Kernel panic - not syncing: KASAN: panic_on_warn set ...

Reject segments that cannot hold one descriptor before allocating or
transferring their contents.

Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Daehyeon Ko <4ncienth@gmail.com>
---
Affected since v6.14-rc1; verified in current mainline 587858367581,
Linux 7.2.6, and Linux 6.18.52. Triggering requires
CONFIG_NVME_TARGET_PCI_EPF and CONFIG_PCI_ENDPOINT, with a PCI host
supplying an SGL segment length from 1 through 15.

No PCI endpoint hardware was available. The fixed KASAN kernel passed
the same test in 3/3 fresh boots. Reproducer source is available privately
on request and is intentionally omitted from this public AI-assisted
submission.

 drivers/nvme/target/pci-epf.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index 9c28367435a5..c683450df422 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -978,6 +978,9 @@ nvmet_pci_epf_get_sgl_segment(struct nvmet_pci_epf_ctrl *ctrl,
 	int nr_descs, ret;
 	void *buf;
 
+	if (length < sizeof(struct nvme_sgl_desc))
+		return NULL;
+
 	buf = kmalloc(length, GFP_KERNEL);
 	if (!buf)
 		return NULL;

base-commit: 587858367581b9c55c3690f4e63382ad622719d4
Re: [PATCH] nvmet: pci-epf: reject too-short SGL segments
Posted by Christoph Hellwig 6 days, 19 hours ago
Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>