[PATCH 2/2] nvmet-auth: store the DH-CHAP key offset instead of hardcoding it
shao.mingyin at zte.com.cn
shao.mingyin at zte.com.cn
Mon Nov 9 06:59:21 PST 2026
From: Shao Mingyin <shao.mingyin at zte.com.cn>
nvmet_auth_set_key() accepts variable-width hash identifiers, but
nvmet_setup_auth() always skips ten bytes before extracting the key.
For "DHHC-1:1:" this starts one byte past the allocated string's NUL
terminator, causing an out-of-bounds read in nvme_auth_extract_key().
Other nonstandard prefix widths also select the wrong key bytes.
Use %n to validate the complete prefix and record its actual length
for both host and controller secrets. Keep the offsets as int, matching
the scan result, so whitespace or leading zeroes in the hash identifier
do not truncate the saved offset.
Fixes: db1312dd9548 ("nvmet: implement basic In-Band Authentication")
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, KASAN) with host and
target DH-CHAP enabled.
Configuring the same 9-byte secret for the host entry on the target and
connecting makes nvmet_setup_auth() read past the kstrdup'ed string:
unpatched patched
KASAN slab-out-of-bounds in malformed key rejected,
strlen/strrchr, nvmet_setup_auth connect fails cleanly
diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c
index 574025730834..e0fc257ab90d 100644
--- a/drivers/nvme/target/auth.c
+++ b/drivers/nvme/target/auth.c
@@ -24,20 +24,24 @@ int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
{
unsigned char key_hash;
char *dhchap_secret;
+ int offset = 0;
if (!strlen(secret)) {
if (set_ctrl) {
kfree(host->dhchap_ctrl_secret);
host->dhchap_ctrl_secret = NULL;
host->dhchap_ctrl_key_hash = 0;
+ host->dhchap_ctrl_key_offset = 0;
} else {
kfree(host->dhchap_secret);
host->dhchap_secret = NULL;
host->dhchap_key_hash = 0;
+ host->dhchap_key_offset = 0;
}
return 0;
}
- if (sscanf(secret, "DHHC-1:%hhd:%*s", &key_hash) != 1)
+ if (sscanf(secret, "DHHC-1:%hhd:%n", &key_hash, &offset) != 1 ||
+ !offset)
return -EINVAL;
if (key_hash > 3) {
pr_warn("Invalid DH-HMAC-CHAP hash id %d\n",
@@ -52,10 +56,12 @@ int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
kfree(host->dhchap_ctrl_secret);
host->dhchap_ctrl_secret = strim(dhchap_secret);
host->dhchap_ctrl_key_hash = key_hash;
+ host->dhchap_ctrl_key_offset = offset;
} else {
kfree(host->dhchap_secret);
host->dhchap_secret = strim(dhchap_secret);
host->dhchap_key_hash = key_hash;
+ host->dhchap_key_offset = offset;
}
up_write(&nvmet_config_sem);
return 0;
@@ -135,6 +141,7 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset)
int ret = 0;
struct nvmet_host_link *p;
struct nvmet_host *host = NULL;
+ const u8 *key;
down_read(&nvmet_config_sem);
if (nvmet_is_disc_subsys(ctrl->subsys))
@@ -181,8 +188,8 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset)
/* Skip the 'DHHC-1:XX:' prefix */
nvme_auth_free_key(ctrl->host_key);
- ctrl->host_key = nvme_auth_extract_key(host->dhchap_secret + 10,
- host->dhchap_key_hash);
+ key = host->dhchap_secret + host->dhchap_key_offset;
+ ctrl->host_key = nvme_auth_extract_key(key, host->dhchap_key_hash);
if (IS_ERR(ctrl->host_key)) {
ret = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE;
ctrl->host_key = NULL;
@@ -200,8 +207,8 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset)
goto out_unlock;
}
- ctrl->ctrl_key = nvme_auth_extract_key(host->dhchap_ctrl_secret + 10,
- host->dhchap_ctrl_key_hash);
+ key = host->dhchap_ctrl_secret + host->dhchap_ctrl_key_offset;
+ ctrl->ctrl_key = nvme_auth_extract_key(key, host->dhchap_ctrl_key_hash);
if (IS_ERR(ctrl->ctrl_key)) {
ret = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE;
ctrl->ctrl_key = NULL;
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index d7804bf91aaa..6a17cd9ee0a9 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -400,6 +400,8 @@ struct nvmet_host {
struct config_group group;
u8 *dhchap_secret;
u8 *dhchap_ctrl_secret;
+ int dhchap_key_offset;
+ int dhchap_ctrl_key_offset;
u8 dhchap_key_hash;
u8 dhchap_ctrl_key_hash;
u8 dhchap_hash_id;
More information about the Linux-nvme
mailing list