ALSA: hda - hdmi get jack from hda_jack_tbl when not dyn_pcm_assign
authorLibin Yang <libin.yang@linux.intel.com>
Fri, 19 Feb 2016 07:42:06 +0000 (15:42 +0800)
committerTakashi Iwai <tiwai@suse.de>
Fri, 19 Feb 2016 08:06:39 +0000 (09:06 +0100)
On Intel platform, if !dyn_pcm_assign, spec->pcm_rec[].jack is not
NULL even after snd_hda_jack_tbl_clear() is called to free snd_jack.
This may cause access invalid memory when calling snd_jack_report.

Fixes: 25e4abb33df3 ('ALSA: hda - hdmi jack created based on pcm')
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_hdmi.c

index f4443b5..541986f 100644 (file)
@@ -1956,6 +1956,29 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
        return ret;
 }
 
+static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec,
+                                struct hdmi_spec_per_pin *per_pin)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct snd_jack *jack = NULL;
+       struct hda_jack_tbl *jack_tbl;
+
+       /* if !dyn_pcm_assign, get jack from hda_jack_tbl
+        * in !dyn_pcm_assign case, spec->pcm_rec[].jack is not
+        * NULL even after snd_hda_jack_tbl_clear() is called to
+        * free snd_jack. This may cause access invalid memory
+        * when calling snd_jack_report
+        */
+       if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign)
+               jack = spec->pcm_rec[per_pin->pcm_idx].jack;
+       else if (!spec->dyn_pcm_assign) {
+               jack_tbl = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);
+               if (jack_tbl)
+                       jack = jack_tbl->jack;
+       }
+       return jack;
+}
+
 /* update ELD and jack state via audio component */
 static void sync_eld_via_acomp(struct hda_codec *codec,
                               struct hdmi_spec_per_pin *per_pin)
@@ -1989,11 +2012,10 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
        /* pcm_idx >=0 before update_eld() means it is in monitor
         * disconnected event. Jack must be fetched before update_eld()
         */
-       if (per_pin->pcm_idx >= 0)
-               jack = spec->pcm_rec[per_pin->pcm_idx].jack;
+       jack = pin_idx_to_jack(codec, per_pin);
        update_eld(codec, per_pin, eld);
-       if (jack == NULL && per_pin->pcm_idx >= 0)
-               jack = spec->pcm_rec[per_pin->pcm_idx].jack;
+       if (jack == NULL)
+               jack = pin_idx_to_jack(codec, per_pin);
        if (jack == NULL)
                goto unlock;
        snd_jack_report(jack,