[PATCH v2 3/3] scsi: arcmsr: wrap the type B completion index before using it
From: Yehyeong Lee
Date: Mon Oct 12 2026 - 05:09:44 EST
struct MessageUnit_B lives in the dma_alloc_coherent() area shared with
the adapter, and holds the completion ring next to the index into it:
uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
uint32_t postq_index;
uint32_t doneq_index;
arcmsr_hbaB_postqueue_isr() takes doneq_index from there and subscripts
done_qbuffer[] with it, and only afterwards reduces it:
index = reg->doneq_index;
while ((flag_ccb = reg->done_qbuffer[index]) != 0) {
...
reg->done_qbuffer[index] = 0;
index++;
index %= ARCMSR_MAX_HBB_POSTQUEUE;
reg->doneq_index = index;
}
So the first iteration uses the value as it was found, unmasked. An
index beyond ARCMSR_MAX_HBB_POSTQUEUE (264) reads past done_qbuffer[]
and, should the word it finds be non-zero, stores a zero there as well.
arcmsr_hbaB_polling_ccbdone() has the same ordering.
Reduce the index where it is read instead, which leaves the rest of the
loop unchanged.
Measured with a KASAN build. struct MessageUnit_B is 2176 bytes with
done_qbuffer at offset 1056, so a reported index of 600 reads 3456 bytes
in:
BUG: KASAN: slab-out-of-bounds in arcmsr_hbaB_postqueue_isr+0x1f5/0x270 [arcmsr]
Read of size 4 at addr ffff88800c08cd80 by task init/1
...
which belongs to the cache kmalloc-4k of size 4096
The buggy address is located 1280 bytes to the right of
Fixes: 1c57e86d75cf ("[SCSI] arcmsr: initial driver, version 1.20.00.13")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yehyeong Lee <yhlee@xxxxxxxxxxxxxxxxxx>
---
drivers/scsi/arcmsr/arcmsr_hba.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 9519715883b5a..c2c62ad6c6502 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -2568,7 +2568,7 @@ static void arcmsr_hbaB_postqueue_isr(struct AdapterControlBlock *acb)
bool error;
unsigned long cdb_phy_addr;
- index = reg->doneq_index;
+ index = reg->doneq_index % ARCMSR_MAX_HBB_POSTQUEUE;
while ((flag_ccb = reg->done_qbuffer[index]) != 0) {
cdb_phy_addr = (flag_ccb << 5) & 0xffffffff;
if (acb->cdb_phyadd_hipart)
@@ -3669,7 +3669,7 @@ static int arcmsr_hbaB_polling_ccbdone(struct AdapterControlBlock *acb,
/* clear doorbell interrupt */
writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
while(1){
- index = reg->doneq_index;
+ index = reg->doneq_index % ARCMSR_MAX_HBB_POSTQUEUE;
flag_ccb = reg->done_qbuffer[index];
if (flag_ccb == 0) {
if (poll_ccb_done){
--
2.43.0