⬢ DragonFlyBSD Kernel Audit
DF-5399 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/u4b/net/if_mos.c
+++ b/sys/bus/u4b/net/if_mos.c
@@ -703,7 +703,7 @@
 
 	if (error) {
 		device_printf(dev, "allocating USB transfers failed\n");
-		goto detach;
+		goto detach_usb;
 	}
 	ue->ue_sc = sc;
 	ue->ue_dev = dev;
@@ -722,14 +722,23 @@
 	error = uether_ifattach(ue);
 	if (error) {
 		device_printf(dev, "could not attach interface\n");
-		goto detach;
+		goto detach_usb;
 	}
 	return (0);
 
 
-detach:
-	mos_detach(dev);
-	return (ENXIO);
+detach_usb:
+	/*
+	 * The usb_ether was never attached (or failed halfway): do NOT
+	 * call mos_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, MOS_ENDPT_MAX);
+	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);