]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ALSA: hda/intel: Make sure to cancel irq-pending work at closing PCM stream
authorTakashi Iwai <tiwai@suse.de>
Tue, 19 May 2026 12:11:53 +0000 (14:11 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 20 May 2026 05:50:45 +0000 (07:50 +0200)
The pending irq work might be still floating while the assigned stream
has been already closed, which may lead to UAF, especially when
another async work for fasync is involved.

For addressing this, extend the hda_controller_ops for allowing the
extra cleanup procedure that is specific to the controller driver, and
make sure to cancel and sync the pending irq work at each PCM close
before releasing the resources.

Reported-by: Jake Lamberson <lamberson.jake@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20260519121157.28477-2-tiwai@suse.de
sound/hda/common/controller.c
sound/hda/common/hda_controller.h
sound/hda/controllers/intel.c

index 89e63a53d6830a9ffd7c0cc4cd4b65010480435e..a847546753db9f8dcaa32665f0d673fb18ef5290 100644 (file)
@@ -97,6 +97,8 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
 
        trace_azx_pcm_close(chip, azx_dev);
        scoped_guard(mutex, &chip->open_mutex) {
+               if (chip->ops->pcm_close)
+                       chip->ops->pcm_close(chip, azx_dev);
                azx_release_device(azx_dev);
                if (hinfo->ops.close)
                        hinfo->ops.close(hinfo, apcm->codec, substream);
index bc8ee4cc24011143b9cf8eddd05d5a172108f603..38227f82e7040d881968add042e2f9236907ba00 100644 (file)
@@ -78,6 +78,8 @@ struct hda_controller_ops {
        int (*position_check)(struct azx *chip, struct azx_dev *azx_dev);
        /* enable/disable the link power */
        int (*link_power)(struct azx *chip, bool enable);
+       /* additional hook for PCM */
+       void (*pcm_close)(struct azx *chip, struct azx_dev *azx_dev);
 };
 
 struct azx_pcm {
index 01477bd4fcb9b9ddfb2811b84e1c9457ef081bf9..4b03c64e72ab48a53b8b9cdc3c3048e7b8f5fc84 100644 (file)
@@ -761,16 +761,27 @@ static void azx_irq_pending_work(struct work_struct *work)
 }
 
 /* clear irq_pending flags and assure no on-going workq */
+static void hda_intel_stream_clear_irq_pending(struct azx_dev *azx_dev)
+{
+       struct hda_intel_stream *istream = azx_dev_to_istream(azx_dev);
+
+       istream->irq_pending = false;
+       cancel_work_sync(&istream->irq_pending_work);
+}
+
+/* called at PCM close */
+static void hda_intel_pcm_close(struct azx *chip, struct azx_dev *azx_dev)
+{
+       hda_intel_stream_clear_irq_pending(azx_dev);
+}
+
 static void azx_clear_irq_pending(struct azx *chip)
 {
        struct hdac_bus *bus = azx_bus(chip);
        struct hdac_stream *s;
 
        list_for_each_entry(s, &bus->stream_list, list) {
-               struct azx_dev *azx_dev = stream_to_azx_dev(s);
-               struct hda_intel_stream *istream = azx_dev_to_istream(azx_dev);
-               istream->irq_pending = false;
-               cancel_work_sync(&istream->irq_pending_work);
+               hda_intel_stream_clear_irq_pending(stream_to_azx_dev(s));
        }
 }
 
@@ -2131,6 +2142,7 @@ static const struct dmi_system_id driver_denylist_dmi[] = {
 static const struct hda_controller_ops pci_hda_ops = {
        .disable_msi_reset_irq = disable_msi_reset_irq,
        .position_check = azx_position_check,
+       .pcm_close = hda_intel_pcm_close,
 };
 
 static DECLARE_BITMAP(probed_devs, SNDRV_CARDS);