Merge: CVE-2025-21739 kernel: scsi: ufs: core: Fix use-after free in init error and remove paths
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6575 Backport upstream commit `f8fb2403ddeb` ("scsi: ufs: core: Fix use-after free in init error and remove paths") to fix CVE-2025-21739, pulling in [this](https://lore.kernel.org/all/20241111-ufs_bug_fix-v1-0-45ad8b62f02e@linaro.org/) series, as well as [this](https://lore.kernel.org/r/20230917145722.1131557-1-u.kleine-koenig@pengutronix.de) patch to minimize conflicts. JIRA: https://issues.redhat.com/browse/RHEL-84800 CVE: CVE-2025-21739 Signed-off-by: Jared Kangas <jkangas@redhat.com> Approved-by: Radu Rendec <rrendec@redhat.com> Approved-by: Eric Chanudet <echanude@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Jarod Wilson <jarod@redhat.com>
This commit is contained in:
commit
ae39b57b1f
|
@ -10293,16 +10293,6 @@ int ufshcd_system_thaw(struct device *dev)
|
|||
EXPORT_SYMBOL_GPL(ufshcd_system_thaw);
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
/**
|
||||
* ufshcd_dealloc_host - deallocate Host Bus Adapter (HBA)
|
||||
* @hba: pointer to Host Bus Adapter (HBA)
|
||||
*/
|
||||
void ufshcd_dealloc_host(struct ufs_hba *hba)
|
||||
{
|
||||
scsi_host_put(hba->host);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ufshcd_dealloc_host);
|
||||
|
||||
/**
|
||||
* ufshcd_set_dma_mask - Set dma mask based on the controller
|
||||
* addressing capability
|
||||
|
@ -10319,12 +10309,26 @@ static int ufshcd_set_dma_mask(struct ufs_hba *hba)
|
|||
return dma_set_mask_and_coherent(hba->dev, DMA_BIT_MASK(32));
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_devres_release - devres cleanup handler, invoked during release of
|
||||
* hba->dev
|
||||
* @host: pointer to SCSI host
|
||||
*/
|
||||
static void ufshcd_devres_release(void *host)
|
||||
{
|
||||
scsi_host_put(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_alloc_host - allocate Host Bus Adapter (HBA)
|
||||
* @dev: pointer to device handle
|
||||
* @hba_handle: driver private handle
|
||||
*
|
||||
* Return: 0 on success, non-zero value on failure.
|
||||
*
|
||||
* NOTE: There is no corresponding ufshcd_dealloc_host() because this function
|
||||
* keeps track of its allocations using devres and deallocates everything on
|
||||
* device removal automatically.
|
||||
*/
|
||||
int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle)
|
||||
{
|
||||
|
@ -10346,6 +10350,13 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle)
|
|||
err = -ENOMEM;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
err = devm_add_action_or_reset(dev, ufshcd_devres_release,
|
||||
host);
|
||||
if (err)
|
||||
return dev_err_probe(dev, err,
|
||||
"failed to add ufshcd dealloc action\n");
|
||||
|
||||
host->nr_maps = HCTX_TYPE_POLL + 1;
|
||||
hba = shost_priv(host);
|
||||
hba->host = host;
|
||||
|
|
|
@ -305,12 +305,9 @@ static int cdns_ufs_pltfrm_probe(struct platform_device *pdev)
|
|||
*
|
||||
* Return: 0 (success).
|
||||
*/
|
||||
static int cdns_ufs_pltfrm_remove(struct platform_device *pdev)
|
||||
static void cdns_ufs_pltfrm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
|
||||
ufshcd_remove(hba);
|
||||
return 0;
|
||||
ufshcd_pltfrm_remove(pdev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
|
||||
|
@ -322,7 +319,7 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
|
|||
|
||||
static struct platform_driver cdns_ufs_pltfrm_driver = {
|
||||
.probe = cdns_ufs_pltfrm_probe,
|
||||
.remove = cdns_ufs_pltfrm_remove,
|
||||
.remove_new = cdns_ufs_pltfrm_remove,
|
||||
.driver = {
|
||||
.name = "cdns-ufshcd",
|
||||
.pm = &cdns_ufs_dev_pm_ops,
|
||||
|
|
|
@ -74,14 +74,9 @@ static int tc_dwc_g210_pltfm_probe(struct platform_device *pdev)
|
|||
* @pdev: pointer to platform device structure
|
||||
*
|
||||
*/
|
||||
static int tc_dwc_g210_pltfm_remove(struct platform_device *pdev)
|
||||
static void tc_dwc_g210_pltfm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&(pdev)->dev);
|
||||
ufshcd_remove(hba);
|
||||
|
||||
return 0;
|
||||
ufshcd_pltfrm_remove(pdev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tc_dwc_g210_pltfm_pm_ops = {
|
||||
|
@ -91,7 +86,7 @@ static const struct dev_pm_ops tc_dwc_g210_pltfm_pm_ops = {
|
|||
|
||||
static struct platform_driver tc_dwc_g210_pltfm_driver = {
|
||||
.probe = tc_dwc_g210_pltfm_probe,
|
||||
.remove = tc_dwc_g210_pltfm_remove,
|
||||
.remove_new = tc_dwc_g210_pltfm_remove,
|
||||
.driver = {
|
||||
.name = "tc-dwc-g210-pltfm",
|
||||
.pm = &tc_dwc_g210_pltfm_pm_ops,
|
||||
|
|
|
@ -65,13 +65,11 @@ disable_pm:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ti_j721e_ufs_remove(struct platform_device *pdev)
|
||||
static void ti_j721e_ufs_remove(struct platform_device *pdev)
|
||||
{
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ti_j721e_ufs_of_match[] = {
|
||||
|
@ -85,7 +83,7 @@ MODULE_DEVICE_TABLE(of, ti_j721e_ufs_of_match);
|
|||
|
||||
static struct platform_driver ti_j721e_ufs_driver = {
|
||||
.probe = ti_j721e_ufs_probe,
|
||||
.remove = ti_j721e_ufs_remove,
|
||||
.remove_new = ti_j721e_ufs_remove,
|
||||
.driver = {
|
||||
.name = "ti-j721e-ufs",
|
||||
.of_match_table = ti_j721e_ufs_of_match,
|
||||
|
|
|
@ -1606,18 +1606,15 @@ static int exynos_ufs_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int exynos_ufs_remove(struct platform_device *pdev)
|
||||
static void exynos_ufs_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
|
||||
|
||||
pm_runtime_get_sync(&(pdev)->dev);
|
||||
ufshcd_remove(hba);
|
||||
ufshcd_pltfrm_remove(pdev);
|
||||
|
||||
phy_power_off(ufs->phy);
|
||||
phy_exit(ufs->phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct exynos_ufs_uic_attr exynos7_uic_attr = {
|
||||
|
@ -1756,7 +1753,7 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
|
|||
|
||||
static struct platform_driver exynos_ufs_pltform = {
|
||||
.probe = exynos_ufs_probe,
|
||||
.remove = exynos_ufs_remove,
|
||||
.remove_new = exynos_ufs_remove,
|
||||
.driver = {
|
||||
.name = "exynos-ufshc",
|
||||
.pm = &exynos_ufs_pm_ops,
|
||||
|
|
|
@ -574,12 +574,9 @@ static int ufs_hisi_probe(struct platform_device *pdev)
|
|||
return ufshcd_pltfrm_init(pdev, of_id->data);
|
||||
}
|
||||
|
||||
static int ufs_hisi_remove(struct platform_device *pdev)
|
||||
static void ufs_hisi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
|
||||
ufshcd_remove(hba);
|
||||
return 0;
|
||||
ufshcd_pltfrm_remove(pdev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ufs_hisi_pm_ops = {
|
||||
|
@ -591,7 +588,7 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = {
|
|||
|
||||
static struct platform_driver ufs_hisi_pltform = {
|
||||
.probe = ufs_hisi_probe,
|
||||
.remove = ufs_hisi_remove,
|
||||
.remove_new = ufs_hisi_remove,
|
||||
.driver = {
|
||||
.name = "ufshcd-hisi",
|
||||
.pm = &ufs_hisi_pm_ops,
|
||||
|
|
|
@ -1731,13 +1731,9 @@ out:
|
|||
*
|
||||
* Always return 0
|
||||
*/
|
||||
static int ufs_mtk_remove(struct platform_device *pdev)
|
||||
static void ufs_mtk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&(pdev)->dev);
|
||||
ufshcd_remove(hba);
|
||||
return 0;
|
||||
ufshcd_pltfrm_remove(pdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -1801,7 +1797,7 @@ static const struct dev_pm_ops ufs_mtk_pm_ops = {
|
|||
|
||||
static struct platform_driver ufs_mtk_pltform = {
|
||||
.probe = ufs_mtk_probe,
|
||||
.remove = ufs_mtk_remove,
|
||||
.remove_new = ufs_mtk_remove,
|
||||
.driver = {
|
||||
.name = "ufshcd-mtk",
|
||||
.pm = &ufs_mtk_pm_ops,
|
||||
|
|
|
@ -2090,14 +2090,14 @@ static int ufs_qcom_probe(struct platform_device *pdev)
|
|||
*
|
||||
* Always returns 0
|
||||
*/
|
||||
static int ufs_qcom_remove(struct platform_device *pdev)
|
||||
static void ufs_qcom_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||
|
||||
pm_runtime_get_sync(&(pdev)->dev);
|
||||
ufshcd_remove(hba);
|
||||
platform_msi_domain_free_irqs(hba->dev);
|
||||
return 0;
|
||||
ufshcd_pltfrm_remove(pdev);
|
||||
if (host->esi_enabled)
|
||||
platform_msi_domain_free_irqs(hba->dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id ufs_qcom_of_match[] = {
|
||||
|
@ -2129,7 +2129,7 @@ static const struct dev_pm_ops ufs_qcom_pm_ops = {
|
|||
|
||||
static struct platform_driver ufs_qcom_pltform = {
|
||||
.probe = ufs_qcom_probe,
|
||||
.remove = ufs_qcom_remove,
|
||||
.remove_new = ufs_qcom_remove,
|
||||
.driver = {
|
||||
.name = "ufshcd-qcom",
|
||||
.pm = &ufs_qcom_pm_ops,
|
||||
|
|
|
@ -388,18 +388,14 @@ static int ufs_renesas_probe(struct platform_device *pdev)
|
|||
return ufshcd_pltfrm_init(pdev, &ufs_renesas_vops);
|
||||
}
|
||||
|
||||
static int ufs_renesas_remove(struct platform_device *pdev)
|
||||
static void ufs_renesas_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
|
||||
ufshcd_remove(hba);
|
||||
|
||||
return 0;
|
||||
ufshcd_pltfrm_remove(pdev);
|
||||
}
|
||||
|
||||
static struct platform_driver ufs_renesas_platform = {
|
||||
.probe = ufs_renesas_probe,
|
||||
.remove = ufs_renesas_remove,
|
||||
.remove_new = ufs_renesas_remove,
|
||||
.driver = {
|
||||
.name = "ufshcd-renesas",
|
||||
.of_match_table = of_match_ptr(ufs_renesas_of_match),
|
||||
|
|
|
@ -425,13 +425,9 @@ static int ufs_sprd_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ufs_sprd_remove(struct platform_device *pdev)
|
||||
static void ufs_sprd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&(pdev)->dev);
|
||||
ufshcd_remove(hba);
|
||||
return 0;
|
||||
ufshcd_pltfrm_remove(pdev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ufs_sprd_pm_ops = {
|
||||
|
@ -443,7 +439,7 @@ static const struct dev_pm_ops ufs_sprd_pm_ops = {
|
|||
|
||||
static struct platform_driver ufs_sprd_pltform = {
|
||||
.probe = ufs_sprd_probe,
|
||||
.remove = ufs_sprd_remove,
|
||||
.remove_new = ufs_sprd_remove,
|
||||
.driver = {
|
||||
.name = "ufshcd-sprd",
|
||||
.pm = &ufs_sprd_pm_ops,
|
||||
|
|
|
@ -516,7 +516,6 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
|
|||
pm_runtime_forbid(&pdev->dev);
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
ufshcd_remove(hba);
|
||||
ufshcd_dealloc_host(hba);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -561,7 +560,6 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
err = ufshcd_init(hba, mmio_base, pdev->irq);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Initialization failed\n");
|
||||
ufshcd_dealloc_host(hba);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -464,21 +464,17 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
|
|||
struct device *dev = &pdev->dev;
|
||||
|
||||
mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mmio_base)) {
|
||||
err = PTR_ERR(mmio_base);
|
||||
goto out;
|
||||
}
|
||||
if (IS_ERR(mmio_base))
|
||||
return PTR_ERR(mmio_base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
err = irq;
|
||||
goto out;
|
||||
}
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
err = ufshcd_alloc_host(dev, &hba);
|
||||
if (err) {
|
||||
dev_err(dev, "Allocation failed\n");
|
||||
goto out;
|
||||
return err;
|
||||
}
|
||||
|
||||
hba->vops = vops;
|
||||
|
@ -487,13 +483,13 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
|
|||
if (err) {
|
||||
dev_err(dev, "%s: clock parse failed %d\n",
|
||||
__func__, err);
|
||||
goto dealloc_host;
|
||||
return err;
|
||||
}
|
||||
err = ufshcd_parse_regulator_info(hba);
|
||||
if (err) {
|
||||
dev_err(dev, "%s: regulator init failed %d\n",
|
||||
__func__, err);
|
||||
goto dealloc_host;
|
||||
return err;
|
||||
}
|
||||
|
||||
ufshcd_init_lanes_per_dir(hba);
|
||||
|
@ -501,28 +497,38 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
|
|||
err = ufshcd_parse_operating_points(hba);
|
||||
if (err) {
|
||||
dev_err(dev, "%s: OPP parse failed %d\n", __func__, err);
|
||||
goto dealloc_host;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ufshcd_init(hba, mmio_base, irq);
|
||||
if (err) {
|
||||
dev_err_probe(dev, err, "Initialization failed with error %d\n",
|
||||
err);
|
||||
goto dealloc_host;
|
||||
return err;
|
||||
}
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
dealloc_host:
|
||||
ufshcd_dealloc_host(hba);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
|
||||
|
||||
/**
|
||||
* ufshcd_pltfrm_remove - Remove ufshcd platform
|
||||
* @pdev: pointer to Platform device handle
|
||||
*/
|
||||
void ufshcd_pltfrm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
ufshcd_remove(hba);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ufshcd_pltfrm_remove);
|
||||
|
||||
MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
|
||||
MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
|
||||
MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver");
|
||||
|
|
|
@ -31,6 +31,7 @@ int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params,
|
|||
void ufshcd_init_host_params(struct ufs_host_params *host_params);
|
||||
int ufshcd_pltfrm_init(struct platform_device *pdev,
|
||||
const struct ufs_hba_variant_ops *vops);
|
||||
void ufshcd_pltfrm_remove(struct platform_device *pdev);
|
||||
int ufshcd_populate_vreg(struct device *dev, const char *name,
|
||||
struct ufs_vreg **out_vreg);
|
||||
|
||||
|
|
|
@ -1297,7 +1297,6 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
|
|||
}
|
||||
|
||||
int ufshcd_alloc_host(struct device *, struct ufs_hba **);
|
||||
void ufshcd_dealloc_host(struct ufs_hba *);
|
||||
int ufshcd_hba_enable(struct ufs_hba *hba);
|
||||
int ufshcd_init(struct ufs_hba *, void __iomem *, unsigned int);
|
||||
int ufshcd_link_recovery(struct ufs_hba *hba);
|
||||
|
|
Loading…
Reference in New Issue