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

ASoC: stm32: sai: fix OF node leak on probe

The reference taken to the sync provider OF node when probing the
platform device is currently only dropped if the set_sync() callback
fails during DAI probe.

Make sure to drop the reference on platform probe failures (e.g. probe
deferral) and on driver unbind.

This also avoids a potential use-after-free in case the DAI is ever
reprobed without first rebinding the platform driver.

Fixes: 5914d285f6b7 ("ASoC: stm32: sai: Add synchronization support")
Fixes: d4180b4c02e7 ("ASoC: stm32: sai: fix set_sync service")
Cc: Olivier Moysan <olivier.moysan@st.com>
Cc: stable@vger.kernel.org # 4.16: d4180b4c02e7
Signed-off-by: Johan Hovold <johan@kernel.org>
Reviewed-by: olivier moysan <olivier.moysan@foss.st.com>
Link: https://patch.msgid.link/20251124104908.15754-4-johan@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Johan Hovold and committed by
Mark Brown
23261f0d 312ec2f0

+19 -16
+3 -9
sound/soc/stm/stm32_sai.c
··· 138 138 if (!pdev) { 139 139 dev_err(&sai_client->pdev->dev, 140 140 "Device not found for node %pOFn\n", np_provider); 141 - of_node_put(np_provider); 142 141 return -ENODEV; 143 142 } 144 143 ··· 146 147 if (!sai_provider) { 147 148 dev_err(&sai_client->pdev->dev, 148 149 "SAI sync provider data not found\n"); 149 - ret = -EINVAL; 150 - goto error; 150 + return -EINVAL; 151 151 } 152 152 153 153 /* Configure sync client */ 154 154 ret = stm32_sai_sync_conf_client(sai_client, synci); 155 155 if (ret < 0) 156 - goto error; 156 + return ret; 157 157 158 158 /* Configure sync provider */ 159 - ret = stm32_sai_sync_conf_provider(sai_provider, synco); 160 - 161 - error: 162 - of_node_put(np_provider); 163 - return ret; 159 + return stm32_sai_sync_conf_provider(sai_provider, synco); 164 160 } 165 161 166 162 static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai)
+16 -7
sound/soc/stm/stm32_sai_sub.c
··· 1586 1586 dev_err(&pdev->dev, 1587 1587 "External synchro not supported\n"); 1588 1588 of_node_put(args.np); 1589 - return -EINVAL; 1589 + ret = -EINVAL; 1590 + goto err_put_sync_provider; 1590 1591 } 1591 1592 sai->sync = SAI_SYNC_EXTERNAL; 1592 1593 ··· 1596 1595 (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) { 1597 1596 dev_err(&pdev->dev, "Wrong SAI index\n"); 1598 1597 of_node_put(args.np); 1599 - return -EINVAL; 1598 + ret = -EINVAL; 1599 + goto err_put_sync_provider; 1600 1600 } 1601 1601 1602 1602 if (of_property_match_string(args.np, "compatible", ··· 1611 1609 if (!sai->synco) { 1612 1610 dev_err(&pdev->dev, "Unknown SAI sub-block\n"); 1613 1611 of_node_put(args.np); 1614 - return -EINVAL; 1612 + ret = -EINVAL; 1613 + goto err_put_sync_provider; 1615 1614 } 1616 1615 } 1617 1616 ··· 1622 1619 1623 1620 of_node_put(args.np); 1624 1621 sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); 1625 - if (IS_ERR(sai->sai_ck)) 1626 - return dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), 1627 - "Missing kernel clock sai_ck\n"); 1622 + if (IS_ERR(sai->sai_ck)) { 1623 + ret = dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), 1624 + "Missing kernel clock sai_ck\n"); 1625 + goto err_put_sync_provider; 1626 + } 1628 1627 1629 1628 ret = clk_prepare(sai->pdata->pclk); 1630 1629 if (ret < 0) 1631 - return ret; 1630 + goto err_put_sync_provider; 1632 1631 1633 1632 if (STM_SAI_IS_F4(sai->pdata)) 1634 1633 return 0; ··· 1652 1647 1653 1648 err_unprepare_pclk: 1654 1649 clk_unprepare(sai->pdata->pclk); 1650 + err_put_sync_provider: 1651 + of_node_put(sai->np_sync_provider); 1655 1652 1656 1653 return ret; 1657 1654 } ··· 1727 1720 1728 1721 err_unprepare_pclk: 1729 1722 clk_unprepare(sai->pdata->pclk); 1723 + of_node_put(sai->np_sync_provider); 1730 1724 1731 1725 return ret; 1732 1726 } ··· 1740 1732 snd_dmaengine_pcm_unregister(&pdev->dev); 1741 1733 snd_soc_unregister_component(&pdev->dev); 1742 1734 pm_runtime_disable(&pdev->dev); 1735 + of_node_put(sai->np_sync_provider); 1743 1736 } 1744 1737 1745 1738 static int stm32_sai_sub_suspend(struct device *dev)