From 5c279fcabb0ea7ba61881c13027b15d8054b8abd Mon Sep 17 00:00:00 2001 From: Guixin Liu Date: Wed, 28 Oct 2026 16:55:51 +0800 Subject: [PATCH] nvmet: Free the old negotiation state when restarting authentication Restarting a DH-HMAC-CHAP negotiation with SEND(NEGOTIATE) resets sq->dhchap_step but does not release the previous c1/c2/skey, which are only freed in nvmet_auth_sq_free() at teardown. The next CHALLENGE/REPLY exchange then overwrites those pointers with fresh allocations. An unauthenticated host can repeat the negotiate message endlessly, leaking a few dozen bytes per round and slowly exhausting target memory. Clear the old negotiation state with nvmet_auth_sq_free() before setting up the new one. Also reset dhchap_skey_len to zero: if a DH session key was already established, a following round with dhvlen=0 would otherwise pass a NULL skey with a stale non-zero length to the HMAC code and dereference it. Fixes: db1312dd95488 ("nvmet: implement basic In-Band Authentication") Cc: stable@vger.kernel.org Reviewed-by: Christoph Hellwig Signed-off-by: Guixin Liu Signed-off-by: Keith Busch --- drivers/nvme/target/auth.c | 1 + drivers/nvme/target/fabrics-cmd-auth.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c index 1680e5e6839c..574025730834 100644 --- a/drivers/nvme/target/auth.c +++ b/drivers/nvme/target/auth.c @@ -237,6 +237,7 @@ void nvmet_auth_sq_free(struct nvmet_sq *sq) sq->dhchap_c2 = NULL; kfree(sq->dhchap_skey); sq->dhchap_skey = NULL; + sq->dhchap_skey_len = 0; } void nvmet_auth_sq_destroy(struct nvmet_sq *sq) diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c index bc49b48cdd63..3d9840d37a8b 100644 --- a/drivers/nvme/target/fabrics-cmd-auth.c +++ b/drivers/nvme/target/fabrics-cmd-auth.c @@ -330,6 +330,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req) /* Restart negotiation */ pr_debug("%s: ctrl %d qid %d reset negotiation\n", __func__, ctrl->cntlid, req->sq->qid); + nvmet_auth_sq_free(req->sq); if (!req->sq->qid) { dhchap_status = nvmet_setup_auth(ctrl, req->sq, true);