In the driver code for the MV‑based queue variant (struct hpt_iopmu_mv of the hptiop driver), the field "inbound_head" is read from the hardware register and used as an index into the array "inbound_q[MVIOP_QUEUE_LEN]". For example:
u32 inbound_head = readl(&hba->u.mv.mu->inbound_head); /* ... */ memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8);
The code then increments head and wraps it to zero when it equals MVIOP_QUEUE_LEN. However, the driver does *not* check that the initial value of "inbound_head" is strictly less than "MVIOP_QUEUE_LEN". If the hardware (or attacker‑controlled firmware/hardware device) writes a malicious value into the inbound_head register (which could be ≥ MVIOP_QUEUE_LEN), then subsequent "memcpy_toio" will write past the end of "inbound_q", leading to an out‑of‑bounds write condition.
Since inbound_q is allocated with exactly MVIOP_QUEUE_LEN entries (see:
__le64 inbound_q[MVIOP_QUEUE_LEN]; /* MVIOP_QUEUE_LEN == 512 */
), indexing at e.g. "inbound_head == 512" or greater results in undefined memory access and potential corruption of adjacent fields or memory regions.
This issue is particularly concerning in scenarios where an attacker has control or influence over the hardware/firmware on the adapter card (for example a malicious or compromised controller), because they could deliberately set "inbound_head" to a value outside the expected [0, MVIOP_QUEUE_LEN‑1] range, thus forcing the driver to write arbitrary data beyond the queue bounds.
To mitigate this issue, we add a check to validate the value of "inbound_head" before it is used as an index. If "inbound_head" is found to be out of bounds (≥ MVIOP_QUEUE_LEN), the head will be reset to 0, and "head" will be set to 1 to ensure that a valid entry is written to the queue. The resetting of "inbound_head" to 0 ensures that the queue processing can continue safely and predictably, while the adjustment of "head = 1" ensures that the next valid index is used for subsequent writes.
This prevents any out-of-bounds writes and ensures that the queue continues to operate safely even if the hardware is compromised.
Fixes: 00f5970193e22 ("[SCSI] hptiop: add more adapter models and other fixes") Cc: stable@vger.kernel.org Signed-off-by: Guangshuo Li lgs201920130244@gmail.com --- drivers/scsi/hptiop.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index c01370893a81..a1a3840e6ea8 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -166,6 +166,14 @@ static void mv_inbound_write(u64 p, struct hptiop_hba *hba) if (head == MVIOP_QUEUE_LEN) head = 0;
+ if (inbound_head >= MVIOP_QUEUE_LEN) { + dev_err(&hba->pdev->dev, + "hptiop: inbound_head out of range (%u)\n", + inbound_head); + inbound_head = 0; + head = 1; + } + memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8); writel(head, &hba->u.mv.mu->inbound_head); writel(MVIOP_MU_INBOUND_INT_POSTQUEUE,
linux-stable-mirror@lists.linaro.org