diff options
author | Aaro Koskinen <aaro.koskinen@iki.fi> | 2011-12-05 17:10:40 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-12-08 15:26:06 -0500 |
commit | 08ce239c106f1d147820f419e3dde86422663e7f (patch) | |
tree | f9bf0d4027ba680cb5761966ffa79194ae74bb11 | |
parent | 82986dd9e738996a9d2e508c164d1eb7464c07c6 (diff) |
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>
-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 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, | |||
1093 | xgifb_reg_set(pVBInfo->P3c4, 0x21, (unsigned short) (data | 0x20)); | 1093 | xgifb_reg_set(pVBInfo->P3c4, 0x21, (unsigned short) (data | 0x20)); |
1094 | } | 1094 | } |
1095 | 1095 | ||
1096 | static u8 *xgifb_copy_rom(struct pci_dev *dev) | 1096 | static u8 *xgifb_copy_rom(struct pci_dev *dev, size_t *rom_size) |
1097 | { | 1097 | { |
1098 | void __iomem *rom_address; | 1098 | void __iomem *rom_address; |
1099 | u8 *rom_copy; | 1099 | u8 *rom_copy; |
1100 | size_t rom_size; | ||
1101 | 1100 | ||
1102 | rom_address = pci_map_rom(dev, &rom_size); | 1101 | rom_address = pci_map_rom(dev, rom_size); |
1103 | if (rom_address == NULL) | 1102 | if (rom_address == NULL) |
1104 | return NULL; | 1103 | return NULL; |
1105 | 1104 | ||
@@ -1107,8 +1106,8 @@ static u8 *xgifb_copy_rom(struct pci_dev *dev) | |||
1107 | if (rom_copy == NULL) | 1106 | if (rom_copy == NULL) |
1108 | goto done; | 1107 | goto done; |
1109 | 1108 | ||
1110 | rom_size = min_t(size_t, rom_size, XGIFB_ROM_SIZE); | 1109 | *rom_size = min_t(size_t, *rom_size, XGIFB_ROM_SIZE); |
1111 | memcpy_fromio(rom_copy, rom_address, rom_size); | 1110 | memcpy_fromio(rom_copy, rom_address, *rom_size); |
1112 | 1111 | ||
1113 | done: | 1112 | done: |
1114 | pci_unmap_rom(dev, rom_address); | 1113 | pci_unmap_rom(dev, rom_address); |
@@ -1123,27 +1122,37 @@ static void ReadVBIOSTablData(struct pci_dev *pdev, | |||
1123 | unsigned long i; | 1122 | unsigned long i; |
1124 | unsigned char j, k; | 1123 | unsigned char j, k; |
1125 | struct XGI21_LVDSCapStruct *lvds; | 1124 | struct XGI21_LVDSCapStruct *lvds; |
1125 | size_t vbios_size; | ||
1126 | 1126 | ||
1127 | if (xgifb_info->chip != XG21) | 1127 | if (xgifb_info->chip != XG21) |
1128 | return; | 1128 | return; |
1129 | pVBInfo->IF_DEF_LVDS = 0; | 1129 | pVBInfo->IF_DEF_LVDS = 0; |
1130 | vbios = xgifb_copy_rom(pdev); | 1130 | vbios = xgifb_copy_rom(pdev, &vbios_size); |
1131 | if (vbios == NULL) { | 1131 | if (vbios == NULL) { |
1132 | dev_err(&pdev->dev, "video BIOS not available\n"); | 1132 | dev_err(&pdev->dev, "video BIOS not available\n"); |
1133 | return; | 1133 | return; |
1134 | } | 1134 | } |
1135 | if (vbios_size <= 0x65) | ||
1136 | goto error; | ||
1135 | if (!(vbios[0x65] & 0x1)) { | 1137 | if (!(vbios[0x65] & 0x1)) { |
1136 | vfree(vbios); | 1138 | vfree(vbios); |
1137 | return; | 1139 | return; |
1138 | } | 1140 | } |
1139 | pVBInfo->IF_DEF_LVDS = 1; | 1141 | if (vbios_size <= 0x317) |
1142 | goto error; | ||
1140 | i = vbios[0x316] | (vbios[0x317] << 8); | 1143 | i = vbios[0x316] | (vbios[0x317] << 8); |
1144 | if (vbios_size <= i - 1) | ||
1145 | goto error; | ||
1141 | j = vbios[i - 1]; | 1146 | j = vbios[i - 1]; |
1147 | if (j == 0) | ||
1148 | goto error; | ||
1142 | if (j == 0xff) | 1149 | if (j == 0xff) |
1143 | j = 1; | 1150 | j = 1; |
1144 | k = 0; | 1151 | k = 0; |
1145 | lvds = &pVBInfo->XG21_LVDSCapList[0]; | 1152 | lvds = &pVBInfo->XG21_LVDSCapList[0]; |
1146 | do { | 1153 | do { |
1154 | if (vbios_size <= i + 24) | ||
1155 | goto error; | ||
1147 | lvds->LVDS_Capability = vbios[i] | (vbios[i + 1] << 8); | 1156 | lvds->LVDS_Capability = vbios[i] | (vbios[i + 1] << 8); |
1148 | lvds->LVDSHT = vbios[i + 2] | (vbios[i + 3] << 8); | 1157 | lvds->LVDSHT = vbios[i + 2] | (vbios[i + 3] << 8); |
1149 | lvds->LVDSVT = vbios[i + 4] | (vbios[i + 5] << 8); | 1158 | lvds->LVDSVT = vbios[i + 4] | (vbios[i + 5] << 8); |
@@ -1166,6 +1175,11 @@ static void ReadVBIOSTablData(struct pci_dev *pdev, | |||
1166 | lvds++; | 1175 | lvds++; |
1167 | } while (j > 0 && k < ARRAY_SIZE(XGI21_LCDCapList)); | 1176 | } while (j > 0 && k < ARRAY_SIZE(XGI21_LCDCapList)); |
1168 | vfree(vbios); | 1177 | vfree(vbios); |
1178 | pVBInfo->IF_DEF_LVDS = 1; | ||
1179 | return; | ||
1180 | error: | ||
1181 | dev_err(&pdev->dev, "video BIOS corrupted\n"); | ||
1182 | vfree(vbios); | ||
1169 | } | 1183 | } |
1170 | 1184 | ||
1171 | static void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, | 1185 | static void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, |