* nvmet: pre-auth heap OOB read in DH-HMAC-CHAP authentication (data->hl unchecked in nvmet_auth_reply)
@ 2026-06-02 3:32 Jeremy Erazo
2026-06-02 6:23 ` Greg KH
2026-06-02 8:50 ` Keith Busch
0 siblings, 2 replies; 5+ messages in thread
From: Jeremy Erazo @ 2026-06-02 3:32 UTC (permalink / raw)
To: security
Cc: Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Hannes Reinecke, Keith Busch, Jens Axboe, linux-nvme, stable
Hi,
I'm reporting an out-of-bounds read in `nvmet_auth_reply()`
(`drivers/nvme/target/fabrics-cmd-auth.c`), reachable from an
unauthenticated remote attacker against any nvmet host that has
DH-HMAC-CHAP authentication enabled on a configured subsystem.
The bug is present in **mainline torvalds/master** at audit time
(2026-06-02, verified via raw.githubusercontent.com fetch). It is
also present in stable LTS 6.6.x and other branches that ship the
NVMe-oF DH-HMAC-CHAP target (the function was added with the
DH-HMAC-CHAP target feature in 6.0).
CVSS 3.1 base: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N = **7.5 (High)**.
This is filed shortly after my earlier report of an arbitrary
kernel-memory read in `nvmet_execute_disc_get_log_page` (sent today
to this list). Both are in `drivers/nvme/target/` and both are
attacker-controlled-length-meets-pointer-arithmetic class — but they
are independent bugs with independent fixes.
== Affected code (cited from torvalds/master, 2026-06-02) ==
`drivers/nvme/target/fabrics-cmd-auth.c::nvmet_execute_auth_send()`
(the AUTH_Send PDU dispatcher) does:
tl = le32_to_cpu(req->cmd->auth_send.tl); /* attacker u32 */
if (!tl) { ... goto done; }
if (!nvmet_check_transfer_len(req, tl)) return;
d = kmalloc(tl, GFP_KERNEL);
if (!d) { ... }
status = nvmet_copy_from_sgl(req, 0, d, tl);
/* ... dispatch by data->auth_id ... */
if (data->auth_id == NVME_AUTH_DHCHAP_MESSAGE_REPLY)
dhchap_status = nvmet_auth_reply(req, d);
The ONLY validation of `tl` is "non-zero" and that the SGL transfer
length matches the command's declared length. There is no check that
`tl` is large enough to contain the struct header *plus* the
payload that the message body advertises.
`nvmet_auth_reply()` then does:
struct nvmf_auth_dhchap_reply_data *data = d;
u16 dhvlen = le16_to_cpu(data->dhvlen);
u8 *response;
if (dhvlen) {
if (!ctrl->dh_tfm) ...
if (nvmet_auth_ctrl_sesskey(req, data->rval + 2 * data->hl, /* OOB#3 */
dhvlen) < 0) ...
}
response = kmalloc(data->hl, GFP_KERNEL);
...
if (nvmet_auth_host_hash(req, response, data->hl) < 0) ...
if (memcmp(data->rval, response, data->hl)) /* OOB#1 */
...
if (data->cvalid) {
req->sq->dhchap_c2 = kmemdup(data->rval + data->hl, data->hl, /* OOB#2 */
GFP_KERNEL);
...
}
Three call sites use `data->hl` (an attacker-controlled u8, range
0-255 from the wire) and `data->dhvlen` (an attacker-controlled
__le16, range 0-65535) as offsets into / lengths reading from
`data->rval` without any prior check that the PDU transfer length
contained the corresponding bytes.
Supporting struct (`include/linux/nvme.h:1712`):
struct nvmf_auth_dhchap_reply_data {
__u8 auth_type;
__u8 auth_id;
__le16 rsvd1;
__le16 t_id;
__u8 hl; /* attacker u8 */
__u8 rsvd2;
__u8 cvalid;
__u8 rsvd3;
__le16 dhvlen; /* attacker __le16 */
__le32 seqnum;
/* 'hl' bytes of response data */
__u8 rval[];
/* followed by 'hl' bytes of Challenge value */
/* followed by 'dhvlen' bytes of DH value */
};
`sizeof(struct nvmf_auth_dhchap_reply_data)` = 16 bytes (header only).
== Attack flow ==
1. Attacker opens TCP/4420 to a nvmet host that has DH-HMAC-CHAP
configured on at least one subsystem.
2. Sends NVMe-TCP ICReq, receives ICResp (transport handshake).
3. Sends NVMe-Fabrics Connect with `subsysnqn = <target subsys with
CHAP>`, any `hostnqn`. (Connect succeeds; the controller now
expects the host to drive the CHAP exchange.)
4. Sends AUTH_Send with `auth_id = MESSAGE_NEGOTIATE`, advertising
any supported hash (e.g., SHA-256).
5. AUTH_Receive — controller sends CHALLENGE.
6. Sends a malicious AUTH_Send with:
auth_type = NVME_AUTH_DHCHAP_MESSAGES (1)
auth_id = NVME_AUTH_DHCHAP_MESSAGE_REPLY (2)
tl = 16 (sizeof(struct nvmf_auth_dhchap_reply_data) only;
no rval[] payload)
data->hl = 0xff
data->cvalid = 1
data->dhvlen = 0
7. Kernel:
- kmalloc(16) returns a kmalloc-16 slab object (SLUB rounds up).
- copy_from_sgl writes the 16-byte attacker header into it.
- data = d; data->rval = d + 16 = past the allocation.
- memcmp(data->rval, response, 255) reads 255 bytes starting at
offset 16 of the kmalloc-16 slab object — directly into the
adjacent slab object.
- If data->cvalid is set, kmemdup(data->rval + 255, 255) reads
an additional 510 bytes past the allocation and copies 255 of
them into a new kernel allocation (which the attacker can
later exfil via further wire messages if the CHAP exchange
continues, e.g., via AUTH_Receive's payload).
== KASAN catch signature (expected) ==
Under KASAN this produces a slab-out-of-bounds READ report tied to
`memcmp` / `kmemdup` called from `nvmet_auth_reply`:
BUG: KASAN: slab-out-of-bounds in memcmp+0x... (or __asan_memcmp)
Read of size 255 at addr ffff... by task kworker/...
Call Trace:
memcmp
nvmet_auth_reply
nvmet_execute_auth_send
nvmet_tcp_io_work
...
I've prepared an in-kernel proof module
(`nvmet-auth-oob-proof.c`) that replicates the primitive against a
deliberately-undersized buffer to make the KASAN signature explicit;
it's a one-shot module that builds against any current 6.x kernel
tree. Available on request — withheld from this initial mail to keep
disclosure surface minimal.
A userspace network reproducer (Python NVMe-TCP client driving the
CHAP state machine through the malicious AUTH_Send) is in progress
and will follow.
== Fix proposal ==
Validate the PDU transfer length covers the struct header *plus* the
hl- and dhvlen-derived payload before any pointer arithmetic on
data->rval. The minimal fix sits at the entry to nvmet_auth_reply:
--- a/drivers/nvme/target/fabrics-cmd-auth.c
+++ b/drivers/nvme/target/fabrics-cmd-auth.c
@@ -112,6 +112,7 @@ static u8 nvmet_auth_reply(struct nvmet_req *req, void *d)
{
struct nvmet_ctrl *ctrl = req->sq->ctrl;
struct nvmf_auth_dhchap_reply_data *data = d;
+ u32 tl = le32_to_cpu(req->cmd->auth_send.tl);
u16 dhvlen = le16_to_cpu(data->dhvlen);
u8 *response;
@@ -119,6 +120,16 @@ static u8 nvmet_auth_reply(struct nvmet_req *req, void *d)
__func__, ctrl->cntlid, req->sq->qid,
data->hl, data->cvalid, dhvlen);
+ /* Confirm the transferred length actually contains the
+ * rval payload the message body advertises. The host
+ * response is hl bytes; with cvalid set, hl more bytes
+ * of challenge follow; with dhvlen set, dhvlen more
+ * bytes of DH value follow.
+ */
+ if (tl < sizeof(*data) + data->hl +
+ (data->cvalid ? data->hl : 0) + dhvlen)
+ return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
+
if (dhvlen) {
if (!ctrl->dh_tfm)
return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
The same shape applies to `nvmet_auth_negotiate` and any other
auth-state handler that reads variable-length fields from the
attacker buffer. A defence-in-depth alternative is to do this length
validation once inside `nvmet_execute_auth_send` before dispatching,
since the handler-specific math (hl, dhvlen, etc.) varies per
message type.
== Affected branches ==
Confirmed vulnerable: mainline torvalds/master at 2026-06-02
(verified via raw.githubusercontent.com fetch).
Probable also vulnerable: linux-stable 6.6.x, 6.1.x (where the
DH-HMAC-CHAP target was backported), and distros tracking those
(Debian/Ubuntu/RHEL/SUSE).
NOT vulnerable: any kernel without `CONFIG_NVME_TARGET_AUTH=y` (the
auth subsystem isn't compiled in).
== Threat model ==
This is reachable pre-final-authentication: the attacker has
completed Fabrics Connect (which establishes the controller binding)
but has not yet completed the CHAP handshake. CHAP is exactly what
this code is supposed to enforce; the bug is in the CHAP enforcement
itself. The kernel cannot rely on CHAP being effective when the CHAP
handler can be tricked into reading past its input buffer before any
secret is verified.
Network reachability is "any host that can open TCP/4420 to the
nvmet target". In production NVMe-oF deployments this is the same
exposure surface that DH-HMAC-CHAP exists to protect — i.e., the
mitigation is the bug.
== Researcher / Credit ==
Jeremy Erazo (trexnegr0)
mendozayt13@gmail.com
Signed-off-by: Jeremy Erazo <mendozayt13@gmail.com>
== Disclosure preferences ==
I'm happy with any reasonable embargo length (14-30 days). I have
not shared this finding with any third party. Please coordinate CVE
assignment with the kernel.org CNA.
This is the second nvmet finding I'm reporting today; both are
independent bugs but they neighbour each other in the same subsystem
and one combined backport batch on the stable side might be the
cleanest disposition. Happy to coordinate that with whichever route
your team prefers.
Thanks for your time.
— Jeremy
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: nvmet: pre-auth heap OOB read in DH-HMAC-CHAP authentication (data->hl unchecked in nvmet_auth_reply)
2026-06-02 3:32 nvmet: pre-auth heap OOB read in DH-HMAC-CHAP authentication (data->hl unchecked in nvmet_auth_reply) Jeremy Erazo
@ 2026-06-02 6:23 ` Greg KH
2026-06-02 8:50 ` Keith Busch
1 sibling, 0 replies; 5+ messages in thread
From: Greg KH @ 2026-06-02 6:23 UTC (permalink / raw)
To: Jeremy Erazo
Cc: security, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Hannes Reinecke, Keith Busch, Jens Axboe, linux-nvme, stable
On Mon, Jun 01, 2026 at 08:32:37PM -0700, Jeremy Erazo wrote:
> == Disclosure preferences ==
>
> I'm happy with any reasonable embargo length (14-30 days). I have
> not shared this finding with any third party. Please coordinate CVE
> assignment with the kernel.org CNA.
You sent this to a public mailing list, there is no "embargo" possible.
Nor is this how CVEs are assigned (please read the documentation for
that.)
Please submit a patch for both of the issues you reported, in a format
that can be applied, so this can be resolved properly.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: nvmet: pre-auth heap OOB read in DH-HMAC-CHAP authentication (data->hl unchecked in nvmet_auth_reply)
2026-06-02 3:32 nvmet: pre-auth heap OOB read in DH-HMAC-CHAP authentication (data->hl unchecked in nvmet_auth_reply) Jeremy Erazo
2026-06-02 6:23 ` Greg KH
@ 2026-06-02 8:50 ` Keith Busch
2026-06-02 8:56 ` Keith Busch
1 sibling, 1 reply; 5+ messages in thread
From: Keith Busch @ 2026-06-02 8:50 UTC (permalink / raw)
To: Jeremy Erazo
Cc: security, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Hannes Reinecke, Jens Axboe, linux-nvme, stable
On Mon, Jun 01, 2026 at 08:32:37PM -0700, Jeremy Erazo wrote:
> @@ -119,6 +120,16 @@ static u8 nvmet_auth_reply(struct nvmet_req *req, void *d)
> __func__, ctrl->cntlid, req->sq->qid,
> data->hl, data->cvalid, dhvlen);
>
> + /* Confirm the transferred length actually contains the
> + * rval payload the message body advertises. The host
> + * response is hl bytes; with cvalid set, hl more bytes
> + * of challenge follow; with dhvlen set, dhvlen more
> + * bytes of DH value follow.
> + */
> + if (tl < sizeof(*data) + data->hl +
> + (data->cvalid ? data->hl : 0) + dhvlen)
> + return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
> +
I think the fix should change the ternary condition from data->cvalid to
(data->cvalid || dhvlen):
if (tl < sizeof(*data) + data->hl +
((data->cvalid || dhvlen) ? data->hl : 0) + dhvlen)
return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
But this is a bit of an eye-sore, so let's make this easier to read by
lifting the ternary computation outside the 'if' section and store the
result in a temporary variable.
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: nvmet: pre-auth heap OOB read in DH-HMAC-CHAP authentication (data->hl unchecked in nvmet_auth_reply)
2026-06-02 8:50 ` Keith Busch
@ 2026-06-02 8:56 ` Keith Busch
0 siblings, 0 replies; 5+ messages in thread
From: Keith Busch @ 2026-06-02 8:56 UTC (permalink / raw)
To: Jeremy Erazo
Cc: security, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Hannes Reinecke, Jens Axboe, linux-nvme, stable
On Tue, Jun 02, 2026 at 09:50:38AM +0100, Keith Busch wrote:
> On Mon, Jun 01, 2026 at 08:32:37PM -0700, Jeremy Erazo wrote:
> > @@ -119,6 +120,16 @@ static u8 nvmet_auth_reply(struct nvmet_req *req, void *d)
> > __func__, ctrl->cntlid, req->sq->qid,
> > data->hl, data->cvalid, dhvlen);
> >
> > + /* Confirm the transferred length actually contains the
> > + * rval payload the message body advertises. The host
> > + * response is hl bytes; with cvalid set, hl more bytes
> > + * of challenge follow; with dhvlen set, dhvlen more
> > + * bytes of DH value follow.
> > + */
> > + if (tl < sizeof(*data) + data->hl +
> > + (data->cvalid ? data->hl : 0) + dhvlen)
> > + return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
> > +
>
> I think the fix should change the ternary condition from data->cvalid to
> (data->cvalid || dhvlen):
>
> if (tl < sizeof(*data) + data->hl +
> ((data->cvalid || dhvlen) ? data->hl : 0) + dhvlen)
> return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
>
> But this is a bit of an eye-sore, so let's make this easier to read by
> lifting the ternary computation outside the 'if' section and store the
> result in a temporary variable.
Oh wait, this is also a duplicate report:
https://lore.kernel.org/linux-nvme/f4aca9b14e74a7f7f8cd9620e13cc32a6a2b7746@linux.dev/
^ permalink raw reply [flat|nested] 5+ messages in thread
* nvmet: pre-auth heap OOB read in DH-HMAC-CHAP authentication (data->hl unchecked in nvmet_auth_reply)
@ 2026-06-02 3:32 Jeremy Erazo
0 siblings, 0 replies; 5+ messages in thread
From: Jeremy Erazo @ 2026-06-02 3:32 UTC (permalink / raw)
To: security
Cc: Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
Hannes Reinecke, Keith Busch, Jens Axboe, linux-nvme, stable
Hi,
I'm reporting an out-of-bounds read in `nvmet_auth_reply()`
(`drivers/nvme/target/fabrics-cmd-auth.c`), reachable from an
unauthenticated remote attacker against any nvmet host that has
DH-HMAC-CHAP authentication enabled on a configured subsystem.
The bug is present in **mainline torvalds/master** at audit time
(2026-06-02, verified via raw.githubusercontent.com fetch). It is
also present in stable LTS 6.6.x and other branches that ship the
NVMe-oF DH-HMAC-CHAP target (the function was added with the
DH-HMAC-CHAP target feature in 6.0).
CVSS 3.1 base: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N = **7.5 (High)**.
This is filed shortly after my earlier report of an arbitrary
kernel-memory read in `nvmet_execute_disc_get_log_page` (sent today
to this list). Both are in `drivers/nvme/target/` and both are
attacker-controlled-length-meets-pointer-arithmetic class — but they
are independent bugs with independent fixes.
== Affected code (cited from torvalds/master, 2026-06-02) ==
`drivers/nvme/target/fabrics-cmd-auth.c::nvmet_execute_auth_send()`
(the AUTH_Send PDU dispatcher) does:
tl = le32_to_cpu(req->cmd->auth_send.tl); /* attacker u32 */
if (!tl) { ... goto done; }
if (!nvmet_check_transfer_len(req, tl)) return;
d = kmalloc(tl, GFP_KERNEL);
if (!d) { ... }
status = nvmet_copy_from_sgl(req, 0, d, tl);
/* ... dispatch by data->auth_id ... */
if (data->auth_id == NVME_AUTH_DHCHAP_MESSAGE_REPLY)
dhchap_status = nvmet_auth_reply(req, d);
The ONLY validation of `tl` is "non-zero" and that the SGL transfer
length matches the command's declared length. There is no check that
`tl` is large enough to contain the struct header *plus* the
payload that the message body advertises.
`nvmet_auth_reply()` then does:
struct nvmf_auth_dhchap_reply_data *data = d;
u16 dhvlen = le16_to_cpu(data->dhvlen);
u8 *response;
if (dhvlen) {
if (!ctrl->dh_tfm) ...
if (nvmet_auth_ctrl_sesskey(req, data->rval + 2 * data->hl, /* OOB#3 */
dhvlen) < 0) ...
}
response = kmalloc(data->hl, GFP_KERNEL);
...
if (nvmet_auth_host_hash(req, response, data->hl) < 0) ...
if (memcmp(data->rval, response, data->hl)) /* OOB#1 */
...
if (data->cvalid) {
req->sq->dhchap_c2 = kmemdup(data->rval + data->hl, data->hl, /* OOB#2 */
GFP_KERNEL);
...
}
Three call sites use `data->hl` (an attacker-controlled u8, range
0-255 from the wire) and `data->dhvlen` (an attacker-controlled
__le16, range 0-65535) as offsets into / lengths reading from
`data->rval` without any prior check that the PDU transfer length
contained the corresponding bytes.
Supporting struct (`include/linux/nvme.h:1712`):
struct nvmf_auth_dhchap_reply_data {
__u8 auth_type;
__u8 auth_id;
__le16 rsvd1;
__le16 t_id;
__u8 hl; /* attacker u8 */
__u8 rsvd2;
__u8 cvalid;
__u8 rsvd3;
__le16 dhvlen; /* attacker __le16 */
__le32 seqnum;
/* 'hl' bytes of response data */
__u8 rval[];
/* followed by 'hl' bytes of Challenge value */
/* followed by 'dhvlen' bytes of DH value */
};
`sizeof(struct nvmf_auth_dhchap_reply_data)` = 16 bytes (header only).
== Attack flow ==
1. Attacker opens TCP/4420 to a nvmet host that has DH-HMAC-CHAP
configured on at least one subsystem.
2. Sends NVMe-TCP ICReq, receives ICResp (transport handshake).
3. Sends NVMe-Fabrics Connect with `subsysnqn = <target subsys with
CHAP>`, any `hostnqn`. (Connect succeeds; the controller now
expects the host to drive the CHAP exchange.)
4. Sends AUTH_Send with `auth_id = MESSAGE_NEGOTIATE`, advertising
any supported hash (e.g., SHA-256).
5. AUTH_Receive — controller sends CHALLENGE.
6. Sends a malicious AUTH_Send with:
auth_type = NVME_AUTH_DHCHAP_MESSAGES (1)
auth_id = NVME_AUTH_DHCHAP_MESSAGE_REPLY (2)
tl = 16 (sizeof(struct nvmf_auth_dhchap_reply_data) only;
no rval[] payload)
data->hl = 0xff
data->cvalid = 1
data->dhvlen = 0
7. Kernel:
- kmalloc(16) returns a kmalloc-16 slab object (SLUB rounds up).
- copy_from_sgl writes the 16-byte attacker header into it.
- data = d; data->rval = d + 16 = past the allocation.
- memcmp(data->rval, response, 255) reads 255 bytes starting at
offset 16 of the kmalloc-16 slab object — directly into the
adjacent slab object.
- If data->cvalid is set, kmemdup(data->rval + 255, 255) reads
an additional 510 bytes past the allocation and copies 255 of
them into a new kernel allocation (which the attacker can
later exfil via further wire messages if the CHAP exchange
continues, e.g., via AUTH_Receive's payload).
== KASAN catch signature (expected) ==
Under KASAN this produces a slab-out-of-bounds READ report tied to
`memcmp` / `kmemdup` called from `nvmet_auth_reply`:
BUG: KASAN: slab-out-of-bounds in memcmp+0x... (or __asan_memcmp)
Read of size 255 at addr ffff... by task kworker/...
Call Trace:
memcmp
nvmet_auth_reply
nvmet_execute_auth_send
nvmet_tcp_io_work
...
I've prepared an in-kernel proof module
(`nvmet-auth-oob-proof.c`) that replicates the primitive against a
deliberately-undersized buffer to make the KASAN signature explicit;
it's a one-shot module that builds against any current 6.x kernel
tree. Available on request — withheld from this initial mail to keep
disclosure surface minimal.
A userspace network reproducer (Python NVMe-TCP client driving the
CHAP state machine through the malicious AUTH_Send) is in progress
and will follow.
== Fix proposal ==
Validate the PDU transfer length covers the struct header *plus* the
hl- and dhvlen-derived payload before any pointer arithmetic on
data->rval. The minimal fix sits at the entry to nvmet_auth_reply:
--- a/drivers/nvme/target/fabrics-cmd-auth.c
+++ b/drivers/nvme/target/fabrics-cmd-auth.c
@@ -112,6 +112,7 @@ static u8 nvmet_auth_reply(struct nvmet_req *req, void *d)
{
struct nvmet_ctrl *ctrl = req->sq->ctrl;
struct nvmf_auth_dhchap_reply_data *data = d;
+ u32 tl = le32_to_cpu(req->cmd->auth_send.tl);
u16 dhvlen = le16_to_cpu(data->dhvlen);
u8 *response;
@@ -119,6 +120,16 @@ static u8 nvmet_auth_reply(struct nvmet_req *req, void *d)
__func__, ctrl->cntlid, req->sq->qid,
data->hl, data->cvalid, dhvlen);
+ /* Confirm the transferred length actually contains the
+ * rval payload the message body advertises. The host
+ * response is hl bytes; with cvalid set, hl more bytes
+ * of challenge follow; with dhvlen set, dhvlen more
+ * bytes of DH value follow.
+ */
+ if (tl < sizeof(*data) + data->hl +
+ (data->cvalid ? data->hl : 0) + dhvlen)
+ return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
+
if (dhvlen) {
if (!ctrl->dh_tfm)
return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
The same shape applies to `nvmet_auth_negotiate` and any other
auth-state handler that reads variable-length fields from the
attacker buffer. A defence-in-depth alternative is to do this length
validation once inside `nvmet_execute_auth_send` before dispatching,
since the handler-specific math (hl, dhvlen, etc.) varies per
message type.
== Affected branches ==
Confirmed vulnerable: mainline torvalds/master at 2026-06-02
(verified via raw.githubusercontent.com fetch).
Probable also vulnerable: linux-stable 6.6.x, 6.1.x (where the
DH-HMAC-CHAP target was backported), and distros tracking those
(Debian/Ubuntu/RHEL/SUSE).
NOT vulnerable: any kernel without `CONFIG_NVME_TARGET_AUTH=y` (the
auth subsystem isn't compiled in).
== Threat model ==
This is reachable pre-final-authentication: the attacker has
completed Fabrics Connect (which establishes the controller binding)
but has not yet completed the CHAP handshake. CHAP is exactly what
this code is supposed to enforce; the bug is in the CHAP enforcement
itself. The kernel cannot rely on CHAP being effective when the CHAP
handler can be tricked into reading past its input buffer before any
secret is verified.
Network reachability is "any host that can open TCP/4420 to the
nvmet target". In production NVMe-oF deployments this is the same
exposure surface that DH-HMAC-CHAP exists to protect — i.e., the
mitigation is the bug.
== Researcher / Credit ==
Jeremy Erazo (trexnegr0)
mendozayt13@gmail.com
Signed-off-by: Jeremy Erazo <mendozayt13@gmail.com>
== Disclosure preferences ==
I'm happy with any reasonable embargo length (14-30 days). I have
not shared this finding with any third party. Please coordinate CVE
assignment with the kernel.org CNA.
This is the second nvmet finding I'm reporting today; both are
independent bugs but they neighbour each other in the same subsystem
and one combined backport batch on the stable side might be the
cleanest disposition. Happy to coordinate that with whichever route
your team prefers.
Thanks for your time.
— Jeremy
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-02 8:57 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-02 3:32 nvmet: pre-auth heap OOB read in DH-HMAC-CHAP authentication (data->hl unchecked in nvmet_auth_reply) Jeremy Erazo
2026-06-02 6:23 ` Greg KH
2026-06-02 8:50 ` Keith Busch
2026-06-02 8:56 ` Keith Busch
-- strict thread matches above, loose matches on Subject: below --
2026-06-02 3:32 Jeremy Erazo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox