⬢ DragonFlyBSD Kernel Audit
DF-5278 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/pci/pci.c
+++ b/sys/bus/pci/pci.c
@@ -1098,6 +1098,7 @@
 			    "pci%d:%d:%d:%d: invalid VPD data, remain %#x\n",
 					    cfg->domain, cfg->bus, cfg->slot,
 					    cfg->func, remain);
+				break;
 				}
 				name = byte & 0x7f;
 			} else {
@@ -1106,6 +1107,12 @@
 			}
 			switch (name) {
 			case 0x2:	/* String */
+				if (remain == 0) {
+					/* zero-length ident: state 1 would
+					 * write unboundedly past kmalloc(1) */
+					state = -1;
+					break;
+				}
 				cfg->vpd.vpd_ident = kmalloc(remain + 1,
 				    M_DEVBUF, M_WAITOK);
 				i = 0;
@@ -1187,6 +1194,12 @@
 				    sizeof(*cfg->vpd.vpd_ros[off].value),
 				    M_DEVBUF, M_WAITOK);
 			remain -= 3;
+			if (remain < 0) {
+				/* header longer than item: `remain == 0`
+				 * could never fire again */
+				state = -1;
+				break;
+			}
 			i = 0;
 			/* keep in sync w/ state 3's transistions */
 			if (dflen == 0 && remain == 0)
@@ -1258,6 +1271,12 @@
 			    sizeof(*cfg->vpd.vpd_w[off].value),
 			    M_DEVBUF, M_WAITOK);
 			remain -= 3;
+			if (remain < 0) {
+				/* header longer than item: `remain == 0`
+				 * could never fire again */
+				state = -1;
+				break;
+			}
 			i = 0;
 			/* keep in sync w/ state 6's transistions */
 			if (dflen == 0 && remain == 0)
@@ -1301,6 +1320,7 @@
 				kfree(cfg->vpd.vpd_ros[off].value, M_DEVBUF);
 			kfree(cfg->vpd.vpd_ros, M_DEVBUF);
 			cfg->vpd.vpd_ros = NULL;
+			cfg->vpd.vpd_rocnt = 0;
 		}
 	}
 	if (state < -1) {
@@ -1316,6 +1336,7 @@
 				kfree(cfg->vpd.vpd_w[off].value, M_DEVBUF);
 			kfree(cfg->vpd.vpd_w, M_DEVBUF);
 			cfg->vpd.vpd_w = NULL;
+			cfg->vpd.vpd_wcnt = 0;
 		}
 	}
 	cfg->vpd.vpd_cached = 1;
@@ -1351,10 +1372,14 @@
 	if (!cfg->vpd.vpd_cached && cfg->vpd.vpd_reg != 0)
 		pci_read_vpd(device_get_parent(dev), cfg);
 
+	if (cfg->vpd.vpd_ros == NULL)
+		return (ENXIO);
+
 	for (i = 0; i < cfg->vpd.vpd_rocnt; i++)
 		if (memcmp(kw, cfg->vpd.vpd_ros[i].keyword,
 		    sizeof(cfg->vpd.vpd_ros[i].keyword)) == 0) {
 			*vptr = cfg->vpd.vpd_ros[i].value;
+			break;
 		}
 
 	if (i != cfg->vpd.vpd_rocnt)
@@ -2144,13 +2169,19 @@
 	devlist_head = &pci_devq;
 
 	if (dinfo->cfg.vpd.vpd_reg) {
-		kfree(dinfo->cfg.vpd.vpd_ident, M_DEVBUF);
-		for (i = 0; i < dinfo->cfg.vpd.vpd_rocnt; i++)
-			kfree(dinfo->cfg.vpd.vpd_ros[i].value, M_DEVBUF);
-		kfree(dinfo->cfg.vpd.vpd_ros, M_DEVBUF);
-		for (i = 0; i < dinfo->cfg.vpd.vpd_wcnt; i++)
-			kfree(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF);
-		kfree(dinfo->cfg.vpd.vpd_w, M_DEVBUF);
+		if (dinfo->cfg.vpd.vpd_ident != NULL)
+			kfree(dinfo->cfg.vpd.vpd_ident, M_DEVBUF);
+		if (dinfo->cfg.vpd.vpd_ros != NULL) {
+			for (i = 0; i < dinfo->cfg.vpd.vpd_rocnt; i++)
+				kfree(dinfo->cfg.vpd.vpd_ros[i].value,
+				    M_DEVBUF);
+			kfree(dinfo->cfg.vpd.vpd_ros, M_DEVBUF);
+		}
+		if (dinfo->cfg.vpd.vpd_w != NULL) {
+			for (i = 0; i < dinfo->cfg.vpd.vpd_wcnt; i++)
+				kfree(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF);
+			kfree(dinfo->cfg.vpd.vpd_w, M_DEVBUF);
+		}
 	}
 	STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links);
 	kfree(dinfo, M_DEVBUF);