[PATCH] soc: mediatek: SVS: fix device reference leak in svs_add_device_link()
From: Coia Prant
Date: Fri Oct 23 2026 - 04:30:16 EST
svs_add_device_link() calls svs_get_subsys_device(), which returns a
device with a reference taken by of_find_device_by_node(). If either of
the subsequent checks fails, the function returns an error pointer
without dropping that reference, and the caller only checks IS_ERR() and
bails out, so the reference is leaked on every -EPROBE_DEFER.
Both error paths can be hit in practice: device_link_add() returns NULL
when the link would create a reverse dependency or on allocation
failure, and the supplier status check fails whenever the supplier has
not bound yet.
Drop the reference before returning on both paths.
While at it, note that the return value of device_link_add() is only
used to detect failure. Managed links are owned by the driver core, so
the driver must not keep or dereference the struct device_link pointer
to inspect the supplier state; read dev->links.status directly instead.
Fixes: 681a02e95000 ("soc: mediatek: SVS: introduce MTK SVS engine")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Coia Prant <coiaprant@xxxxxxxxx>
---
drivers/soc/mediatek/mtk-svs.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
index 99edecb204f25..fecb09b9185c2 100644
--- a/drivers/soc/mediatek/mtk-svs.c
+++ b/drivers/soc/mediatek/mtk-svs.c
@@ -2145,21 +2145,21 @@ static struct device *svs_add_device_link(struct svs_platform *svsp,
const char *node_name)
{
struct device *dev;
- struct device_link *sup_link;
dev = svs_get_subsys_device(svsp, node_name);
if (IS_ERR(dev))
return dev;
- sup_link = device_link_add(svsp->dev, dev,
- DL_FLAG_AUTOREMOVE_CONSUMER);
- if (!sup_link) {
- dev_err(svsp->dev, "sup_link is NULL\n");
+ if (!device_link_add(svsp->dev, dev, DL_FLAG_AUTOREMOVE_CONSUMER)) {
+ dev_err(svsp->dev, "device_link_add returns NULL\n");
+ put_device(dev);
return ERR_PTR(-EINVAL);
}
- if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
+ if (READ_ONCE(dev->links.status) != DL_DEV_DRIVER_BOUND) {
+ put_device(dev);
return ERR_PTR(-EPROBE_DEFER);
+ }
return dev;
}
--
2.47.3