提交 b5a663aa 编写于 作者: T Takashi Iwai

ALSA: timer: Harden slave timer list handling

A slave timer instance might be still accessible in a racy way while
operating the master instance as it lacks of locking.  Since the
master operation is mostly protected with timer->lock, we should cope
with it while changing the slave instance, too.  Also, some linked
lists (active_list and ack_list) of slave instances aren't unlinked
immediately at stopping or closing, and this may lead to unexpected
accesses.

This patch tries to address these issues.  It adds spin lock of
timer->lock (either from master or slave, which is equivalent) in a
few places.  For avoiding a deadlock, we ensure that the global
slave_active_lock is always locked at first before each timer lock.

Also, ack and active_list of slave instances are properly unlinked at
snd_timer_stop() and snd_timer_close().

Last but not least, remove the superfluous call of _snd_timer_stop()
at removing slave links.  This is a noop, and calling it may confuse
readers wrt locking.  Further cleanup will follow in a later patch.

Actually we've got reports of use-after-free by syzkaller fuzzer, and
this hopefully fixes these issues.
Reported-by: NDmitry Vyukov <dvyukov@google.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: NTakashi Iwai <tiwai@suse.de>
上级 cf52103a
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
...@@ -215,11 +215,13 @@ static void snd_timer_check_master(struct snd_timer_instance *master) ...@@ -215,11 +215,13 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
slave->slave_id == master->slave_id) { slave->slave_id == master->slave_id) {
list_move_tail(&slave->open_list, &master->slave_list_head); list_move_tail(&slave->open_list, &master->slave_list_head);
spin_lock_irq(&slave_active_lock); spin_lock_irq(&slave_active_lock);
spin_lock(&master->timer->lock);
slave->master = master; slave->master = master;
slave->timer = master->timer; slave->timer = master->timer;
if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
list_add_tail(&slave->active_list, list_add_tail(&slave->active_list,
&master->slave_active_head); &master->slave_active_head);
spin_unlock(&master->timer->lock);
spin_unlock_irq(&slave_active_lock); spin_unlock_irq(&slave_active_lock);
} }
} }
...@@ -346,15 +348,18 @@ int snd_timer_close(struct snd_timer_instance *timeri) ...@@ -346,15 +348,18 @@ int snd_timer_close(struct snd_timer_instance *timeri)
timer->hw.close) timer->hw.close)
timer->hw.close(timer); timer->hw.close(timer);
/* remove slave links */ /* remove slave links */
spin_lock_irq(&slave_active_lock);
spin_lock(&timer->lock);
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
open_list) { open_list) {
spin_lock_irq(&slave_active_lock);
_snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
list_move_tail(&slave->open_list, &snd_timer_slave_list); list_move_tail(&slave->open_list, &snd_timer_slave_list);
slave->master = NULL; slave->master = NULL;
slave->timer = NULL; slave->timer = NULL;
spin_unlock_irq(&slave_active_lock); list_del_init(&slave->ack_list);
list_del_init(&slave->active_list);
} }
spin_unlock(&timer->lock);
spin_unlock_irq(&slave_active_lock);
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
} }
out: out:
...@@ -441,9 +446,12 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) ...@@ -441,9 +446,12 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri)
spin_lock_irqsave(&slave_active_lock, flags); spin_lock_irqsave(&slave_active_lock, flags);
timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
if (timeri->master) if (timeri->master && timeri->timer) {
spin_lock(&timeri->timer->lock);
list_add_tail(&timeri->active_list, list_add_tail(&timeri->active_list,
&timeri->master->slave_active_head); &timeri->master->slave_active_head);
spin_unlock(&timeri->timer->lock);
}
spin_unlock_irqrestore(&slave_active_lock, flags); spin_unlock_irqrestore(&slave_active_lock, flags);
return 1; /* delayed start */ return 1; /* delayed start */
} }
...@@ -489,6 +497,8 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, ...@@ -489,6 +497,8 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri,
if (!keep_flag) { if (!keep_flag) {
spin_lock_irqsave(&slave_active_lock, flags); spin_lock_irqsave(&slave_active_lock, flags);
timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
list_del_init(&timeri->ack_list);
list_del_init(&timeri->active_list);
spin_unlock_irqrestore(&slave_active_lock, flags); spin_unlock_irqrestore(&slave_active_lock, flags);
} }
goto __end; goto __end;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部