Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

can: mcp251x: fix deadlock in error path of mcp251x_open

The mcp251x_open() function call free_irq() in its error path with the
mpc_lock mutex held. But if an interrupt already occurred the
interrupt handler will be waiting for the mpc_lock and free_irq() will
deadlock waiting for the handler to finish.

This issue is similar to the one fixed in commit 7dd9c26bd6cf ("can:
mcp251x: fix deadlock if an interrupt occurs during mcp251x_open") but
for the error path.

To solve this issue move the call to free_irq() after the lock is
released. Setting `priv->force_quit = 1` beforehand ensure that the IRQ
handler will exit right away once it acquired the lock.

Signed-off-by: Alban Bedel <alban.bedel@lht.dlh.de>
Link: https://patch.msgid.link/20260209144706.2261954-1-alban.bedel@lht.dlh.de
Fixes: bf66f3736a94 ("can: mcp251x: Move to threaded interrupts instead of workqueues.")
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Alban Bedel and committed by
Marc Kleine-Budde
ab3f894d c77bfbdd

+14 -1
+14 -1
drivers/net/can/spi/mcp251x.c
··· 1214 1214 { 1215 1215 struct mcp251x_priv *priv = netdev_priv(net); 1216 1216 struct spi_device *spi = priv->spi; 1217 + bool release_irq = false; 1217 1218 unsigned long flags = 0; 1218 1219 int ret; 1219 1220 ··· 1258 1257 return 0; 1259 1258 1260 1259 out_free_irq: 1261 - free_irq(spi->irq, priv); 1260 + /* The IRQ handler might be running, and if so it will be waiting 1261 + * for the lock. But free_irq() must wait for the handler to finish 1262 + * so calling it here would deadlock. 1263 + * 1264 + * Setting priv->force_quit will let the handler exit right away 1265 + * without any access to the hardware. This make it safe to call 1266 + * free_irq() after the lock is released. 1267 + */ 1268 + priv->force_quit = 1; 1269 + release_irq = true; 1270 + 1262 1271 mcp251x_hw_sleep(spi); 1263 1272 out_close: 1264 1273 mcp251x_power_enable(priv->transceiver, 0); 1265 1274 close_candev(net); 1266 1275 mutex_unlock(&priv->mcp_lock); 1276 + if (release_irq) 1277 + free_irq(spi->irq, priv); 1267 1278 return ret; 1268 1279 } 1269 1280