mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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 03c427147b ("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>
			
			
This commit is contained in:
		
							parent
							
								
									cbf658dd09
								
							
						
					
					
						commit
						6b69680847
					
				
					 1 changed files with 17 additions and 16 deletions
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -770,34 +768,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -908,6 +895,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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -943,6 +939,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:
 | 
			
		||||
| 
						 | 
				
			
			@ -963,6 +961,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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue