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@vger.kernel.org Signed-off-by: Yehyeong Lee --- 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