Commit 08ce239c authored by Aaro Koskinen's avatar Aaro Koskinen Committed by Greg Kroah-Hartman

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: default avatarAaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 82986dd9
...@@ -1093,13 +1093,12 @@ static void XGINew_SetDRAMSize_340(struct xgi_hw_device_info *HwDeviceExtension, ...@@ -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)); 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; void __iomem *rom_address;
u8 *rom_copy; 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) if (rom_address == NULL)
return NULL; return NULL;
...@@ -1107,8 +1106,8 @@ static u8 *xgifb_copy_rom(struct pci_dev *dev) ...@@ -1107,8 +1106,8 @@ static u8 *xgifb_copy_rom(struct pci_dev *dev)
if (rom_copy == NULL) if (rom_copy == NULL)
goto done; goto done;
rom_size = min_t(size_t, rom_size, XGIFB_ROM_SIZE); *rom_size = min_t(size_t, *rom_size, XGIFB_ROM_SIZE);
memcpy_fromio(rom_copy, rom_address, rom_size); memcpy_fromio(rom_copy, rom_address, *rom_size);
done: done:
pci_unmap_rom(dev, rom_address); pci_unmap_rom(dev, rom_address);
...@@ -1123,27 +1122,37 @@ static void ReadVBIOSTablData(struct pci_dev *pdev, ...@@ -1123,27 +1122,37 @@ static void ReadVBIOSTablData(struct pci_dev *pdev,
unsigned long i; unsigned long i;
unsigned char j, k; unsigned char j, k;
struct XGI21_LVDSCapStruct *lvds; struct XGI21_LVDSCapStruct *lvds;
size_t vbios_size;
if (xgifb_info->chip != XG21) if (xgifb_info->chip != XG21)
return; return;
pVBInfo->IF_DEF_LVDS = 0; pVBInfo->IF_DEF_LVDS = 0;
vbios = xgifb_copy_rom(pdev); vbios = xgifb_copy_rom(pdev, &vbios_size);
if (vbios == NULL) { if (vbios == NULL) {
dev_err(&pdev->dev, "video BIOS not available\n"); dev_err(&pdev->dev, "video BIOS not available\n");
return; return;
} }
if (vbios_size <= 0x65)
goto error;
if (!(vbios[0x65] & 0x1)) { if (!(vbios[0x65] & 0x1)) {
vfree(vbios); vfree(vbios);
return; return;
} }
pVBInfo->IF_DEF_LVDS = 1; if (vbios_size <= 0x317)
goto error;
i = vbios[0x316] | (vbios[0x317] << 8); i = vbios[0x316] | (vbios[0x317] << 8);
if (vbios_size <= i - 1)
goto error;
j = vbios[i - 1]; j = vbios[i - 1];
if (j == 0)
goto error;
if (j == 0xff) if (j == 0xff)
j = 1; j = 1;
k = 0; k = 0;
lvds = &pVBInfo->XG21_LVDSCapList[0]; lvds = &pVBInfo->XG21_LVDSCapList[0];
do { do {
if (vbios_size <= i + 24)
goto error;
lvds->LVDS_Capability = vbios[i] | (vbios[i + 1] << 8); lvds->LVDS_Capability = vbios[i] | (vbios[i + 1] << 8);
lvds->LVDSHT = vbios[i + 2] | (vbios[i + 3] << 8); lvds->LVDSHT = vbios[i + 2] | (vbios[i + 3] << 8);
lvds->LVDSVT = vbios[i + 4] | (vbios[i + 5] << 8); lvds->LVDSVT = vbios[i + 4] | (vbios[i + 5] << 8);
...@@ -1166,6 +1175,11 @@ static void ReadVBIOSTablData(struct pci_dev *pdev, ...@@ -1166,6 +1175,11 @@ static void ReadVBIOSTablData(struct pci_dev *pdev,
lvds++; lvds++;
} while (j > 0 && k < ARRAY_SIZE(XGI21_LCDCapList)); } while (j > 0 && k < ARRAY_SIZE(XGI21_LCDCapList));
vfree(vbios); 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, static void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment