[[PATCH staging] 3/7] staging: wfx: fix init/remove vs IRQ race

Michał Mirosław mirq-linux at rere.qmqm.pl
Tue Feb 11 08:46:54 UTC 2020


Move interrupt request and free so to avoid following WARN on probe
and possible use-after-free on remove.

WARNING: CPU: 0 PID: 827 at drivers/staging/wfx/bus_spi.c:142 wfx_spi_irq_handler+0x5c/0x64 [wfx]
race condition in driver init/deinit

Cc: stable at vger.kernel.org
Signed-off-by: Michał Mirosław <mirq-linux at rere.qmqm.pl>
---
 drivers/staging/wfx/bus_sdio.c | 16 ++++++++--------
 drivers/staging/wfx/bus_spi.c  | 16 +++++++++-------
 2 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index 29688b324b33..2bfaf61e8f62 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -200,16 +200,16 @@ static int wfx_sdio_probe(struct sdio_func *func,
 	if (ret)
 		goto err0;
 
-	ret = wfx_sdio_irq_subscribe(bus);
-	if (ret)
-		goto err1;
-
 	bus->core = wfx_init_common(&func->dev, &wfx_sdio_pdata,
 				    &wfx_sdio_hwbus_ops, bus);
 	if (!bus->core) {
 		ret = -EIO;
+		goto err1;
+	}
+
+	ret = wfx_sdio_irq_subscribe(bus);
+	if (ret)
 		goto err2;
-	}
 
 	ret = wfx_probe(bus->core);
 	if (ret)
@@ -218,9 +218,9 @@ static int wfx_sdio_probe(struct sdio_func *func,
 	return 0;
 
 err3:
-	wfx_free_common(bus->core);
+	wfx_sdio_irq_unsubscribe(bus);
 err2:
-	wfx_sdio_irq_unsubscribe(bus);
+	wfx_free_common(bus->core);
 err1:
 	sdio_claim_host(func);
 	sdio_disable_func(func);
@@ -234,8 +234,8 @@ static void wfx_sdio_remove(struct sdio_func *func)
 	struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
 
 	wfx_release(bus->core);
-	wfx_free_common(bus->core);
 	wfx_sdio_irq_unsubscribe(bus);
+	wfx_free_common(bus->core);
 	sdio_claim_host(func);
 	sdio_disable_func(func);
 	sdio_release_host(func);
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index 3ba705477ca8..2b108a9fa5ae 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -211,20 +211,22 @@ static int wfx_spi_probe(struct spi_device *func)
 		udelay(2000);
 	}
 
-	ret = devm_request_irq(&func->dev, func->irq, wfx_spi_irq_handler,
-			       IRQF_TRIGGER_RISING, "wfx", bus);
-	if (ret)
-		return ret;
-
 	INIT_WORK(&bus->request_rx, wfx_spi_request_rx);
 	bus->core = wfx_init_common(&func->dev, &wfx_spi_pdata,
 				    &wfx_spi_hwbus_ops, bus);
 	if (!bus->core)
 		return -EIO;
 
+	ret = devm_request_irq(&func->dev, func->irq, wfx_spi_irq_handler,
+			       IRQF_TRIGGER_RISING, "wfx", bus);
+	if (ret)
+		return ret;
+
 	ret = wfx_probe(bus->core);
-	if (ret)
+	if (ret) {
+		devm_free_irq(&func->dev, func->irq, bus);
 		wfx_free_common(bus->core);
+	}
 
 	return ret;
 }
@@ -234,11 +236,11 @@ static int wfx_spi_remove(struct spi_device *func)
 	struct wfx_spi_priv *bus = spi_get_drvdata(func);
 
 	wfx_release(bus->core);
-	wfx_free_common(bus->core);
 	// A few IRQ will be sent during device release. Hopefully, no IRQ
 	// should happen after wdev/wvif are released.
 	devm_free_irq(&func->dev, func->irq, bus);
 	flush_work(&bus->request_rx);
+	wfx_free_common(bus->core);
 	return 0;
 }
 
-- 
2.20.1



More information about the devel mailing list