diff --git a/sys/dev/disk/advansys/advlib.c b/sys/dev/disk/advansys/advlib.c --- a/sys/dev/disk/advansys/advlib.c +++ b/sys/dev/disk/advansys/advlib.c @@ -1004,6 +1004,16 @@ */ cinfo_index = adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); + /* cinfo_index is a 32-bit value read from RISC LRAM (firmware- + * shared memory); validate it against the ccb_infos[] allocation + * (max_openings entries) before indexing, or a firmware bug / + * malicious device can drive an OOB read of adv->ccb_infos. + * See DF-2414. */ + if (cinfo_index >= adv->max_openings) { + device_printf(adv->dev, + "CHK_CONDITION: bad cinfo_index %u\n", cinfo_index); + return; + } ccb = adv->ccb_infos[cinfo_index].ccb; xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); ccb->ccb_h.status |= CAM_DEV_QFRZN; @@ -1045,6 +1055,12 @@ + ADV_SCSIQ_SCSI_STATUS); cinfo_index = adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); + /* See DF-2414: validate firmware-supplied ccb index. */ + if (cinfo_index >= adv->max_openings) { + device_printf(adv->dev, + "QUEUE_FULL: bad cinfo_index %u\n", cinfo_index); + return; + } ccb = adv->ccb_infos[cinfo_index].ccb; xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR; @@ -1892,6 +1908,14 @@ cinfo_index = adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); + /* See DF-2414: validate firmware-supplied ccb index before + * indexing ccb_infos[] (and before the adv_set_syncrate(... ccb) + * below derefs it). */ + if (cinfo_index >= adv->max_openings) { + device_printf(adv->dev, + "SDTR: bad cinfo_index %u\n", cinfo_index); + return; + } ccb = adv->ccb_infos[cinfo_index].ccb; tinfo = &adv->tinfo[tid_no]; sdtr_accept = TRUE; @@ -1985,6 +2009,14 @@ q_addr = ADV_QNO_TO_QADDR(q_no); adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count); + /* scsiq->d2.ccb_index is copied from firmware LRAM and indexes + * ccb_infos[max_openings]; validate before dereferencing. + * See DF-2414. */ + if (scsiq->d2.ccb_index >= adv->max_openings) { + device_printf(adv->dev, + "abort: bad ccb_index %u\n", scsiq->d2.ccb_index); + continue; + } ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index]; if (((scsiq->q_status & QS_READY) != 0) && ((scsiq->q_status & QS_ABORTED) == 0)