DragonFlyBSD Kernel Audit
DF-2322 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/bus/pci/pci.c b/sys/bus/pci/pci.c
--- a/sys/bus/pci/pci.c
+++ b/sys/bus/pci/pci.c
@@ -1685,6 +1685,30 @@
 	cfg->msix.msix_table_res = table_res;
 	cfg->msix.msix_pba_res = pba_res;
 
+	/* All of msix_msgnum, msix_table_offset and msix_pba_offset come from
+	   device config space and so are attacker-controlled on a malicious PCI
+	   device.  Verify the BAR mappings are large enough for the reported
+	   table/PBA layout before pci_mask_msix_allvectors() and later vector
+	   writes can run off the mapping (OOB MMIO read/write). */
+	{
+		u_long table_need = (u_long)msix->msix_table_offset +
+		    (u_long)msix->msix_msgnum * 16;
+		u_long pba_need = (u_long)msix->msix_pba_offset +
+		    howmany(msix->msix_msgnum, 8);
+
+		if (table_need > rman_get_size(table_res) ||
+		    pba_need > rman_get_size(pba_res)) {
+			device_printf(dev,
+			    "MSI-X table/PBA exceeds BAR size (table %#lx/%#lx, "
+			    "pba %#lx/%#lx)\n", table_need,
+			    (u_long)rman_get_size(table_res), pba_need,
+			    (u_long)rman_get_size(pba_res));
+			cfg->msix.msix_table_res = NULL;
+			cfg->msix.msix_pba_res = NULL;
+			return (ENXIO);
+		}
+	}
+
 	pci_mask_msix_allvectors(dev);
 
 	return 0;