aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/pci/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/pci.c')
-rw-r--r--sys/dev/pci/pci.c42
1 files changed, 36 insertions, 6 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index b9d908bdd822..24f81b57ff11 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1094,6 +1094,7 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg)
int alloc, off; /* alloc/off for RO/W arrays */
int cksumvalid;
int dflen;
+ int firstrecord;
uint8_t byte;
uint8_t byte2;
@@ -1109,14 +1110,16 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg)
alloc = off = 0; /* shut up stupid gcc */
dflen = 0; /* shut up stupid gcc */
cksumvalid = -1;
+ firstrecord = 1;
while (state >= 0) {
if (vpd_nextbyte(&vrs, &byte)) {
+ pci_printf(cfg, "VPD read timed out\n");
state = -2;
break;
}
#if 0
- printf("vpd: val: %#x, off: %d, bytesinval: %d, byte: %#hhx, " \
- "state: %d, remain: %d, name: %#x, i: %d\n", vrs.val,
+ pci_printf(cfg, "vpd: val: %#x, off: %d, bytesinval: %d, byte: "
+ "%#hhx, state: %d, remain: %d, name: %#x, i: %d\n", vrs.val,
vrs.off, vrs.bytesinval, byte, state, remain, name, i);
#endif
switch (state) {
@@ -1137,6 +1140,15 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg)
remain = byte & 0x7;
name = (byte >> 3) & 0xf;
}
+ if (firstrecord) {
+ if (name != 0x2) {
+ pci_printf(cfg, "VPD data does not " \
+ "start with ident (%#x)\n", name);
+ state = -2;
+ break;
+ }
+ firstrecord = 0;
+ }
if (vrs.off + remain - vrs.bytesinval > 0x8000) {
pci_printf(cfg,
"VPD data overflow, remain %#x\n", remain);
@@ -1145,6 +1157,19 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg)
}
switch (name) {
case 0x2: /* String */
+ if (cfg->vpd.vpd_ident != NULL) {
+ pci_printf(cfg,
+ "duplicate VPD ident record\n");
+ state = -2;
+ break;
+ }
+ if (remain > 255) {
+ pci_printf(cfg,
+ "VPD ident length %d exceeds 255\n",
+ remain);
+ state = -2;
+ break;
+ }
cfg->vpd.vpd_ident = malloc(remain + 1,
M_DEVBUF, M_WAITOK);
i = 0;
@@ -1170,7 +1195,8 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg)
state = 5;
break;
default: /* Invalid data, abort */
- state = -1;
+ pci_printf(cfg, "invalid VPD name: %#x\n", name);
+ state = -2;
break;
}
break;
@@ -1208,8 +1234,7 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg)
* if this happens, we can't trust the rest
* of the VPD.
*/
- pci_printf(cfg, "bad keyword length: %d\n",
- dflen);
+ pci_printf(cfg, "invalid VPD RV record");
cksumvalid = 0;
state = -1;
break;
@@ -1325,9 +1350,14 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg)
state = -1;
break;
}
+
+ if (cfg->vpd.vpd_ident == NULL || cfg->vpd.vpd_ident[0] == '\0') {
+ pci_printf(cfg, "no valid vpd ident found\n");
+ state = -2;
+ }
}
- if (cksumvalid == 0 || state < -1) {
+ if (cksumvalid <= 0 || state < -1) {
/* read-only data bad, clean up */
if (cfg->vpd.vpd_ros != NULL) {
for (off = 0; cfg->vpd.vpd_ros[off].value; off++)