summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorChen Yufeng <chenyufeng@iie.ac.cn>2025-09-11 23:08:20 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-10-12 12:56:21 +0200
commite93af787187e585933570563c643337fa731584a (patch)
treea22a9fec2a83770cf1c3b2b52f4a7d6c08c5baa9 /drivers/net
parent03510f5fce33dec648919f0a7e4b82d8a5003e8b (diff)
downloadlinux-e93af787187e585933570563c643337fa731584a.tar.gz
linux-e93af787187e585933570563c643337fa731584a.tar.bz2
linux-e93af787187e585933570563c643337fa731584a.zip
can: hi311x: fix null pointer dereference when resuming from sleep before interface was enabled
[ Upstream commit 6b696808472197b77b888f50bc789a3bae077743 ] This issue is similar to the vulnerability in the `mcp251x` driver, which was fixed in commit 03c427147b2d ("can: mcp251x: fix resume from sleep before interface was brought up"). In the `hi311x` driver, when the device resumes from sleep, the driver schedules `priv->restart_work`. However, if the network interface was not previously enabled, the `priv->wq` (workqueue) is not allocated and initialized, leading to a null pointer dereference. To fix this, we move the allocation and initialization of the workqueue from the `hi3110_open` function to the `hi3110_can_probe` function. This ensures that the workqueue is properly initialized before it is used during device resume. And added logic to destroy the workqueue in the error handling paths of `hi3110_can_probe` and in the `hi3110_can_remove` function to prevent resource leaks. Signed-off-by: Chen Yufeng <chenyufeng@iie.ac.cn> Link: https://patch.msgid.link/20250911150820.250-1-chenyufeng@iie.ac.cn Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/can/spi/hi311x.c33
1 files changed, 17 insertions, 16 deletions
diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
index 57ea7dfe8a59..1acd4fc7adc8 100644
--- a/drivers/net/can/spi/hi311x.c
+++ b/drivers/net/can/spi/hi311x.c
@@ -545,8 +545,6 @@ static int hi3110_stop(struct net_device *net)
priv->force_quit = 1;
free_irq(spi->irq, priv);
- destroy_workqueue(priv->wq);
- priv->wq = NULL;
mutex_lock(&priv->hi3110_lock);
@@ -771,34 +769,23 @@ static int hi3110_open(struct net_device *net)
goto out_close;
}
- priv->wq = alloc_workqueue("hi3110_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
- 0);
- if (!priv->wq) {
- ret = -ENOMEM;
- goto out_free_irq;
- }
- INIT_WORK(&priv->tx_work, hi3110_tx_work_handler);
- INIT_WORK(&priv->restart_work, hi3110_restart_work_handler);
-
ret = hi3110_hw_reset(spi);
if (ret)
- goto out_free_wq;
+ goto out_free_irq;
ret = hi3110_setup(net);
if (ret)
- goto out_free_wq;
+ goto out_free_irq;
ret = hi3110_set_normal_mode(spi);
if (ret)
- goto out_free_wq;
+ goto out_free_irq;
netif_wake_queue(net);
mutex_unlock(&priv->hi3110_lock);
return 0;
- out_free_wq:
- destroy_workqueue(priv->wq);
out_free_irq:
free_irq(spi->irq, priv);
hi3110_hw_sleep(spi);
@@ -915,6 +902,15 @@ static int hi3110_can_probe(struct spi_device *spi)
if (ret)
goto out_clk;
+ priv->wq = alloc_workqueue("hi3110_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
+ 0);
+ if (!priv->wq) {
+ ret = -ENOMEM;
+ goto out_clk;
+ }
+ INIT_WORK(&priv->tx_work, hi3110_tx_work_handler);
+ INIT_WORK(&priv->restart_work, hi3110_restart_work_handler);
+
priv->spi = spi;
mutex_init(&priv->hi3110_lock);
@@ -950,6 +946,8 @@ static int hi3110_can_probe(struct spi_device *spi)
return 0;
error_probe:
+ destroy_workqueue(priv->wq);
+ priv->wq = NULL;
hi3110_power_enable(priv->power, 0);
out_clk:
@@ -970,6 +968,9 @@ static void hi3110_can_remove(struct spi_device *spi)
hi3110_power_enable(priv->power, 0);
+ destroy_workqueue(priv->wq);
+ priv->wq = NULL;
+
clk_disable_unprepare(priv->clk);
free_candev(net);