mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 09:04:39 +02:00
ALSA: hda/intel: Make sure to cancel irq-pending work at closing PCM stream
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
This commit is contained in:
parent
e36a88b33c
commit
33d3b6f0d8
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user