Skip to content

Commit 6b69680

Browse files
Chen Yufengmarckleinebudde
authored andcommitted
can: hi311x: fix null pointer dereference when resuming from sleep before interface was enabled
This issue is similar to the vulnerability in the `mcp251x` driver, which was fixed in commit 03c4271 ("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 <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent cbf658d commit 6b69680

File tree

1 file changed

+17
-16
lines changed

1 file changed

+17
-16
lines changed

drivers/net/can/spi/hi311x.c

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -545,8 +545,6 @@ static int hi3110_stop(struct net_device *net)
545545

546546
priv->force_quit = 1;
547547
free_irq(spi->irq, priv);
548-
destroy_workqueue(priv->wq);
549-
priv->wq = NULL;
550548

551549
mutex_lock(&priv->hi3110_lock);
552550

@@ -770,34 +768,23 @@ static int hi3110_open(struct net_device *net)
770768
goto out_close;
771769
}
772770

773-
priv->wq = alloc_workqueue("hi3110_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
774-
0);
775-
if (!priv->wq) {
776-
ret = -ENOMEM;
777-
goto out_free_irq;
778-
}
779-
INIT_WORK(&priv->tx_work, hi3110_tx_work_handler);
780-
INIT_WORK(&priv->restart_work, hi3110_restart_work_handler);
781-
782771
ret = hi3110_hw_reset(spi);
783772
if (ret)
784-
goto out_free_wq;
773+
goto out_free_irq;
785774

786775
ret = hi3110_setup(net);
787776
if (ret)
788-
goto out_free_wq;
777+
goto out_free_irq;
789778

790779
ret = hi3110_set_normal_mode(spi);
791780
if (ret)
792-
goto out_free_wq;
781+
goto out_free_irq;
793782

794783
netif_wake_queue(net);
795784
mutex_unlock(&priv->hi3110_lock);
796785

797786
return 0;
798787

799-
out_free_wq:
800-
destroy_workqueue(priv->wq);
801788
out_free_irq:
802789
free_irq(spi->irq, priv);
803790
hi3110_hw_sleep(spi);
@@ -908,6 +895,15 @@ static int hi3110_can_probe(struct spi_device *spi)
908895
if (ret)
909896
goto out_clk;
910897

898+
priv->wq = alloc_workqueue("hi3110_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
899+
0);
900+
if (!priv->wq) {
901+
ret = -ENOMEM;
902+
goto out_clk;
903+
}
904+
INIT_WORK(&priv->tx_work, hi3110_tx_work_handler);
905+
INIT_WORK(&priv->restart_work, hi3110_restart_work_handler);
906+
911907
priv->spi = spi;
912908
mutex_init(&priv->hi3110_lock);
913909

@@ -943,6 +939,8 @@ static int hi3110_can_probe(struct spi_device *spi)
943939
return 0;
944940

945941
error_probe:
942+
destroy_workqueue(priv->wq);
943+
priv->wq = NULL;
946944
hi3110_power_enable(priv->power, 0);
947945

948946
out_clk:
@@ -963,6 +961,9 @@ static void hi3110_can_remove(struct spi_device *spi)
963961

964962
hi3110_power_enable(priv->power, 0);
965963

964+
destroy_workqueue(priv->wq);
965+
priv->wq = NULL;
966+
966967
clk_disable_unprepare(priv->clk);
967968

968969
free_candev(net);

0 commit comments

Comments
 (0)