⬢ DragonFlyBSD Kernel Audit
DF-5368 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/u4b/input/ums.c
+++ b/sys/bus/u4b/input/ums.c
@@ -770,6 +770,22 @@
 
 	DPRINTF("sc=%p\n", sc);
 
+	/*
+	 * Stop and drain the interrupt transfer and the SBU callout
+	 * FIRST. Until the transfer is drained ums_intr_callback() can
+	 * still run, and it dereferences sc->sc_fifo.fp[USB_FIFO_RX]
+	 * and sc->sc_evdev. With an evdev client holding the device
+	 * open (and no /dev/umsX fifo open) usb_fifo_detach() does not
+	 * stop the transfer - usb_fifo_close() returns early - so
+	 * tearing down the fifo and the evdev before stopping the
+	 * transfer leaves a window where the callback feeds a NULL or
+	 * freed usb_fifo / evdev (usb_fifo_put_bytes_max(NULL),
+	 * usb_fifo_put_data_linear(NULL), evdev_push_*(freed evdev)).
+	 */
+	usbd_transfer_unsetup(sc->sc_xfer, UMS_N_TRANSFER);
+
+	usb_callout_drain(&sc->sc_callout);
+
 	usb_fifo_detach(&sc->sc_fifo);
 
 #ifdef EVDEV_SUPPORT
@@ -777,10 +793,6 @@
 	sc->sc_evdev = NULL;
 #endif
 
-	usbd_transfer_unsetup(sc->sc_xfer, UMS_N_TRANSFER);
-
-	usb_callout_drain(&sc->sc_callout);
-
 	lockuninit(&sc->sc_lock);
 
 	return (0);