| From 3e01ad1aaf38c81368aa840a9a28195d6268cdfb Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 18 Mar 2021 08:24:50 +0100 |
| Subject: spi: stm32: Fix use-after-free on unbind |
| |
| From: Alain Volmat <alain.volmat@foss.st.com> |
| |
| [ Upstream commit 79c6246ae8793448c05da86a4c82298eed8549b0 ] |
| |
| stm32_spi_remove() accesses the driver's private data after calling |
| spi_unregister_master() even though that function releases the last |
| reference on the spi_master and thereby frees the private data. |
| |
| Fix by switching over to the new devm_spi_alloc_master() helper which |
| keeps the private data accessible until the driver has unbound. |
| |
| Fixes: 8d559a64f00b ("spi: stm32: drop devres version of spi_register_master") |
| |
| Reported-by: Lukas Wunner <lukas@wunner.de> |
| Signed-off-by: Alain Volmat <alain.volmat@foss.st.com> |
| Link: https://lore.kernel.org/r/1616052290-10887-1-git-send-email-alain.volmat@foss.st.com |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/spi/spi-stm32.c | 24 ++++++++++-------------- |
| 1 file changed, 10 insertions(+), 14 deletions(-) |
| |
| diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c |
| index 8d8a32d46f2d..0318f02d6212 100644 |
| --- a/drivers/spi/spi-stm32.c |
| +++ b/drivers/spi/spi-stm32.c |
| @@ -1830,7 +1830,7 @@ static int stm32_spi_probe(struct platform_device *pdev) |
| struct resource *res; |
| int ret; |
| |
| - master = spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); |
| + master = devm_spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); |
| if (!master) { |
| dev_err(&pdev->dev, "spi master allocation failed\n"); |
| return -ENOMEM; |
| @@ -1848,18 +1848,16 @@ static int stm32_spi_probe(struct platform_device *pdev) |
| |
| res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| spi->base = devm_ioremap_resource(&pdev->dev, res); |
| - if (IS_ERR(spi->base)) { |
| - ret = PTR_ERR(spi->base); |
| - goto err_master_put; |
| - } |
| + if (IS_ERR(spi->base)) |
| + return PTR_ERR(spi->base); |
| |
| spi->phys_addr = (dma_addr_t)res->start; |
| |
| spi->irq = platform_get_irq(pdev, 0); |
| - if (spi->irq <= 0) { |
| - ret = dev_err_probe(&pdev->dev, spi->irq, "failed to get irq\n"); |
| - goto err_master_put; |
| - } |
| + if (spi->irq <= 0) |
| + return dev_err_probe(&pdev->dev, spi->irq, |
| + "failed to get irq\n"); |
| + |
| ret = devm_request_threaded_irq(&pdev->dev, spi->irq, |
| spi->cfg->irq_handler_event, |
| spi->cfg->irq_handler_thread, |
| @@ -1867,20 +1865,20 @@ static int stm32_spi_probe(struct platform_device *pdev) |
| if (ret) { |
| dev_err(&pdev->dev, "irq%d request failed: %d\n", spi->irq, |
| ret); |
| - goto err_master_put; |
| + return ret; |
| } |
| |
| spi->clk = devm_clk_get(&pdev->dev, NULL); |
| if (IS_ERR(spi->clk)) { |
| ret = PTR_ERR(spi->clk); |
| dev_err(&pdev->dev, "clk get failed: %d\n", ret); |
| - goto err_master_put; |
| + return ret; |
| } |
| |
| ret = clk_prepare_enable(spi->clk); |
| if (ret) { |
| dev_err(&pdev->dev, "clk enable failed: %d\n", ret); |
| - goto err_master_put; |
| + return ret; |
| } |
| spi->clk_rate = clk_get_rate(spi->clk); |
| if (!spi->clk_rate) { |
| @@ -1976,8 +1974,6 @@ err_dma_release: |
| dma_release_channel(spi->dma_rx); |
| err_clk_disable: |
| clk_disable_unprepare(spi->clk); |
| -err_master_put: |
| - spi_master_put(master); |
| |
| return ret; |
| } |
| -- |
| 2.30.2 |
| |