Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: uniphier: fix reference count leak in uniphier_spi_probe()

The issue happens in several error paths in uniphier_spi_probe().
When either dma_get_slave_caps() or devm_spi_register_master() returns
an error code, the function forgets to decrease the refcount of both
`dma_rx` and `dma_tx` objects, which may lead to refcount leaks.

Fix it by decrementing the reference count of specific objects in
those error paths.

Signed-off-by: Xin Xiong <xiongx18@fudan.edu.cn>
Signed-off-by: Xiyu Yang <xiyuyang19@fudan.edu.cn>
Signed-off-by: Xin Tan <tanxin.ctf@gmail.com>
Reviewed-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Fixes: 28d1dddc59f6 ("spi: uniphier: Add DMA transfer mode support")
Link: https://lore.kernel.org/r/20220125101214.35677-1-xiongx18@fudan.edu.cn
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Xin Xiong and committed by
Mark Brown
37c2c83c e937440f

+14 -4
+14 -4
drivers/spi/spi-uniphier.c
··· 726 726 if (ret) { 727 727 dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n", 728 728 ret); 729 - goto out_disable_clk; 729 + goto out_release_dma; 730 730 } 731 731 dma_tx_burst = caps.max_burst; 732 732 } ··· 735 735 if (IS_ERR_OR_NULL(master->dma_rx)) { 736 736 if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) { 737 737 ret = -EPROBE_DEFER; 738 - goto out_disable_clk; 738 + goto out_release_dma; 739 739 } 740 740 master->dma_rx = NULL; 741 741 dma_rx_burst = INT_MAX; ··· 744 744 if (ret) { 745 745 dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n", 746 746 ret); 747 - goto out_disable_clk; 747 + goto out_release_dma; 748 748 } 749 749 dma_rx_burst = caps.max_burst; 750 750 } ··· 753 753 754 754 ret = devm_spi_register_master(&pdev->dev, master); 755 755 if (ret) 756 - goto out_disable_clk; 756 + goto out_release_dma; 757 757 758 758 return 0; 759 + 760 + out_release_dma: 761 + if (!IS_ERR_OR_NULL(master->dma_rx)) { 762 + dma_release_channel(master->dma_rx); 763 + master->dma_rx = NULL; 764 + } 765 + if (!IS_ERR_OR_NULL(master->dma_tx)) { 766 + dma_release_channel(master->dma_tx); 767 + master->dma_tx = NULL; 768 + } 759 769 760 770 out_disable_clk: 761 771 clk_disable_unprepare(priv->clk);