drivers/soc/qcom/ice.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
qcom_ice_probe() stores probe failures in ice_handles so that
of_qcom_ice_get() can distinguish between an ICE device that has not
probed yet and one that has failed permanently.
However, the failure paths store raw ERR_PTR() values in the XArray.
XArray entries use low pointer bits for internal encodings, so some
ERR_PTR() values can be interpreted as internal entries. For example,
ERR_PTR(-EINVAL) has the internal-node bit pattern and may be treated as
an xa_node by xa_load(), causing xas_load() to dereference an invalid
pointer before of_qcom_ice_get() reaches IS_ERR_OR_NULL().
Store probe failures as xa_mk_value() encoded errno values instead, and
convert them back to ERR_PTR() values when loading them from the XArray.
Fixes: d922113ef91e ("soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get()")
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
---
drivers/soc/qcom/ice.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
index 5f20108aa03e..bc77dce971a6 100644
--- a/drivers/soc/qcom/ice.c
+++ b/drivers/soc/qcom/ice.c
@@ -667,12 +667,12 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
}
ice = xa_load(&ice_handles, pdev->dev.of_node->phandle);
- if (IS_ERR_OR_NULL(ice)) {
+ if (!ice || xa_is_value(ice)) {
platform_device_put(pdev);
if (!ice)
return ERR_PTR(-EPROBE_DEFER);
else
- return ice;
+ return ERR_PTR(-(long)xa_to_value(ice));
}
link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
@@ -744,15 +744,17 @@ static int qcom_ice_probe(struct platform_device *pdev)
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base)) {
dev_warn(&pdev->dev, "ICE registers not found\n");
- /* Store the error pointer for devm_of_qcom_ice_get() */
- xa_store(&ice_handles, phandle, (__force void *)base, GFP_KERNEL);
+ /* Store the error code for devm_of_qcom_ice_get() */
+ xa_store(&ice_handles, phandle,
+ xa_mk_value(-PTR_ERR(base)), GFP_KERNEL);
return PTR_ERR(base);
}
engine = qcom_ice_create(&pdev->dev, base);
if (IS_ERR(engine)) {
- /* Store the error pointer for devm_of_qcom_ice_get() */
- xa_store(&ice_handles, phandle, engine, GFP_KERNEL);
+ /* Store the error code for devm_of_qcom_ice_get() */
+ xa_store(&ice_handles, phandle,
+ xa_mk_value(-PTR_ERR(engine)), GFP_KERNEL);
return PTR_ERR(engine);
}
--
2.43.0
© 2016 - 2026 Red Hat, Inc.