[PATCH v1 2/2] ASoC: amd: acp3x-es83xx: Keep an owned codec device reference

From: Yibo Tan

Date: Sat Sep 19 2026 - 08:14:02 EST


acpi_get_first_physical_node() returns a borrowed device pointer. The
private data allocation failure path in acp3x_es83xx_probe() puts that
pointer despite not owning a reference. The successful path also saves the
borrowed pointer for later card operations.

This was reproduced on current mainline with failslab restricted to the
real static callback. The rejected devm_kzalloc() returned -ENOMEM, and
normal codec platform-device unregister then produced a KASAN
slab-use-after-free in device_del(), with allocation in
acpi_create_platform_device() and release in acpi_unbind_one().

Use acpi_bus_get_primary_device() to acquire the reference while the
physical-node lock is held. After allocating private data, register a
devres put action before publishing the pointer. This balances action
allocation and later probe failures, keeps the saved pointer alive during
card use, and drops the credit after ASoC card unregister during successful
teardown. The existing OOM put now correctly balances the owned lookup.

The same filtered KASAN guest with this change reached the same -ENOMEM and
unregister path without KASAN, WARNING, Oops or panic. The test directly
invoked the production callback and did not emulate a complete ACP/ASoC
card or physical Huawei hardware.

Fixes: 54fcd9dd44b2 ("ASoC: amd: acp: Add machine driver that enables sound for systems with a ES8336 codec")
Assisted-by: LLM
Signed-off-by: Yibo Tan <lhfff@xxxxxxxxxx>
---
sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
index 3a640e652314..568142b6d115 100644
--- a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
+++ b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
@@ -41,6 +41,11 @@ struct acp3x_es83xx_private {
struct snd_soc_dapm_route mic_map[2];
};

+static void acp3x_es83xx_put_codec_device(void *data)
+{
+ put_device(data);
+}
+
static const unsigned int channels[] = {
DUAL_CHANNEL,
};
@@ -428,7 +433,7 @@ static int acp3x_es83xx_probe(struct snd_soc_card *card)
return -ENXIO;
}

- codec_dev = acpi_get_first_physical_node(adev);
+ codec_dev = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!codec_dev) {
dev_warn(dev, "Error cannot find codec device, will defer probe\n");
@@ -441,6 +446,12 @@ static int acp3x_es83xx_probe(struct snd_soc_card *card)
return -ENOMEM;
}

+ ret = devm_add_action_or_reset(dev,
+ acp3x_es83xx_put_codec_device,
+ codec_dev);
+ if (ret)
+ return ret;
+
priv->codec_dev = codec_dev;
priv->quirk = (unsigned long)dmi_id->driver_data;
acp_drvdata->mach_priv = priv;
--
2.39.5