DragonFlyBSD Kernel Audit
DF-1075 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/bus/u4b/net/if_kue.c b/sys/bus/u4b/net/if_kue.c
--- a/sys/bus/u4b/net/if_kue.c
+++ b/sys/bus/u4b/net/if_kue.c
@@ -439,6 +439,20 @@
 	kue_ctl(sc, KUE_CTL_READ, KUE_CMD_GET_ETHER_DESCRIPTOR,
 	    0, &sc->sc_desc, sizeof(sc->sc_desc));
 
+	/*
+	 * Allocate the multicast filter buffer now that the device has
+	 * reported its multicast filter capacity in the descriptor above.
+	 * This MUST happen here, not in kue_attach(): at kue_attach() time
+	 * the descriptor has not been fetched yet and the zero-initialised
+	 * softc yields KUE_MCFILTCNT(sc)==0, producing a zero-length
+	 * kmalloc that returns ZERO_LENGTH_PTR.  The NULL check in
+	 * kue_attach() does not catch the sentinel ((void *)-8 != NULL),
+	 * so a later kue_setmulti() memcpy would write past the sentinel
+	 * into unmapped KVA and panic the kernel (DF-1075).
+	 */
+	sc->sc_mcfilters = kmalloc(KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN,
+	    M_USBDEV, M_WAITOK);
+
 	/* copy in ethernet address */
 	memcpy(ue->ue_eaddr, sc->sc_desc.kue_macaddr, sizeof(ue->ue_eaddr));
 }
@@ -485,13 +499,6 @@
 		goto detach;
 	}
 
-	sc->sc_mcfilters = kmalloc(KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN,
-	    M_USBDEV, M_WAITOK);
-	if (sc->sc_mcfilters == NULL) {
-		device_printf(dev, "failed allocating USB memory\n");
-		goto detach;
-	}
-
 	ue->ue_sc = sc;
 	ue->ue_dev = dev;
 	ue->ue_udev = uaa->device;
@@ -518,8 +525,14 @@
 
 	usbd_transfer_unsetup(sc->sc_xfer, KUE_N_TRANSFER);
 	uether_ifdetach(ue);
+	/*
+	 * kfree(NULL) panics on DragonFlyBSD (kern_slaballoc.c:1406-1407).
+	 * If uether_ifattach() failed before kue_attach_post() ran,
+	 * sc_mcfilters is still NULL — guard the free.
+	 */
+	if (sc->sc_mcfilters != NULL)
+		kfree(sc->sc_mcfilters, M_USBDEV);
 	lockuninit(&sc->sc_lock);
-	kfree(sc->sc_mcfilters, M_USBDEV);
 
 	return (0);
 }