aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/xgifb
diff options
context:
space:
mode:
authorAaro Koskinen <aaro.koskinen@iki.fi>2011-12-06 00:10:40 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2011-12-08 12:26:06 -0800
commit08ce239c106f1d147820f419e3dde86422663e7f (patch)
treef9bf0d4027ba680cb5761966ffa79194ae74bb11 /drivers/staging/xgifb
parentstaging: xgifb: use u8 for video BIOS data (diff)
downloadlinux-dev-08ce239c106f1d147820f419e3dde86422663e7f.tar.xz
linux-dev-08ce239c106f1d147820f419e3dde86422663e7f.zip
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/staging/xgifb')
-rw-r--r--drivers/staging/xgifb/vb_init.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index b4383948d72a..96e2334af2a1 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,