forked from Minki/linux
ALSA: hda: Skip event processing for unregistered codecs
When codec is unbound but not yet removed, in the eyes of snd_hdac_bus_process_unsol_events() it is still a valid target to delegate work to. Such behaviour may lead to use-after-free errors. Address by verifying if codec is actually registered. Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com> Link: https://lore.kernel.org/r/20220706120230.427296-6-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
622f219945
commit
e7255c00b1
@ -231,7 +231,6 @@ struct hda_codec {
|
||||
/* misc flags */
|
||||
unsigned int configured:1; /* codec was configured */
|
||||
unsigned int in_freeing:1; /* being released */
|
||||
unsigned int registered:1; /* codec was registered */
|
||||
unsigned int display_power_control:1; /* needs display power */
|
||||
unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
|
||||
* status change
|
||||
|
@ -93,6 +93,7 @@ struct hdac_device {
|
||||
bool lazy_cache:1; /* don't wake up for writes */
|
||||
bool caps_overwriting:1; /* caps overwrite being in process */
|
||||
bool cache_coef:1; /* cache COEF read/write too */
|
||||
unsigned int registered:1; /* codec was registered */
|
||||
};
|
||||
|
||||
/* device/driver type used for matching */
|
||||
|
@ -183,7 +183,7 @@ static void snd_hdac_bus_process_unsol_events(struct work_struct *work)
|
||||
if (!(caddr & (1 << 4))) /* no unsolicited event? */
|
||||
continue;
|
||||
codec = bus->caddr_tbl[caddr & 0x0f];
|
||||
if (!codec || !codec->dev.driver)
|
||||
if (!codec || !codec->registered)
|
||||
continue;
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
drv = drv_to_hdac_driver(codec->dev.driver);
|
||||
|
@ -772,11 +772,11 @@ static void codec_release_pcms(struct hda_codec *codec)
|
||||
*/
|
||||
void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
|
||||
{
|
||||
if (codec->registered) {
|
||||
if (codec->core.registered) {
|
||||
/* pm_runtime_put() is called in snd_hdac_device_exit() */
|
||||
pm_runtime_get_noresume(hda_codec_dev(codec));
|
||||
pm_runtime_disable(hda_codec_dev(codec));
|
||||
codec->registered = 0;
|
||||
codec->core.registered = 0;
|
||||
}
|
||||
|
||||
snd_hda_codec_disconnect_pcms(codec);
|
||||
@ -825,14 +825,14 @@ void snd_hda_codec_display_power(struct hda_codec *codec, bool enable)
|
||||
*/
|
||||
void snd_hda_codec_register(struct hda_codec *codec)
|
||||
{
|
||||
if (codec->registered)
|
||||
if (codec->core.registered)
|
||||
return;
|
||||
if (device_is_registered(hda_codec_dev(codec))) {
|
||||
snd_hda_codec_display_power(codec, true);
|
||||
pm_runtime_enable(hda_codec_dev(codec));
|
||||
/* it was powered up in snd_hda_codec_new(), now all done */
|
||||
snd_hda_power_down(codec);
|
||||
codec->registered = 1;
|
||||
codec->core.registered = 1;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_register);
|
||||
@ -3047,7 +3047,7 @@ void snd_hda_codec_shutdown(struct hda_codec *codec)
|
||||
struct hda_pcm *cpcm;
|
||||
|
||||
/* Skip the shutdown if codec is not registered */
|
||||
if (!codec->registered)
|
||||
if (!codec->core.registered)
|
||||
return;
|
||||
|
||||
cancel_delayed_work_sync(&codec->jackpoll_work);
|
||||
|
@ -274,7 +274,7 @@ static void hda_codec_remove(struct snd_soc_component *component)
|
||||
struct hdac_device *hdev = &codec->core;
|
||||
struct hdac_bus *bus = hdev->bus;
|
||||
struct hdac_ext_link *hlink;
|
||||
bool was_registered = codec->registered;
|
||||
bool was_registered = codec->core.registered;
|
||||
|
||||
/* Don't allow any more runtime suspends */
|
||||
pm_runtime_forbid(&hdev->dev);
|
||||
@ -376,7 +376,7 @@ static int hda_hdev_detach(struct hdac_device *hdev)
|
||||
{
|
||||
struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
|
||||
|
||||
if (codec->registered)
|
||||
if (codec->core.registered)
|
||||
cancel_delayed_work_sync(&codec->jackpoll_work);
|
||||
|
||||
snd_soc_unregister_component(&hdev->dev);
|
||||
|
Loading…
Reference in New Issue
Block a user