diff options
author | Aaro Koskinen <aaro.koskinen@iki.fi> | 2011-12-05 22:10:40 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-12-08 20:26:06 (GMT) |
commit | 08ce239c106f1d147820f419e3dde86422663e7f (patch) | |
tree | f9bf0d4027ba680cb5761966ffa79194ae74bb11 /drivers | |
parent | 82986dd9e738996a9d2e508c164d1eb7464c07c6 (diff) | |
download | linux-08ce239c106f1d147820f419e3dde86422663e7f.tar.xz |
staging: xgifb: ReadVBIOSTablData(): check the BIOS size
Check the BIOS size to avoid out of bounds array access. Disable LVDS
in case errors are detected.
Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/xgifb/vb_init.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c index b438394..96e2334 100644 --- a/drivers/staging/xgifb/vb_init.c +++ b/drivers/staging/xgifb/vb_init.c @@ -1093,13 +1093,12 @@ static void XGINew_SetDRAMSize_340(struct xgi_hw_device_info *HwDeviceExtension, xgifb_reg_set(pVBInfo->P3c4, 0x21, (unsigned short) (data | 0x20)); } -static u8 *xgifb_copy_rom(struct pci_dev *dev) +static u8 *xgifb_copy_rom(struct pci_dev *dev, size_t *rom_size) { void __iomem *rom_address; u8 *rom_copy; - size_t rom_size; - rom_address = pci_map_rom(dev, &rom_size); + rom_address = pci_map_rom(dev, rom_size); if (rom_address == NULL) return NULL; @@ -1107,8 +1106,8 @@ static u8 *xgifb_copy_rom(struct pci_dev *dev) if (rom_copy == NULL) goto done; - rom_size = min_t(size_t, rom_size, XGIFB_ROM_SIZE); - memcpy_fromio(rom_copy, rom_address, rom_size); + *rom_size = min_t(size_t, *rom_size, XGIFB_ROM_SIZE); + memcpy_fromio(rom_copy, rom_address, *rom_size); done: pci_unmap_rom(dev, rom_address); @@ -1123,27 +1122,37 @@ static void ReadVBIOSTablData(struct pci_dev *pdev, unsigned long i; unsigned char j, k; struct XGI21_LVDSCapStruct *lvds; + size_t vbios_size; if (xgifb_info->chip != XG21) return; pVBInfo->IF_DEF_LVDS = 0; - vbios = xgifb_copy_rom(pdev); + vbios = xgifb_copy_rom(pdev, &vbios_size); if (vbios == NULL) { dev_err(&pdev->dev, "video BIOS not available\n"); return; } + if (vbios_size <= 0x65) + goto error; if (!(vbios[0x65] & 0x1)) { vfree(vbios); return; } - pVBInfo->IF_DEF_LVDS = 1; + if (vbios_size <= 0x317) + goto error; i = vbios[0x316] | (vbios[0x317] << 8); + if (vbios_size <= i - 1) + goto error; j = vbios[i - 1]; + if (j == 0) + goto error; if (j == 0xff) j = 1; k = 0; lvds = &pVBInfo->XG21_LVDSCapList[0]; do { + if (vbios_size <= i + 24) + goto error; lvds->LVDS_Capability = vbios[i] | (vbios[i + 1] << 8); lvds->LVDSHT = vbios[i + 2] | (vbios[i + 3] << 8); lvds->LVDSVT = vbios[i + 4] | (vbios[i + 5] << 8); @@ -1166,6 +1175,11 @@ static void ReadVBIOSTablData(struct pci_dev *pdev, lvds++; } while (j > 0 && k < ARRAY_SIZE(XGI21_LCDCapList)); vfree(vbios); + pVBInfo->IF_DEF_LVDS = 1; + return; +error: + dev_err(&pdev->dev, "video BIOS corrupted\n"); + vfree(vbios); } static void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, |