Revert "Revert "ALSA: pcm: Fix races among concurrent prepare and hw_params/hw_free calls""

This reverts commit f9e40dc812.

It fixes CVE-2022-1048 and it had to originally be reverted due to ABI
issues.  Add it back now as the ABI "break" is allowed and we want to
fix this real problem.

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: Ife1c36ac31c25f77aab42b7d96e9552d4acc3184
This commit is contained in:
Greg Kroah-Hartman
2022-03-29 15:55:10 +02:00
committed by Todd Kjos
parent 750d586555
commit a9ac889b4c

View File

@@ -1177,15 +1177,17 @@ struct action_ops {
static int snd_pcm_action_group(const struct action_ops *ops,
struct snd_pcm_substream *substream,
snd_pcm_state_t state,
bool do_lock)
bool stream_lock)
{
struct snd_pcm_substream *s = NULL;
struct snd_pcm_substream *s1;
int res = 0, depth = 1;
snd_pcm_group_for_each_entry(s, substream) {
if (do_lock && s != substream) {
if (s->pcm->nonatomic)
if (s != substream) {
if (!stream_lock)
mutex_lock_nested(&s->runtime->buffer_mutex, depth);
else if (s->pcm->nonatomic)
mutex_lock_nested(&s->self_group.mutex, depth);
else
spin_lock_nested(&s->self_group.lock, depth);
@@ -1213,18 +1215,18 @@ static int snd_pcm_action_group(const struct action_ops *ops,
ops->post_action(s, state);
}
_unlock:
if (do_lock) {
/* unlock streams */
snd_pcm_group_for_each_entry(s1, substream) {
if (s1 != substream) {
if (s1->pcm->nonatomic)
mutex_unlock(&s1->self_group.mutex);
else
spin_unlock(&s1->self_group.lock);
}
if (s1 == s) /* end */
break;
/* unlock streams */
snd_pcm_group_for_each_entry(s1, substream) {
if (s1 != substream) {
if (!stream_lock)
mutex_unlock(&s1->runtime->buffer_mutex);
else if (s1->pcm->nonatomic)
mutex_unlock(&s1->self_group.mutex);
else
spin_unlock(&s1->self_group.lock);
}
if (s1 == s) /* end */
break;
}
return res;
}
@@ -1354,10 +1356,12 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops,
/* Guarantee the group members won't change during non-atomic action */
down_read(&snd_pcm_link_rwsem);
mutex_lock(&substream->runtime->buffer_mutex);
if (snd_pcm_stream_linked(substream))
res = snd_pcm_action_group(ops, substream, state, false);
else
res = snd_pcm_action_single(ops, substream, state);
mutex_unlock(&substream->runtime->buffer_mutex);
up_read(&snd_pcm_link_rwsem);
return res;
}