DF-5453 / fix.diff
--- a/sys/bus/u4b/net/if_kue.c +++ b/sys/bus/u4b/net/if_kue.c @@ -482,14 +482,14 @@ sc->sc_xfer, kue_config, KUE_N_TRANSFER, sc, &sc->sc_lock); if (error) { device_printf(dev, "allocating USB transfers failed\n"); - goto detach; + goto detach_usb; } 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; + goto detach_usb; } ue->ue_sc = sc; @@ -501,12 +501,22 @@ error = uether_ifattach(ue); if (error) { device_printf(dev, "could not attach interface\n"); - goto detach; + goto detach_usb; } return (0); /* success */ -detach: - kue_detach(dev); +detach_usb: + /* + * The usb_ether was never attached (or failed halfway): do NOT + * call kue_detach()/uether_ifdetach() on it -- with ue_lock still + * NULL (USB transfer setup failure) uether_ifdetach() lockmgr()s + * through the NULL pointer, and after a failed uether_ifattach() + * the embedded ifnet was never if_attach()ed, so ether_ifdetach() + * would corrupt ifindex2ifnet[0] and the global ifnet list. + */ + usbd_transfer_unsetup(sc->sc_xfer, KUE_N_TRANSFER); + kfree(sc->sc_mcfilters, M_USBDEV); + lockuninit(&sc->sc_lock); return (ENXIO); /* failure */ } --- a/sys/bus/u4b/net/usb_ethernet.c +++ b/sys/bus/u4b/net/usb_ethernet.c @@ -269,6 +269,16 @@ { struct ifnet *ifp; + /* + * A driver attach() failure may call detach() on a usb_ether that + * was never uether_ifattach()ed: ue_lock is still NULL there and + * the embedded ifnet was never if_attach()ed. Bail out instead + * of lockmgr()ing through the NULL pointer and tearing down a + * non-existent ifnet. + */ + if (ue->ue_lock == NULL) + return; + /* wait for any post attach or other command to complete */ usb_proc_drain(&ue->ue_tq); |