[PATCH v2] ALSA: hda: cs35l41: Fix ACPI device reference leak on probe failure
From: Ma Ke
Date: Sun Oct 11 2026 - 07:43:58 EST
cs35l41_hda_probe() takes an acpi_device through
cs35l41_hda_read_acpi() and stores it in cs35l41->dacpi. It is
released in the err: label, which
is reached from every later failure.
One failure is not routed there:
ret = cs35l41_hda_read_acpi(cs35l41, device_name, id);
if (ret)
return dev_err_probe(cs35l41->dev, ret, "...");
cs35l41->acpi_subsystem_id is allocated inside cs35l41_hda_read_acpi()
before that point, so it is leaked whenever the function fails.
Route the failure through a new err_acpi label that releases it.
That label must not release cs35l41->dacpi a second time. Every
failure path in cs35l41_hda_read_acpi() that can be taken after the
assignment already drops that reference: cs35l41_hda_parse_acpi() does
so in its own err: label, and the !physdev path does it directly.
Clear cs35l41->dacpi wherever it is dropped, so the pointer never
outlives the reference and the put in err_acpi is a no-op on those
paths.
Found by code review.
Fixes: 447106e92a0c ("ALSA: hda: cs35l41: Support mute notifications for CS35L41 HDA")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Ma Ke <make_ruc2021@xxxxxxx>
---
Changes in v2:
- v1 released cs35l41->dacpi from the new err_acpi label, but
cs35l41_hda_parse_acpi() already drops that reference in its own err:
label, so the reference would have been dropped a second time. Clear
cs35l41->dacpi there as well, not only on the !physdev path.
Reported by Sashiko; thanks to Takashi Iwai for pointing it out.
- The leak being fixed and the diff are otherwise unchanged from v1.
---
sound/hda/codecs/side-codecs/cs35l41_hda.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c
index 62296be45c55..3a8e04f73f79 100644
--- a/sound/hda/codecs/side-codecs/cs35l41_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c
@@ -1908,6 +1908,7 @@ int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev,
hw_cfg->gpio1.valid = false;
hw_cfg->gpio2.valid = false;
acpi_dev_put(cs35l41->dacpi);
+ cs35l41->dacpi = NULL;
return ret;
}
@@ -1929,6 +1930,7 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
struct device *physdev __free(put_device) =
get_device(acpi_get_first_physical_node(adev));
if (!physdev) {
+ cs35l41->dacpi = NULL;
acpi_dev_put(adev);
return -ENODEV;
}
@@ -1986,8 +1988,10 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
dev_set_drvdata(dev, cs35l41);
ret = cs35l41_hda_read_acpi(cs35l41, device_name, id);
- if (ret)
- return dev_err_probe(cs35l41->dev, ret, "Platform not supported\n");
+ if (ret) {
+ dev_err_probe(cs35l41->dev, ret, "Platform not supported\n");
+ goto err_acpi;
+ }
if (IS_ERR(cs35l41->reset_gpio)) {
ret = PTR_ERR(cs35l41->reset_gpio);
@@ -2066,6 +2070,12 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
return 0;
+err_acpi:
+ acpi_dev_put(cs35l41->dacpi);
+ kfree(cs35l41->acpi_subsystem_id);
+
+ return ret;
+
err_pm:
pm_runtime_dont_use_autosuspend(cs35l41->dev);
pm_runtime_disable(cs35l41->dev);
--
2.43.0