diff options
author | jmg <jmg@FreeBSD.org> | 2006-10-20 21:28:11 +0000 |
---|---|---|
committer | jmg <jmg@FreeBSD.org> | 2006-10-20 21:28:11 +0000 |
commit | c113c037705c3993d35aee81909d5aa629a2a477 (patch) | |
tree | 56316e3aaf0fc9473818fd9bef4319ed8c1ec33b /sys/dev/pci | |
parent | 9a86c1b09ef674f033c0d362c24a14519a3020f2 (diff) | |
download | FreeBSD-src-c113c037705c3993d35aee81909d5aa629a2a477.zip FreeBSD-src-c113c037705c3993d35aee81909d5aa629a2a477.tar.gz |
fix tab indentation for CP and RV...
If the length is zero, catch this early, instead of making dflen go negative
and letting bad things happen... We also check to see if RV (checksum) is
0, and handle that has a checksum failure...
Properly handle checksum failures by not processing read-write VPD data,
and removing all the found read-only data...
Tested by: oleg (dflen going negative)
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/pci.c | 58 |
1 files changed, 51 insertions, 7 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index ca4aee1..e534548 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -653,12 +653,37 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg) cfg->vpd.vpd_ros[off].keyword[0] = byte; cfg->vpd.vpd_ros[off].keyword[1] = vpd_nextbyte(&vrs); dflen = vpd_nextbyte(&vrs); - cfg->vpd.vpd_ros[off].value = malloc((dflen + 1) * - sizeof *cfg->vpd.vpd_ros[off].value, - M_DEVBUF, M_WAITOK); + if (dflen == 0 && + strncmp(cfg->vpd.vpd_ros[off].keyword, "RV", + 2) == 0) { + /* + * if this happens, we can't trust the rest + * of the VPD. + */ + printf("pci%d:%d:%d: bad keyword length: %d\n", + cfg->bus, cfg->slot, cfg->func, dflen); + cksumvalid = 0; + end = 1; + break; + } else if (dflen == 0) { + cfg->vpd.vpd_ros[off].value = malloc(1 * + sizeof *cfg->vpd.vpd_ros[off].value, + M_DEVBUF, M_WAITOK); + cfg->vpd.vpd_ros[off].value[0] = '\x00'; + } else + cfg->vpd.vpd_ros[off].value = malloc( + (dflen + 1) * + sizeof *cfg->vpd.vpd_ros[off].value, + M_DEVBUF, M_WAITOK); remain -= 3; i = 0; - state = 3; + /* keep in sync w/ state 3's transistions */ + if (dflen == 0 && remain == 0) + state = 0; + else if (dflen == 0) + state = 2; + else + state = 3; break; case 3: /* VPD-R Keyword Value */ @@ -673,10 +698,13 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg) cfg->bus, cfg->slot, cfg->func, vrs.cksum); cksumvalid = 0; + end = 1; + break; } } dflen--; remain--; + /* keep in sync w/ state 2's transistions */ if (dflen == 0) cfg->vpd.vpd_ros[off++].value[i++] = '\0'; if (dflen == 0 && remain == 0) { @@ -710,13 +738,20 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg) M_DEVBUF, M_WAITOK); remain -= 3; i = 0; - state = 6; + /* keep in sync w/ state 6's transistions */ + if (dflen == 0 && remain == 0) + state = 0; + else if (dflen == 0) + state = 5; + else + state = 6; break; case 6: /* VPD-W Keyword Value */ cfg->vpd.vpd_w[off].value[i++] = byte; dflen--; remain--; + /* keep in sync w/ state 5's transistions */ if (dflen == 0) cfg->vpd.vpd_w[off++].value[i++] = '\0'; if (dflen == 0 && remain == 0) { @@ -736,6 +771,15 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg) break; } } + + if (cksumvalid == 0) { + /* read-only data bad, clean up */ + for (; off; off--) + free(cfg->vpd.vpd_ros[off].value, M_DEVBUF); + + free(cfg->vpd.vpd_ros, M_DEVBUF); + cfg->vpd.vpd_ros = NULL; + } #undef REG } @@ -1111,12 +1155,12 @@ pci_print_verbose(struct pci_devinfo *dinfo) struct vpd_readonly *vrop; vrop = &cfg->vpd.vpd_ros[i]; if (strncmp("CP", vrop->keyword, 2) == 0) - printf("CP: id %d, BAR%d, off %#x\n", + printf("\tCP: id %d, BAR%d, off %#x\n", vrop->value[0], vrop->value[1], le16toh( *(uint16_t *)&vrop->value[2])); else if (strncmp("RV", vrop->keyword, 2) == 0) - printf("RV: %#hhx\n", vrop->value[0]); + printf("\tRV: %#hhx\n", vrop->value[0]); else printf("\t%.2s: %s\n", vrop->keyword, vrop->value); |