ALSA: hda/tas2781: leave hda_component in usable state
authorGergo Koteles <soyer@irl.hu>
Sat, 9 Dec 2023 21:18:29 +0000 (22:18 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Dec 2023 16:01:52 +0000 (17:01 +0100)
commit 75a25d31b80770485641ad2789a854955f5c1e40 upstream.

Unloading then loading the module causes a NULL ponter dereference.

The hda_unbind zeroes the hda_component, later the hda_bind tries
to dereference the codec field.

The hda_component is only initialized once by tas2781_generic_fixup.

Set only previously modified fields to NULL.

BUG: kernel NULL pointer dereference, address: 0000000000000322
Call Trace:
 <TASK>
 ? __die+0x23/0x70
 ? page_fault_oops+0x171/0x4e0
 ? exc_page_fault+0x7f/0x180
 ? asm_exc_page_fault+0x26/0x30
 ? tas2781_hda_bind+0x59/0x140 [snd_hda_scodec_tas2781_i2c]
 component_bind_all+0xf3/0x240
 try_to_bring_up_aggregate_device+0x1c3/0x270
 __component_add+0xbc/0x1a0
 tas2781_hda_i2c_probe+0x289/0x3a0 [snd_hda_scodec_tas2781_i2c]
 i2c_device_probe+0x136/0x2e0

Fixes: 5be27f1e3ec9 ("ALSA: hda/tas2781: Add tas2781 HDA driver")
Cc: stable@vger.kernel.org
Signed-off-by: Gergo Koteles <soyer@irl.hu>
Link: https://lore.kernel.org/r/8b8ed2bd5f75fbb32e354a3226c2f966fa85b46b.1702156522.git.soyer@irl.hu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
sound/pci/hda/tas2781_hda_i2c.c

index fb80280..b428371 100644 (file)
@@ -612,9 +612,13 @@ static void tas2781_hda_unbind(struct device *dev,
 {
        struct tasdevice_priv *tas_priv = dev_get_drvdata(dev);
        struct hda_component *comps = master_data;
+       comps = &comps[tas_priv->index];
 
-       if (comps[tas_priv->index].dev == dev)
-               memset(&comps[tas_priv->index], 0, sizeof(*comps));
+       if (comps->dev == dev) {
+               comps->dev = NULL;
+               memset(comps->name, 0, sizeof(comps->name));
+               comps->playback_hook = NULL;
+       }
 
        tasdevice_config_info_remove(tas_priv);
        tasdevice_dsp_remove(tas_priv);