DF-2492 / fix.diff
diff --git a/sys/dev/disk/nata/ata-pci.c b/sys/dev/disk/nata/ata-pci.c --- a/sys/dev/disk/nata/ata-pci.c +++ b/sys/dev/disk/nata/ata-pci.c @@ -380,6 +380,13 @@ struct ata_pci_controller *controller = device_get_softc(dev); int unit = ((struct ata_channel *)device_get_softc(child))->unit; + /* interrupt[] is a fixed 8-entry array (ata-pci.h); reject channel + * units outside it instead of writing OOB. AHCI-class controllers can + * advertise up to 32 channels, which would otherwise corrupt adjacent + * heap. See DF-2492 / DF-2510. */ + if (unit < 0 || unit >= NELEM(controller->interrupt)) + return EINVAL; + controller->interrupt[unit].function = function; controller->interrupt[unit].argument = argument; *cookiep = controller; @@ -400,6 +407,9 @@ struct ata_pci_controller *controller = device_get_softc(dev); int unit = ((struct ata_channel *)device_get_softc(child))->unit; + if (unit < 0 || unit >= NELEM(controller->interrupt)) + return EINVAL; + controller->interrupt[unit].function = NULL; controller->interrupt[unit].argument = NULL; return 0; @@ -579,9 +589,15 @@ { struct ata_pci_controller *ctlr = data; struct ata_channel *ch; - int unit; + int unit, maxunit; - for (unit = 0; unit < ctlr->channels; unit++) { + /* interrupt[] is a fixed 8-entry array; never iterate past it even if + * ctlr->channels (set from hardware CAP/PI on AHCI, up to 32) exceeds + * it, to avoid an OOB read of wild function pointers. See DF-2492. */ + maxunit = NELEM(ctlr->interrupt); + if (ctlr->channels < maxunit) + maxunit = ctlr->channels; + for (unit = 0; unit < maxunit; unit++) { if ((ch = ctlr->interrupt[unit].argument)) ctlr->interrupt[unit].function(ch); } |