[PATCH v1 1/2] ASoC: amd: acp-es8336: Use an owned codec device reference

From: Yibo Tan

Date: Sat Sep 19 2026 - 08:13:56 EST


acpi_get_first_physical_node() returns a borrowed device pointer. If the
pa-enable GPIO lookup fails, st_es8336_late_probe() puts that pointer
despite not owning a reference. A later physical-node teardown can then
release the device while device_del() is still using it.

This was reproduced on current mainline with the real static late-probe
callback and normal platform-device unregister. The GPIO lookup returned
-EPROBE_DEFER and KASAN reported a slab-use-after-free in device_del(),
with the object freed by acpi_unbind_one().

Use acpi_bus_get_primary_device(), which obtains a stable device
reference under the physical-node lock, and release it at callback exit
with scoped cleanup. Keep the reference callback-local because late probe
can be retried; registering one devres action per attempt would accumulate
references.

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

Fixes: 02527c3f2300 ("ASoC: amd: add Machine driver for Jadeite platform")
Assisted-by: LLM
Signed-off-by: Yibo Tan <lhfff@xxxxxxxxxx>
---
sound/soc/amd/acp-es8336.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/sound/soc/amd/acp-es8336.c b/sound/soc/amd/acp-es8336.c
index 9f3f11256788..0cb0ee76191d 100644
--- a/sound/soc/amd/acp-es8336.c
+++ b/sound/soc/amd/acp-es8336.c
@@ -30,7 +30,6 @@

static unsigned long acp2x_machine_id;
static struct snd_soc_jack st_jack;
-static struct device *codec_dev;
static struct gpio_desc *gpio_pa;

static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
@@ -191,6 +190,7 @@ static const struct acpi_gpio_mapping acpi_es8336_gpios[] = {

static int st_es8336_late_probe(struct snd_soc_card *card)
{
+ struct device *codec_dev __free(put_device) = NULL;
struct acpi_device *adev;
int ret;

@@ -198,7 +198,7 @@ static int st_es8336_late_probe(struct snd_soc_card *card)
if (!adev)
return -ENODEV;

- codec_dev = acpi_get_first_physical_node(adev);
+ codec_dev = acpi_bus_get_primary_device(adev);
acpi_dev_put(adev);
if (!codec_dev) {
dev_err(card->dev, "can not find codec dev\n");
@@ -213,7 +213,6 @@ static int st_es8336_late_probe(struct snd_soc_card *card)
if (IS_ERR(gpio_pa)) {
ret = dev_err_probe(card->dev, PTR_ERR(gpio_pa),
"could not get pa-enable GPIO\n");
- put_device(codec_dev);
return ret;
}
return 0;
--
2.39.5