[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20251216060156.41320-3-qu@darknavy.com>
Date: Tue, 16 Dec 2025 14:01:55 +0800
From: Shipei Qu <qu@...knavy.com>
To: Sathya Prakash <sathya.prakash@...adcom.com>,
Sreekanth Reddy <sreekanth.reddy@...adcom.com>,
Suganath Prabu Subramani <suganath-prabu.subramani@...adcom.com>
Cc: Shipei Qu <qu@...knavy.com>,
MPT-FusionLinux.pdl@...adcom.com,
linux-scsi@...r.kernel.org,
linux-kernel@...r.kernel.org,
DARKNAVY <vr@...knavy.com>
Subject: [PATCH v2] scsi: mptbase: bounds-check req_idx in reply paths
Hi,
resending with a correctly generated diff (the previous email had a malformed
patch header). The patch content is unchanged.
In the Fusion MPT base driver, both the normal and turbo reply paths trust a
request index (req_idx) provided by the IOC and use it in MPT_INDEX_2_MFPTR()
without validating it against ioc->req_depth. A bogus index can cause the
driver to compute a request frame pointer outside the allocated req_frames pool
and pass it to protocol callbacks.
In practice, a malicious PCIe or Thunderbolt-attached device that emulates a
supported controller and returns crafted reply contexts can drive the driver
out of bounds in this way.
This affects several devices supported by mpt* drivers and the code is enabled
in distribution kernels such as Ubuntu. The same pattern is present in current
mainline kernels.
This issue was first reported through security@...nel.org. The kernel security
team considered it a normal robustness bug (controllers are assumed to be
trusted from the host's point of view) and asked us to send fixes to the
relevant development lists. The patch below adds simple bounds checks before
converting req_idx into a frame pointer.
Reported-by: DARKNAVY (@DarkNavyOrg) <vr@...knavy.com>
Signed-off-by: Shipei Qu <qu@...knavy.com>
---
drivers/message/fusion/mptbase.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index e60a8d394..58df10fb1 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -453,6 +453,12 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
req_idx = pa & 0x0000FFFF;
+ if (req_idx >= ioc->req_depth) {
+ printk(MYIOC_s_WARN_FMT
+ "TURBO reply: req_idx %u out of range (depth %u)\n",
+ ioc->name, req_idx, ioc->req_depth);
+ return;
+ }
cb_idx = (pa & 0x00FF0000) >> 16;
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
break;
@@ -469,6 +475,12 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
*/
if ((pa & 0x58000000) == 0x58000000) {
req_idx = pa & 0x0000FFFF;
+ if (req_idx >= ioc->req_depth) {
+ printk(MYIOC_s_WARN_FMT
+ "LAN TURBO reply: req_idx %u out of range (depth %u)\n",
+ ioc->name, req_idx, ioc->req_depth);
+ return;
+ }
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
mpt_free_msg_frame(ioc, mf);
mb();
@@ -527,6 +539,13 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
+ if (req_idx >= ioc->req_depth) {
+ printk(MYIOC_s_WARN_FMT
+ "reply: req_idx %u out of range (depth %u)\n",
+ ioc->name, req_idx, ioc->req_depth);
+ freeme = 0;
+ goto out;
+ }
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
--
2.45.1
Powered by blists - more mailing lists