aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-06-19 11:49:48 -0400
committerTakashi Iwai <tiwai@suse.de>2017-06-20 01:53:57 -0400
commiteb8d0eaaf84b0398533a7c091a0b65663f2fd7ea (patch)
treedfb85ea2e1ee4ff8134aef89b7ba933d9f2920d6
parenta4b4793f640b72af3e2bb2a1ad79725c103d5e40 (diff)
ALSA: hda: Fix potential race at unregistration and unsol events
When the codec device is unregistered / freed, it may release the resource while being used in an unsolicited event like the jack detection work. This leads to use-after-free. The fix here is to unregister the device at first, i.e. removing the codec from the list, then flushing the pending works to assure that all unsol events are gone. After this point, we're free from accessing the codec via unsol events, thus can release the resources gracefully. The issue was spotted originally by Intel CI, but it couldn't be reproduced reliably by its nature. So let's hope this fix really addresses the whole issues. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196045 Reported-by: Martin Peres <martin.peres@free.fr> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/hda/hdac_bus.c1
-rw-r--r--sound/hda/hdac_device.c1
2 files changed, 2 insertions, 0 deletions
diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c
index 0e81ea89a596..714a51721a31 100644
--- a/sound/hda/hdac_bus.c
+++ b/sound/hda/hdac_bus.c
@@ -212,5 +212,6 @@ void snd_hdac_bus_remove_device(struct hdac_bus *bus,
212 bus->caddr_tbl[codec->addr] = NULL; 212 bus->caddr_tbl[codec->addr] = NULL;
213 clear_bit(codec->addr, &bus->codec_powered); 213 clear_bit(codec->addr, &bus->codec_powered);
214 bus->num_codecs--; 214 bus->num_codecs--;
215 flush_work(&bus->unsol_work);
215} 216}
216EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device); 217EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device);
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
index 03c9872c31cf..19deb306facb 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/hdac_device.c
@@ -159,6 +159,7 @@ void snd_hdac_device_unregister(struct hdac_device *codec)
159 if (device_is_registered(&codec->dev)) { 159 if (device_is_registered(&codec->dev)) {
160 hda_widget_sysfs_exit(codec); 160 hda_widget_sysfs_exit(codec);
161 device_del(&codec->dev); 161 device_del(&codec->dev);
162 snd_hdac_bus_remove_device(codec->bus, codec);
162 } 163 }
163} 164}
164EXPORT_SYMBOL_GPL(snd_hdac_device_unregister); 165EXPORT_SYMBOL_GPL(snd_hdac_device_unregister);