[PATCH 2/3] scsi: aic94xx: validate the EDB index in asd_get_response_tasklet()
From: Yehyeong Lee
Date: Thu Oct 15 2026 - 03:28:55 EST
asd_get_response_tasklet() takes the empty data buffer index out of the
done list status block the sequencer wrote, with the same arithmetic
escb_tasklet_complete() uses on its own copy:
int edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
The extracted field is three bits, so the subtraction yields -1 through
6, and the function indexes seq->edb_arr[] with it without looking:
edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
r = edb->vaddr;
asd_assign_edbs2escbs() gives the first ESCB edb_index 0, so for that one
edb_id == -1 reads seq->edb_arr[-1], one pointer before the kmalloc'd
array, and the next line dereferences it. asd_invalidate_edb() at the end
of the function would index escb->eb[] and seq->edb_arr[] with the same
value.
Reject an index outside [0, ASD_EDBS_PER_SCB) and return, the way the
lookup failure just above it already returns. That check stays as it is;
this is about the other value taken from the same status block.
The preceding patch added the missing return to the check
escb_tasklet_complete() already had. This is that check in a function
that never had one. It is written against ASD_EDBS_PER_SCB rather than
the literal 6 that function uses, because the constant is what sizes
escb->eb[] and, through asd_assign_edbs2escbs(), the stride within
seq->edb_arr[]; the existing condition is left alone.
Whether the sequencer can really report zero in that field is not
something the tree answers. It is firmware loaded with
request_firmware(), status_block[] is an opaque four bytes in
aic94xx_sas.h whose layout is described only by a struct declared locally
in this function and again in aic94xx_tmf.c, and there is no
Documentation/ file or MAINTAINERS entry for this driver. This is not a
claim of a reachable out-of-bounds access. It makes the driver consistent
with itself: asd_bytes_dmaed_tasklet() in aic94xx_scb.c clamps a
device-supplied length,
size = min(size, (u16) sizeof(phy->frame_rcvd));
a few lines after indexing seq->edb_arr[] with a device-supplied
index and no bound of its own.
As with the preceding patch, a response dropped here leaves its ESCB
uninvalidated and so not reposted, since the repost happens inside
asd_invalidate_edb(). The alternative is to index the array with a value
the driver cannot place.
Fixes: 2908d778ab3e ("[SCSI] aic94xx: new driver")
Signed-off-by: Yehyeong Lee <yhlee@xxxxxxxxxxxxxxxxxx>
---
drivers/scsi/aic94xx/aic94xx_task.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index b26a468ddc981..35cf61f541d1b 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -169,6 +169,12 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
return;
}
+ if (edb_id < 0 || edb_id >= ASD_EDBS_PER_SCB) {
+ ASD_DPRINTK("edb_id is %d! resp_sb->flags is 0x%x\n",
+ edb_id, resp_sb->flags);
+ return;
+ }
+
ts->buf_valid_size = 0;
edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
r = edb->vaddr;
--
2.43.0