[PATCH 3.12 012/175] ALSA: hda - Fix possible races in HDMI driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Takashi Iwai <tiwai@xxxxxxx>

3.12-stable review patch.  If anyone has any objections, please let me know.

===============

commit cbbaa603a03cc46681e24d6b2804b62fde95a2af upstream.

Some per_pin fields and ELD contents might be changed dynamically in
multiple ways where the concurrent accesses are still opened in the
current code.  This patch fixes such possible races by using eld->lock
in appropriate places.

Reported-by: Anssi Hannula <anssi.hannula@xxxxxx>
Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>
Signed-off-by: Jiri Slaby <jslaby@xxxxxxx>
---
 sound/pci/hda/patch_hdmi.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 37da6fb999f2..78338b9c6e9a 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1355,6 +1355,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
 	bool update_eld = false;
 	bool eld_changed = false;
 
+	mutex_lock(&pin_eld->lock);
 	pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
 	if (pin_eld->monitor_present)
 		eld->eld_valid  = !!(present & AC_PINSENSE_ELDV);
@@ -1384,11 +1385,10 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
 			queue_delayed_work(codec->bus->workq,
 					   &per_pin->work,
 					   msecs_to_jiffies(300));
-			return;
+			goto unlock;
 		}
 	}
 
-	mutex_lock(&pin_eld->lock);
 	if (pin_eld->eld_valid && !eld->eld_valid) {
 		update_eld = true;
 		eld_changed = true;
@@ -1413,12 +1413,13 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
 			hdmi_setup_audio_infoframe(codec, per_pin,
 						   per_pin->non_pcm);
 	}
-	mutex_unlock(&pin_eld->lock);
 
 	if (eld_changed)
 		snd_ctl_notify(codec->bus->card,
 			       SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
 			       &per_pin->eld_ctl->id);
+ unlock:
+	mutex_unlock(&pin_eld->lock);
 }
 
 static void hdmi_repoll_eld(struct work_struct *work)
@@ -1590,10 +1591,12 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 	int pinctl;
 
 	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
+	mutex_lock(&per_pin->sink_eld.lock);
 	per_pin->channels = substream->runtime->channels;
 	per_pin->setup = true;
 
 	hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
+	mutex_unlock(&per_pin->sink_eld.lock);
 
 	if (spec->dyn_pin_out) {
 		pinctl = snd_hda_codec_read(codec, pin_nid, 0,
@@ -1648,11 +1651,14 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
 		}
 
 		snd_hda_spdif_ctls_unassign(codec, pin_idx);
+
+		mutex_lock(&per_pin->sink_eld.lock);
 		per_pin->chmap_set = false;
 		memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
 
 		per_pin->setup = false;
 		per_pin->channels = 0;
+		mutex_unlock(&per_pin->sink_eld.lock);
 	}
 
 	return 0;
@@ -1781,10 +1787,12 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
 	ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap);
 	if (ca < 0)
 		return -EINVAL;
+	mutex_lock(&per_pin->sink_eld.lock);
 	per_pin->chmap_set = true;
 	memcpy(per_pin->chmap, chmap, sizeof(chmap));
 	if (prepared)
 		hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+	mutex_unlock(&per_pin->sink_eld.lock);
 
 	return 0;
 }
-- 
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]