提交 2c34260b 编写于 作者: T Takashi Iwai 提交者: Yongqiang Liu

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

stable inclusion
from linux-4.19.243
commit 47cef5937a43a412405ea54ad6e0a91d2890493e
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I50WAS
CVE: CVE-2022-1048

--------------------------------

commit 3c3201f8 upstream.

Like the previous fixes to hw_params and hw_free ioctl races, we need
to paper over the concurrent prepare ioctl calls against hw_params and
hw_free, too.

This patch implements the locking with the existing
runtime->buffer_mutex for prepare ioctls.  Unlike the previous case
for snd_pcm_hw_hw_params() and snd_pcm_hw_free(), snd_pcm_prepare() is
performed to the linked streams, hence the lock can't be applied
simply on the top.  For tracking the lock in each linked substream, we
modify snd_pcm_action_group() slightly and apply the buffer_mutex for
the case stream_lock=false (formerly there was no lock applied)
there.

Cc: <stable@vger.kernel.org>
Reviewed-by: NJaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20220322170720.3529-4-tiwai@suse.deSigned-off-by: NTakashi Iwai <tiwai@suse.de>
[OP: backport to 4.19: adjusted context]
Signed-off-by: NOvidiu Panait <ovidiu.panait@windriver.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NRui Xiang <rui.xiang@huawei.com>
Reviewed-by: Nzhangxiaoxu <zhangxiaoxu5@huawei.com>
Reviewed-by: NXiu Jianfeng <xiujianfeng@huawei.com>
Signed-off-by: NYongqiang Liu <liuyongqiang13@huawei.com>
上级 9fdc9668
...@@ -1073,15 +1073,17 @@ struct action_ops { ...@@ -1073,15 +1073,17 @@ struct action_ops {
*/ */
static int snd_pcm_action_group(const struct action_ops *ops, static int snd_pcm_action_group(const struct action_ops *ops,
struct snd_pcm_substream *substream, struct snd_pcm_substream *substream,
int state, int do_lock) int state, int stream_lock)
{ {
struct snd_pcm_substream *s = NULL; struct snd_pcm_substream *s = NULL;
struct snd_pcm_substream *s1; struct snd_pcm_substream *s1;
int res = 0, depth = 1; int res = 0, depth = 1;
snd_pcm_group_for_each_entry(s, substream) { snd_pcm_group_for_each_entry(s, substream) {
if (do_lock && s != substream) { if (s != substream) {
if (s->pcm->nonatomic) if (!stream_lock)
mutex_lock_nested(&s->runtime->buffer_mutex, depth);
else if (s->pcm->nonatomic)
mutex_lock_nested(&s->self_group.mutex, depth); mutex_lock_nested(&s->self_group.mutex, depth);
else else
spin_lock_nested(&s->self_group.lock, depth); spin_lock_nested(&s->self_group.lock, depth);
...@@ -1109,11 +1111,12 @@ static int snd_pcm_action_group(const struct action_ops *ops, ...@@ -1109,11 +1111,12 @@ static int snd_pcm_action_group(const struct action_ops *ops,
ops->post_action(s, state); ops->post_action(s, state);
} }
_unlock: _unlock:
if (do_lock) {
/* unlock streams */ /* unlock streams */
snd_pcm_group_for_each_entry(s1, substream) { snd_pcm_group_for_each_entry(s1, substream) {
if (s1 != substream) { if (s1 != substream) {
if (s1->pcm->nonatomic) if (!stream_lock)
mutex_unlock(&s1->runtime->buffer_mutex);
else if (s1->pcm->nonatomic)
mutex_unlock(&s1->self_group.mutex); mutex_unlock(&s1->self_group.mutex);
else else
spin_unlock(&s1->self_group.lock); spin_unlock(&s1->self_group.lock);
...@@ -1121,7 +1124,6 @@ static int snd_pcm_action_group(const struct action_ops *ops, ...@@ -1121,7 +1124,6 @@ static int snd_pcm_action_group(const struct action_ops *ops,
if (s1 == s) /* end */ if (s1 == s) /* end */
break; break;
} }
}
return res; return res;
} }
...@@ -1201,10 +1203,12 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops, ...@@ -1201,10 +1203,12 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops,
int res; int res;
down_read(&snd_pcm_link_rwsem); down_read(&snd_pcm_link_rwsem);
mutex_lock(&substream->runtime->buffer_mutex);
if (snd_pcm_stream_linked(substream)) if (snd_pcm_stream_linked(substream))
res = snd_pcm_action_group(ops, substream, state, 0); res = snd_pcm_action_group(ops, substream, state, 0);
else else
res = snd_pcm_action_single(ops, substream, state); res = snd_pcm_action_single(ops, substream, state);
mutex_unlock(&substream->runtime->buffer_mutex);
up_read(&snd_pcm_link_rwsem); up_read(&snd_pcm_link_rwsem);
return res; return res;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册