* [PATCH] nvmet-rdma: fix out-of-bounds write in nvmet_rdma_map_sgl_inline()
[not found] <166ea8e3-189e-4212-a457-e0b6e2e678f4@kernel.dk>
@ 2026-10-21 5:07 ` Andrew Stellman
2026-10-21 22:33 ` Keith Busch
0 siblings, 1 reply; 2+ messages in thread
From: Andrew Stellman @ 2026-10-21 5:07 UTC (permalink / raw)
To: Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni, linux-nvme
Cc: Keith Busch, Jens Axboe, Bryam Vargas, security, linux-kernel,
Andrew Stellman, stable
nvmet_rdma_map_sgl_inline() bounds the host-supplied in-capsule SGL
offset with "off + len > inline_data_size", evaluated in 64-bit
arithmetic. off is taken straight from the host SGL descriptor
(le64_to_cpu(sgl->addr)) and len is promoted to 64-bit, so the sum
wraps: an off within len of 2^64 makes it small and the check passes.
off is then used as page_idx = off / PAGE_SIZE to index the fixed-size
rsp->cmd->inline_sg[] array (NVMET_RDMA_MAX_INLINE_SGE entries), so a
crafted offset yields an out-of-bounds scatterlist index that is written
through in nvmet_rdma_use_inline_sg().
The mapping runs while handling a received capsule, before the command
executes, so a remote RDMA peer can reach it (the Connect capsule is a
write and takes this path on a queue that has no controller yet). The
host controls only the low bits of the resulting displacement, so the
expected impact is an out-of-bounds write that faults the target
(remote denial of service).
This wrap was reported, with a KASAN reproduction, on linux-nvme in May,
and the check below was suggested in that thread. The fix that was
applied, 48c0162f647b, reworked how the offset is mapped but kept the
original check, and its page index turns a wrapped offset into an
out-of-bounds index into inline_sg[].
Reject the offset before it can wrap.
Found independently by static analysis with AI assistance, not
reproduced at runtime.
Fixes: 0d5ee2b2ab4f ("nvmet-rdma: support max(16KB, PAGE_SIZE) inline data")
Fixes: 48c0162f647b ("nvmet-rdma: handle inline data with a nonzero offset")
Reported-by: Bryam Vargas <hexlabsecurity@proton.me>
Closes: https://lore.kernel.org/all/LM21QIR-1-qJb7PViyJKCnGBnUzizeiNJVWQ3wb7ZwGezodjgKg3f-iobqOyequ-sT1jFCKJImfqNO_BKU3KO80xFITnaI5GTV_GxLUNDDc=@proton.me/
Suggested-by: Keith Busch <kbusch@kernel.org>
Cc: stable@kernel.org
Assisted-by: Claude:claude-opus-5
Signed-off-by: Andrew Stellman <astellman@stellman-greene.com>
---
Thanks Jens, and sorry about missing the CCs. Here's the patch.
While preparing it I found that Bryam Vargas reported this same wrap on
linux-nvme in May, and Keith suggested this check in that thread. The
fix that went in (48c0162f647b) changed the offset mapping but kept the
old check, so the wrap is still in mainline and now indexes past
inline_sg[].
Tested: builds with no warnings (W=1) on mainline 4a8bdffce502 with
CONFIG_NVME_TARGET_RDMA=m, and passes checkpatch.pl. Not tested at
runtime, and there is no reproducer: triggering it needs a host that
sends a malformed in-capsule SGL, which a conforming initiator never
does, and I have not written one. The wrap and the out-of-bounds index
were confirmed in userspace against the expressions in the source. I'm
glad to help with testing.
The issue was found by Claude Opus 5 running Quality Playbook, an
LLM-driven code review tool:
https://github.com/andrewstellman/quality-playbook
drivers/nvme/target/rdma.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index ffa1e172c2..e47c572d82 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -864,7 +864,8 @@ static u16 nvmet_rdma_map_sgl_inline(struct nvmet_rdma_rsp *rsp)
return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
}
- if (off + len > rsp->queue->dev->inline_data_size) {
+ if (off > (u64)rsp->queue->dev->inline_data_size ||
+ len > (u64)rsp->queue->dev->inline_data_size - off) {
pr_err("invalid inline data offset!\n");
return NVME_SC_SGL_INVALID_OFFSET | NVME_STATUS_DNR;
}
--
2.43.0
^ permalink raw reply [flat|nested] 2+ messages in thread