[PATCH v2 2/5] ALSA: hda: Disable unsol event handling at error and shutdown paths

From: Takashi Iwai

Date: Fri Oct 09 2026 - 09:34:05 EST


When the HD-audio controller driver probe fails, it still leaves the
unsolicited event handling and jackpoll work active, hence if they are
pending, they might fire up later after the resource gets released,
which may lead to a UAF. A similar problem may be seen at shutdown,
too.

Add the recently added helper to disable unsol events and the cancel
of jackpoll_work at the appropriate places. We need the workaround in
the error path before driver->ops->remove, too. As unsol events and
jack polling may have been already enabled during the probe callback,
the driver->ops->remove call is done (more) conditionally now.

Fixes: c3ec8ac82105 ("ASoC: hdac_hda: fix memleak on module unload")
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>
---
v1->v2: apply the workaround in the wider error path

sound/hda/common/bind.c | 8 ++++++--
sound/hda/common/codec.c | 1 +
2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/sound/hda/common/bind.c b/sound/hda/common/bind.c
index 4772ca154a29..d12359970e74 100644
--- a/sound/hda/common/bind.c
+++ b/sound/hda/common/bind.c
@@ -89,6 +89,7 @@ static int hda_codec_driver_probe(struct device *dev)
struct hda_codec *codec = dev_to_hda_codec(dev);
struct module *owner = dev->driver->owner;
struct hda_codec_driver *driver = hda_codec_to_driver(codec);
+ bool probed = false;
int err;

if (codec->bus->core.ext_ops) {
@@ -122,7 +123,8 @@ static int hda_codec_driver_probe(struct device *dev)

err = driver->ops->probe(codec, codec->preset);
if (err < 0)
- goto error_module_put;
+ goto error_module;
+ probed = true;
err = snd_hda_codec_build_pcms(codec);
if (err < 0)
goto error_module;
@@ -141,7 +143,9 @@ static int hda_codec_driver_probe(struct device *dev)
return 0;

error_module:
- if (driver->ops->remove)
+ snd_hdac_device_disable_unsol(&codec->core);
+ cancel_delayed_work_sync(&codec->jackpoll_work);
+ if (probed && driver->ops->remove)
driver->ops->remove(codec);
error_module_put:
module_put(owner);
diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c
index c99fe61c29db..94da4f3a21ed 100644
--- a/sound/hda/common/codec.c
+++ b/sound/hda/common/codec.c
@@ -3039,6 +3039,7 @@ void snd_hda_codec_shutdown(struct hda_codec *codec)

codec->jackpoll_interval = 0; /* don't poll any longer */
cancel_delayed_work_sync(&codec->jackpoll_work);
+ snd_hdac_device_disable_unsol(&codec->core);
list_for_each_entry(cpcm, &codec->pcm_list_head, list)
snd_pcm_suspend_all(cpcm->pcm);

--
2.55.0