enc28j60_remove() unregisters the interface, frees the IRQ and frees the netdev, but tx_work, setrx_work and restart_work can still be pending or running. tx_work is queued from enc28j60_send_packet(), setrx_work from enc28j60_set_multicast_list(), and restart_work from enc28j60_tx_timeout(). The handlers access the private data, the SPI device and the netdev, all of which are freed with the netdev. Unregister the interface first so the xmit and set_rx_mode paths can no longer queue work, then disable the three works synchronously before freeing the IRQ and the netdev. disable_work_sync() drains a queued or running instance and rejects a later queue_work(), which a plain cancel_work_sync() would not. Fixes: 3ec9c11da033 ("add driver for enc28j60 ethernet chip") Cc: stable@vger.kernel.org # 6.10+ Signed-off-by: BeaCox <0xbeac@gmail.com> --- drivers/net/ethernet/microchip/enc28j60.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/microchip/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c index d6c9491537..bb29a94a1e 100644 --- a/drivers/net/ethernet/microchip/enc28j60.c +++ b/drivers/net/ethernet/microchip/enc28j60.c @@ -1600,7 +1600,16 @@ static void enc28j60_remove(struct spi_device *spi) { struct enc28j60_net *priv = spi_get_drvdata(spi); + /* + * Stop the interface first so the xmit and set_rx_mode paths can no + * longer queue new work. Then drain the works that were already + * queued; the IRQ handler does not queue work, so the IRQ can be + * released after the drain and before free_netdev(). + */ unregister_netdev(priv->netdev); + disable_work_sync(&priv->tx_work); + disable_work_sync(&priv->setrx_work); + disable_work_sync(&priv->restart_work); free_irq(spi->irq, priv); free_netdev(priv->netdev); } -- 2.43.0