[PATCH v3 1/3] scsi: arcmsr: bound the firmware-supplied message length
From: Yehyeong Lee
Date: Mon Oct 12 2026 - 07:41:57 EST
The adapter hands the driver an inbound message through a fixed
128-byte window:
struct QBUFFER {
uint32_t data_len;
uint8_t data[124];
};
arcmsr_Read_iop_rqbuffer_in_DWORD() takes data_len from that window and
uses it as the copy length without comparing it against the window:
iop_len = readl(&prbuffer->data_len);
if (iop_len > 0) {
buf1 = kmalloc(128, GFP_ATOMIC);
...
data_len = iop_len;
while (data_len >= 4) {
*buf2++ = readl(iop_data);
iop_data++;
data_len -= 4;
}
A data_len above 128 therefore walks the 128-byte allocation, writing
firmware-supplied data past its end, and the loop that follows reads the
same overrun back out of buf1. arcmsr_Read_iop_rqbuffer_data() has the
same unchecked loop for adapter types A and B; there the destination is
wrapped to ARCMSR_MAX_QBUFFER so nothing is written out of bounds, but
the loop still spins up to 2^32 times with rqbuffer_lock held.
Two of the three callers place no bound on the value at all:
arcmsr_iop_message_xfer() for ARCMSR_MESSAGE_READ_RQBUFFER and
arcmsr_sysfs_iop_message_read() both call straight into the reader on
ACB_F_IOPDATA_OVERFLOW. The third, arcmsr_iop2drv_data_wrote_handle(),
compares data_len against the free space in acb->rqbuffer, which is up
to ARCMSR_MAX_QBUFFER - 1 and so still far larger than the 128-byte
staging buffer; it also reads data_len separately from the reader, so
the adapter can change it between the two reads.
Clamp the length to the size of the window in both readers. A
conforming adapter never reports more than sizeof(prbuffer->data), so
this does not drop any data it sends.
With a KASAN build and a crafted window, data_len = 4096 produces 992
out-of-bounds 4-byte writes (1024 dwords less the 32 that fit) in
arcmsr_Read_iop_rqbuffer_in_DWORD():
BUG: KASAN: slab-out-of-bounds in arcmsr_Read_iop_rqbuffer_in_DWORD+0x240/0x2a0 [arcmsr]
Write of size 4 at addr ffff88800b5baf80 by task init/1
Call Trace:
<TASK>
dump_stack_lvl+0x66/0xa0
print_report+0xd0/0x630
kasan_report+0xe4/0x120
arcmsr_Read_iop_rqbuffer_in_DWORD+0x240/0x2a0 [arcmsr]
</TASK>
Allocated by task 1:
__kasan_kmalloc+0x8f/0xa0
__kmalloc_cache_noprof+0x22c/0x570
arcmsr_Read_iop_rqbuffer_in_DWORD+0x7b/0x2a0 [arcmsr]
The buggy address belongs to the object at ffff88800b5baf00
which belongs to the cache kmalloc-128 of size 128
The buggy address is located 0 bytes to the right of
The first value that overruns is data_len = 129; 128 and below are
reported clean, and 124 (the window) and 120 copy byte-for-byte
identically with and without the clamp.
Fixes: bb263c4ecbb1 ("arcmsr: fix ioctl data read/write error for adapter type C")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yehyeong Lee <yhlee@xxxxxxxxxxxxxxxxxx>
---
drivers/scsi/arcmsr/arcmsr_hba.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 8aa948f06cacf..255f1d898079f 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -2277,6 +2277,8 @@ arcmsr_Read_iop_rqbuffer_in_DWORD(struct AdapterControlBlock *acb,
iop_data = (uint32_t __iomem *)prbuffer->data;
iop_len = readl(&prbuffer->data_len);
+ if (iop_len > sizeof(prbuffer->data))
+ iop_len = sizeof(prbuffer->data);
if (iop_len > 0) {
buf1 = kmalloc(128, GFP_ATOMIC);
buf2 = (uint32_t *)buf1;
@@ -2319,6 +2321,8 @@ arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb,
return arcmsr_Read_iop_rqbuffer_in_DWORD(acb, prbuffer);
iop_data = (uint8_t __iomem *)prbuffer->data;
iop_len = readl(&prbuffer->data_len);
+ if (iop_len > sizeof(prbuffer->data))
+ iop_len = sizeof(prbuffer->data);
while (iop_len > 0) {
pQbuffer = &acb->rqbuffer[acb->rqbuf_putIndex];
*pQbuffer = readb(iop_data);
--
2.43.0