⬢ DragonFlyBSD Kernel Audit
DF-5282 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/bus/u4b/controller/ehci.c b/sys/bus/u4b/controller/ehci.c
--- a/sys/bus/u4b/controller/ehci.c
+++ b/sys/bus/u4b/controller/ehci.c
@@ -327,6 +327,28 @@
 	sc->sc_noport = EHCI_HCS_N_PORTS(sparams);
 	sc->sc_bus.usbrev = USB_REV_2_0;
 
+	/*
+	 * Validate the device-reported register geometry before it is
+	 * latched into every subsequent EOREAD4/EOWRITE4 (ehci.h adds
+	 * sc_offs to each operational-register offset). The furthest
+	 * register the driver touches is EHCI_PORTSC(sc_noport) =
+	 * 0x44 + 4*sc_noport, so the whole window
+	 * [sc_offs, sc_offs + 0x44 + 4*sc_noport] must fit inside the
+	 * mapped BAR (sc_io_size, set by the bus glue). CAPLENGTH is 8
+	 * bits and N_PORTS is 4 bits, so a malicious or broken controller
+	 * can push accesses up to 0x17F bytes past the BAR base; with an
+	 * undersized BAR that is out-of-bounds MMIO read/write (same
+	 * defect class as the xHCI CAPLENGTH/DBOFF issue).
+	 */
+	if ((sc->sc_offs < 0x08) ||
+	    ((uint32_t)sc->sc_offs + 0x44 + (4 * sc->sc_noport)) >
+	    sc->sc_io_size) {
+		device_printf(sc->sc_bus.bdev, "invalid register geometry: "
+		    "offs=0x%02x noport=%u io_size=0x%jx\n",
+		    sc->sc_offs, sc->sc_noport, (uintmax_t)sc->sc_io_size);
+		return (USB_ERR_IOERROR);
+	}
+
 	if (!(sc->sc_flags & EHCI_SCFLG_DONTRESET)) {
 		/* Reset the controller */
 		DPRINTF("%s: resetting\n",