mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-22 09:34:56 +02:00
nvmet-auth: validate reply message payload bounds against transfer length
[ Upstream commit3a413ece25] nvmet_auth_reply() accesses the variable-length rval[] array using attacker-controlled hl (hash length) and dhvlen (DH value length) fields without verifying they fit within the allocated buffer of tl bytes. A malicious NVMe-oF initiator can craft a DHCHAP_REPLY message with a small transfer length but large hl/dhvlen values, causing out-of-bounds heap reads when the target processes the DH public key (rval + 2*hl) or performs the host response memcmp. With DH authentication configured, the OOB pointer is passed directly to sg_init_one() and read by crypto_kpp_compute_shared_secret(), reaching up to 526 bytes past the buffer. This is exploitable pre-authentication. Add bounds validation ensuring sizeof(*data) + 2*hl + dhvlen <= tl before any access to the variable-length fields. Discovered by Atuin - Automated Vulnerability Discovery Engine. Fixes:db1312dd95("nvmet: implement basic In-Band Authentication") Cc: stable@vger.kernel.org Reviewed-by: Hannes Reinecke <hare@kernel.org> Signed-off-by: Tianchu Chen <flynnnchen@tencent.com> Signed-off-by: Keith Busch <kbusch@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
824425c422
commit
80cd28b56a
@@ -109,13 +109,22 @@ static u8 nvmet_auth_negotiate(struct nvmet_req *req, void *d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 nvmet_auth_reply(struct nvmet_req *req, void *d)
|
||||
static u8 nvmet_auth_reply(struct nvmet_req *req, void *d, u32 tl)
|
||||
{
|
||||
struct nvmet_ctrl *ctrl = req->sq->ctrl;
|
||||
struct nvmf_auth_dhchap_reply_data *data = d;
|
||||
u16 dhvlen = le16_to_cpu(data->dhvlen);
|
||||
u16 dhvlen;
|
||||
u8 *response;
|
||||
|
||||
if (tl < sizeof(*data))
|
||||
return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
|
||||
|
||||
dhvlen = le16_to_cpu(data->dhvlen);
|
||||
|
||||
/* Validate that hl and dhvlen fit within the transfer length */
|
||||
if (sizeof(*data) + 2 * (size_t)data->hl + dhvlen > tl)
|
||||
return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
|
||||
|
||||
pr_debug("%s: ctrl %d qid %d: data hl %d cvalid %d dhvlen %u\n",
|
||||
__func__, ctrl->cntlid, req->sq->qid,
|
||||
data->hl, data->cvalid, dhvlen);
|
||||
@@ -287,7 +296,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req)
|
||||
|
||||
switch (data->auth_id) {
|
||||
case NVME_AUTH_DHCHAP_MESSAGE_REPLY:
|
||||
dhchap_status = nvmet_auth_reply(req, d);
|
||||
dhchap_status = nvmet_auth_reply(req, d, tl);
|
||||
if (dhchap_status == 0)
|
||||
req->sq->dhchap_step =
|
||||
NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1;
|
||||
|
||||
Reference in New Issue
Block a user