* [PATCH] nvmet-auth: fix uninitialized-memory leak in AUTH_RECEIVE
@ 2026-07-09 13:25 Ibrahim Hashimov
2026-07-11 7:53 ` Ibrahim Hashimov
0 siblings, 1 reply; 2+ messages in thread
From: Ibrahim Hashimov @ 2026-07-09 13:25 UTC (permalink / raw)
To: Hannes Reinecke, Christoph Hellwig, Sagi Grimberg,
Chaitanya Kulkarni
Cc: linux-nvme, linux-kernel, stable
nvmet_execute_auth_receive() allocates its response buffer with the
attacker-controlled AUTH_RECEIVE `al` (data length) field:
al = nvmet_auth_receive_data_len(req);
...
d = kmalloc(al, GFP_KERNEL);
...
switch (req->sq->dhchap_step) {
case NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE:
nvmet_auth_challenge(req, d, al);
...
status = nvmet_copy_to_sgl(req, 0, d, al);
nvmet_check_transfer_len() only enforces al == req->transfer_len, a
pure equality check with no upper bound tied to the message actually
being produced. nvmet_auth_challenge() computes its own data_size
(sizeof(challenge header) + hash_len, 48 bytes for SHA-256 with no DH
group) and only checks "al < data_size" as a floor -- it memset()s and
fills exactly data_size bytes of the buffer. The same pattern applies
to nvmet_auth_success1()/nvmet_auth_failure1(), which only memset()
sizeof(*data) bytes of `d`.
Whichever handler runs, nvmet_execute_auth_receive() then streams the
entire al-byte buffer back to the remote host with
nvmet_copy_to_sgl(req, 0, d, al). Since a remote NVMe-oF/TCP host
chooses `al` and can set it far larger than data_size (e.g. 4096 vs.
48), the tail [data_size, al) of the kmalloc()'d buffer is returned to
the peer without ever having been written by the kernel -- a remote,
pre-authentication disclosure of uninitialized kernel heap contents,
confirmed with KASAN by planting a marker byte in
a freed kmalloc-4096 object and observing it echoed back in the tail
of the CHALLENGE response. This is reachable as soon as
CONFIG_NVME_TARGET_AUTH is enabled (the default on Fedora/RHEL/Ubuntu
distro kernels) and a subsystem uses/allows the DH-CHAP auth path; no
secret needs to be proven first, since the leak occurs on the
CHALLENGE step of the handshake.
Fix it the same way nvmet_execute_disc_get_log_page() already handles
an analogous host-controlled-length response buffer
(drivers/nvme/target/discovery.c: "buffer = kzalloc(alloc_len,
GFP_KERNEL);"): zero the allocation up front instead of only zeroing
the sub-range each per-step helper happens to fill. This keeps the fix
to a single line, covers all three dhchap_step handlers that share
this buffer and the common copy-back site (CHALLENGE, SUCCESS1,
FAILURE1), and does not change the wire format, the transfer-length
checks, or any success/error paths.
Testing: the uninitialized-tail disclosure itself was confirmed live
under KASAN before this fix, by planting a marker byte in a freed
kmalloc-4096 object and observing it (or other live heap bytes)
echoed back in the CHALLENGE response tail; a CONTROL request with
al == data_size returned no such tail on every run, and an EXPLOIT
request with al = 4096 leaked up to 4048 bytes of stale heap on two
separate runs. The fix itself is verified by code inspection rather
than a fresh KASAN run: kzalloc() zeroes the whole al-byte allocation
before any dhchap_step handler executes, so the tail past whatever
bytes a handler's own memset()/fill writes is guaranteed zero instead
of leftover slab content, for all three handlers and the single
shared nvmet_copy_to_sgl() copy-back site. Re-running the KASAN
harness against a kernel built with this patch to reconfirm a
zero tail is currently blocked by an nvme-tcp loopback livelock in
the test stand; a controlled A/B check showed the same livelock on
the unpatched baseline as well, so it is a pre-existing harness
limitation, not something introduced by this one-line kzalloc()
change.
Fixes: db1312dd9548 ("nvmet: implement basic In-Band Authentication")
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
---
drivers/nvme/target/fabrics-cmd-auth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c
index 45820a12750d..2b617d3b8bba 100644
--- a/drivers/nvme/target/fabrics-cmd-auth.c
+++ b/drivers/nvme/target/fabrics-cmd-auth.c
@@ -557,7 +557,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req)
return;
}
- d = kmalloc(al, GFP_KERNEL);
+ d = kzalloc(al, GFP_KERNEL);
if (!d) {
status = NVME_SC_INTERNAL;
goto done;
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] nvmet-auth: fix uninitialized-memory leak in AUTH_RECEIVE
2026-07-09 13:25 [PATCH] nvmet-auth: fix uninitialized-memory leak in AUTH_RECEIVE Ibrahim Hashimov
@ 2026-07-11 7:53 ` Ibrahim Hashimov
0 siblings, 0 replies; 2+ messages in thread
From: Ibrahim Hashimov @ 2026-07-11 7:53 UTC (permalink / raw)
To: hare, hch, sagi, kch; +Cc: linux-nvme, linux-kernel
Please disregard this patch -- it duplicates Bryam Vargas's
"nvmet-auth: zero the AUTH_RECEIVE response buffer"
(https://lore.kernel.org/linux-nvme/20260702-b4-disp-127414cf-v1-1-e5395cc0f9ae@proton.me/),
which fixes the same uninitialized-memory leak with the same
kmalloc() -> kzalloc() change and the same Fixes: tag, and already has
Christoph's Reviewed-by. I missed it before sending; sorry for the
noise.
Ibrahim
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-11 7:54 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-09 13:25 [PATCH] nvmet-auth: fix uninitialized-memory leak in AUTH_RECEIVE Ibrahim Hashimov
2026-07-11 7:53 ` Ibrahim Hashimov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox