summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorStefan Eßer <se@FreeBSD.org>2022-02-20 21:07:35 +0000
committerStefan Eßer <se@FreeBSD.org>2022-03-04 19:50:21 +0000
commitf0163795c58982b8bd8d1034dd70f04c2fda5474 (patch)
tree5a885a1d449a5f6f0bb914dda7a2e2651676411a /sys/dev/pci
parent97b94f4332ac370b5fd04b973e96564fa99b043f (diff)
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/pci.c42
-rw-r--r--sys/dev/pci/pci_user.c9
2 files changed, 41 insertions, 10 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++)
diff --git a/sys/dev/pci/pci_user.c b/sys/dev/pci/pci_user.c
index 544cb83ece69..fc84b5cfaa25 100644
--- a/sys/dev/pci/pci_user.c
+++ b/sys/dev/pci/pci_user.c
@@ -562,7 +562,7 @@ pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
{
struct pci_vpd_element vpd_element, *vpd_user;
struct pcicfg_vpd *vpd;
- size_t len;
+ size_t len, datalen;
int error, i;
vpd = pci_fetch_vpd_list(dev);
@@ -593,16 +593,17 @@ pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
* Copyout the identifier string followed by each keyword and
* value.
*/
+ datalen = strlen(vpd->vpd_ident);
+ KASSERT(datalen <= 255, ("invalid VPD ident length"));
vpd_user = lvio->plvi_data;
vpd_element.pve_keyword[0] = '\0';
vpd_element.pve_keyword[1] = '\0';
vpd_element.pve_flags = PVE_FLAG_IDENT;
- vpd_element.pve_datalen = strlen(vpd->vpd_ident);
+ vpd_element.pve_datalen = datalen;
error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
if (error)
return (error);
- error = copyout(vpd->vpd_ident, vpd_user->pve_data,
- strlen(vpd->vpd_ident));
+ error = copyout(vpd->vpd_ident, vpd_user->pve_data, datalen);
if (error)
return (error);
vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);