From: Johan Hovold johan+linaro@kernel.org
commit c9e46ca612cfbb0cf890f7ae7389b742e90efe64 upstream.
The current interconnect provider registration interface is inherently racy as nodes are not added until the after adding the provider. This can specifically cause racing DT lookups to trigger a NULL-pointer deference when either a NULL pointer or not fully initialised node is returned from exynos_generic_icc_xlate().
Switch to using the new API where the provider is not registered until after it has been fully initialised.
Fixes: 2f95b9d5cf0b ("interconnect: Add generic interconnect driver for Exynos SoCs") Cc: stable@vger.kernel.org # 5.11 Cc: Sylwester Nawrocki s.nawrocki@samsung.com Reviewed-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Signed-off-by: Johan Hovold johan+linaro@kernel.org Link: https://lore.kernel.org/r/20230306075651.2449-16-johan+linaro@kernel.org Signed-off-by: Georgi Djakov djakov@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/interconnect/samsung/exynos.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
--- a/drivers/interconnect/samsung/exynos.c +++ b/drivers/interconnect/samsung/exynos.c @@ -98,12 +98,13 @@ static int exynos_generic_icc_remove(str struct exynos_icc_priv *priv = platform_get_drvdata(pdev); struct icc_node *parent_node, *node = priv->node;
+ icc_provider_deregister(&priv->provider); + parent_node = exynos_icc_get_parent(priv->dev->parent->of_node); if (parent_node && !IS_ERR(parent_node)) icc_link_destroy(node, parent_node);
icc_nodes_remove(&priv->provider); - icc_provider_del(&priv->provider);
return 0; } @@ -132,15 +133,11 @@ static int exynos_generic_icc_probe(stru provider->inter_set = true; provider->data = priv;
- ret = icc_provider_add(provider); - if (ret < 0) - return ret; + icc_provider_init(provider);
icc_node = icc_node_create(pdev->id); - if (IS_ERR(icc_node)) { - ret = PTR_ERR(icc_node); - goto err_prov_del; - } + if (IS_ERR(icc_node)) + return PTR_ERR(icc_node);
priv->node = icc_node; icc_node->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOFn", @@ -171,14 +168,17 @@ static int exynos_generic_icc_probe(stru goto err_pmqos_del; }
+ ret = icc_provider_register(provider); + if (ret < 0) + goto err_pmqos_del; + return 0;
err_pmqos_del: dev_pm_qos_remove_request(&priv->qos_req); err_node_del: icc_nodes_remove(provider); -err_prov_del: - icc_provider_del(provider); + return ret; }