Skip to content

Commit

Permalink
ALSA: hda - Fix possible races in HDMI driver
Browse files Browse the repository at this point in the history
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@iki.fi>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Iwai committed Oct 17, 2013
1 parent 4758fed commit cbbaa60
Showing 1 changed file with 11 additions and 3 deletions.
14 changes: 11 additions & 3 deletions sound/pci/hda/patch_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,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);
Expand Down Expand Up @@ -1371,11 +1372,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;
Expand All @@ -1400,12 +1400,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)
Expand Down Expand Up @@ -1576,10 +1577,12 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
bool non_pcm;

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);

return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
}
Expand Down Expand Up @@ -1617,11 +1620,14 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
per_pin = get_pin(spec, pin_idx);

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;
Expand Down Expand Up @@ -1750,10 +1756,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;
}
Expand Down

0 comments on commit cbbaa60

Please sign in to comment.