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); }