From nobody Mon Dec 1 23:03:58 2025 Received: from out30-83.freemail.mail.aliyun.com (out30-83.freemail.mail.aliyun.com [115.124.30.83]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9AD2D342158 for ; Wed, 26 Nov 2025 20:27:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.83 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764188850; cv=none; b=nU4tyeay8M2oo+dPdtGOOnP0PT68Ky/+v6z6XrsmbI++muZeuDsc73jSpZmxr5Aye38snaaPnhZ1kbg1OnRKoX+ShCwHFy3pih+yaRBPKROb2EhZHRA8PrU1CzcTJGVllEIpszdtjEAbxEE3W6KtnjeJ8KSBSmeCTGPlUz9uWig= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764188850; c=relaxed/simple; bh=0KTiNl+uymw6nbZKEEtEm18zlWXqNw8+6zBo1qrdnPs=; h=Date:From:To:Subject:Message-ID:MIME-Version:Content-Type: Content-Disposition; b=LHksOtsLbRJDAxdatnJr1c6rWqtHgkpe9h6M0+NpuzgQ4E/M1/swlZxiW8gHEFojkRkKwTU6R0hewVDvD7F8osq117MieZaw0KURDzuuHpdmYbicaZEr/aaQm97oi8FLESs+17nvMPMUm7LL7PuKe9ffBbzA7sUjtq5V5IShexs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aliyun.com; spf=pass smtp.mailfrom=aliyun.com; dkim=pass (1024-bit key) header.d=aliyun.com header.i=@aliyun.com header.b=C1qDyXny; arc=none smtp.client-ip=115.124.30.83 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aliyun.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aliyun.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=aliyun.com header.i=@aliyun.com header.b="C1qDyXny" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aliyun.com; s=s1024; t=1764188846; h=Date:From:To:Subject:Message-ID:MIME-Version:Content-Type; bh=ot7woekyNWuumg2uCxzEjyg/N5dw0o6ojbbsxWfAufk=; b=C1qDyXnyqv3Vpgm3TRaggoMgUJHlxLOtGzrzQWozwJJBUwmjmTQpZQi+XOv9MHvpV/YB4tP4iSvVc7DsmCMnop9JXZcYbL6KeBMbl8Q+wvxT1j2+WOV1+YJWGzEglBJXHsWl7Y1Y44yIZI4fEjzHXIzyCMhm71BibQGr2mUKInI= Received: from aliyun.com(mailfrom:ekorenevsky@aliyun.com fp:SMTPD_---0WtU51Xe_1764188843 cluster:ay36) by smtp.aliyun-inc.com; Thu, 27 Nov 2025 04:27:25 +0800 Date: Wed, 26 Nov 2025 23:27:21 +0300 From: Eugene Korenevsky To: Keith Busch , Jens Axboe , Christoph Hellwig , Sagi Grimberg , linux-nvme@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH] nvme: nvme_identify_ns_descs: prevent oob Message-ID: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Broken or malicious controller can send invalid ns id. Out-of-band memory access may occur if remaining buffer size is less than .nidl (ns id length) field of `struct nvme_ns_id_desc` Fix this issue by making nvme_process_id_decs() function aware of remaining buffer size. Also simplify nvme_process_id_decs(): replace copy-pasted `case` branches with table lookup. Signed-off-by: Eugene Korenevsky --- drivers/nvme/host/core.c | 80 ++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index f1f719351f3f..2d1a4b9882ca 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1481,52 +1481,45 @@ static int nvme_identify_ctrl(struct nvme_ctrl *dev= , struct nvme_id_ctrl **id) return error; } =20 +struct ns_id_info { + __u8 nidl; + char *name; +}; + +#define NS_ID_INFO(nidt) \ + [nidt] =3D {nidt##_LEN, #nidt} + +static const struct ns_id_info niis[] =3D { + NS_ID_INFO(NVME_NIDT_EUI64), + NS_ID_INFO(NVME_NIDT_NGUID), + NS_ID_INFO(NVME_NIDT_UUID), + NS_ID_INFO(NVME_NIDT_CSI), +}; + static int nvme_process_ns_desc(struct nvme_ctrl *ctrl, struct nvme_ns_ids= *ids, - struct nvme_ns_id_desc *cur, bool *csi_seen) + struct nvme_ns_id_desc *cur, int remain, + bool *csi_seen) { - const char *warn_str =3D "ctrl returned bogus length:"; - void *data =3D cur; + const char *warn_fmt =3D "ctrl returned bogus ns id: %u %u %d %s"; + const struct ns_id_info *nii; =20 switch (cur->nidt) { + case NVME_NIDT_CSI: + *csi_seen =3D true; + fallthrough; case NVME_NIDT_EUI64: - if (cur->nidl !=3D NVME_NIDT_EUI64_LEN) { - dev_warn(ctrl->device, "%s %d for NVME_NIDT_EUI64\n", - warn_str, cur->nidl); - return -1; - } - if (ctrl->quirks & NVME_QUIRK_BOGUS_NID) - return NVME_NIDT_EUI64_LEN; - memcpy(ids->eui64, data + sizeof(*cur), NVME_NIDT_EUI64_LEN); - return NVME_NIDT_EUI64_LEN; case NVME_NIDT_NGUID: - if (cur->nidl !=3D NVME_NIDT_NGUID_LEN) { - dev_warn(ctrl->device, "%s %d for NVME_NIDT_NGUID\n", - warn_str, cur->nidl); - return -1; - } - if (ctrl->quirks & NVME_QUIRK_BOGUS_NID) - return NVME_NIDT_NGUID_LEN; - memcpy(ids->nguid, data + sizeof(*cur), NVME_NIDT_NGUID_LEN); - return NVME_NIDT_NGUID_LEN; case NVME_NIDT_UUID: - if (cur->nidl !=3D NVME_NIDT_UUID_LEN) { - dev_warn(ctrl->device, "%s %d for NVME_NIDT_UUID\n", - warn_str, cur->nidl); + nii =3D &niis[cur->nidt]; + if (cur->nidl !=3D nii->nidl || remain < nii->nidl) { + dev_warn(ctrl->device, warn_fmt, + cur->nidl, nii->nidl, remain, nii->name); return -1; } if (ctrl->quirks & NVME_QUIRK_BOGUS_NID) - return NVME_NIDT_UUID_LEN; - uuid_copy(&ids->uuid, data + sizeof(*cur)); - return NVME_NIDT_UUID_LEN; - case NVME_NIDT_CSI: - if (cur->nidl !=3D NVME_NIDT_CSI_LEN) { - dev_warn(ctrl->device, "%s %d for NVME_NIDT_CSI\n", - warn_str, cur->nidl); - return -1; - } - memcpy(&ids->csi, data + sizeof(*cur), NVME_NIDT_CSI_LEN); - *csi_seen =3D true; - return NVME_NIDT_CSI_LEN; + return nii->nidl; + memcpy(&ids->csi, cur + 1, nii->nidl); + return nii->nidl; default: /* Skip unknown types */ return cur->nidl; @@ -1538,7 +1531,8 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *c= trl, { struct nvme_command c =3D { }; bool csi_seen =3D false; - int status, pos, len; + int status, len, remain; + struct nvme_ns_id_desc *cur; void *data; =20 if (ctrl->vs < NVME_VS(1, 3, 0) && !nvme_multi_css(ctrl)) @@ -1563,17 +1557,21 @@ static int nvme_identify_ns_descs(struct nvme_ctrl = *ctrl, goto free_data; } =20 - for (pos =3D 0; pos < NVME_IDENTIFY_DATA_SIZE; pos +=3D len) { - struct nvme_ns_id_desc *cur =3D data + pos; - + remain =3D NVME_IDENTIFY_DATA_SIZE; + cur =3D data; + while (remain >=3D sizeof(*cur)) { if (cur->nidl =3D=3D 0) break; =20 - len =3D nvme_process_ns_desc(ctrl, &info->ids, cur, &csi_seen); + len =3D nvme_process_ns_desc(ctrl, &info->ids, + cur, remain - sizeof(*cur), + &csi_seen); if (len < 0) break; =20 len +=3D sizeof(*cur); + remain -=3D len; + cur +=3D len; } =20 if (nvme_multi_css(ctrl) && !csi_seen) { --=20 2.47.3