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