Commit 9d4d207d authored by Takashi Iwai's avatar Takashi Iwai

ALSA: timer: Assure timer resolution access always locked

There are still many places calling the timer's hw.c_resolution
callback without lock, and this may lead to some races, as we faced in
the commit a820ccbe ("ALSA: pcm: Fix UAF at PCM release via PCM
timer access").

This patch changes snd_timer_resolution() to take the timer->lock for
avoiding the races.  A place calling this function already inside the
lock (from the notifier) is replaced with the
snd_timer_hw_resolution() accordingly, as well as wrapping with the
lock around another place calling snd_timer_hw_resolution(), too.
Reported-by: default avatarBen Hutchings <ben.hutchings@codethink.co.uk>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 21244e3d
...@@ -438,19 +438,24 @@ static unsigned long snd_timer_hw_resolution(struct snd_timer *timer) ...@@ -438,19 +438,24 @@ static unsigned long snd_timer_hw_resolution(struct snd_timer *timer)
unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
{ {
struct snd_timer * timer; struct snd_timer * timer;
unsigned long ret = 0;
unsigned long flags;
if (timeri == NULL) if (timeri == NULL)
return 0; return 0;
timer = timeri->timer; timer = timeri->timer;
if (timer) if (timer) {
return snd_timer_hw_resolution(timer); spin_lock_irqsave(&timer->lock, flags);
return 0; ret = snd_timer_hw_resolution(timer);
spin_unlock_irqrestore(&timer->lock, flags);
}
return ret;
} }
EXPORT_SYMBOL(snd_timer_resolution); EXPORT_SYMBOL(snd_timer_resolution);
static void snd_timer_notify1(struct snd_timer_instance *ti, int event) static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
{ {
struct snd_timer *timer; struct snd_timer *timer = ti->timer;
unsigned long resolution = 0; unsigned long resolution = 0;
struct snd_timer_instance *ts; struct snd_timer_instance *ts;
struct timespec tstamp; struct timespec tstamp;
...@@ -462,14 +467,14 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) ...@@ -462,14 +467,14 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START || if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START ||
event > SNDRV_TIMER_EVENT_PAUSE)) event > SNDRV_TIMER_EVENT_PAUSE))
return; return;
if (event == SNDRV_TIMER_EVENT_START || if (timer &&
event == SNDRV_TIMER_EVENT_CONTINUE) (event == SNDRV_TIMER_EVENT_START ||
resolution = snd_timer_resolution(ti); event == SNDRV_TIMER_EVENT_CONTINUE))
resolution = snd_timer_hw_resolution(timer);
if (ti->ccallback) if (ti->ccallback)
ti->ccallback(ti, event, &tstamp, resolution); ti->ccallback(ti, event, &tstamp, resolution);
if (ti->flags & SNDRV_TIMER_IFLG_SLAVE) if (ti->flags & SNDRV_TIMER_IFLG_SLAVE)
return; return;
timer = ti->timer;
if (timer == NULL) if (timer == NULL)
return; return;
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
...@@ -1654,6 +1659,7 @@ static int snd_timer_user_gstatus(struct file *file, ...@@ -1654,6 +1659,7 @@ static int snd_timer_user_gstatus(struct file *file,
mutex_lock(&register_mutex); mutex_lock(&register_mutex);
t = snd_timer_find(&tid); t = snd_timer_find(&tid);
if (t != NULL) { if (t != NULL) {
spin_lock_irq(&t->lock);
gstatus.resolution = snd_timer_hw_resolution(t); gstatus.resolution = snd_timer_hw_resolution(t);
if (t->hw.precise_resolution) { if (t->hw.precise_resolution) {
t->hw.precise_resolution(t, &gstatus.resolution_num, t->hw.precise_resolution(t, &gstatus.resolution_num,
...@@ -1662,6 +1668,7 @@ static int snd_timer_user_gstatus(struct file *file, ...@@ -1662,6 +1668,7 @@ static int snd_timer_user_gstatus(struct file *file,
gstatus.resolution_num = gstatus.resolution; gstatus.resolution_num = gstatus.resolution;
gstatus.resolution_den = 1000000000uL; gstatus.resolution_den = 1000000000uL;
} }
spin_unlock_irq(&t->lock);
} else { } else {
err = -ENODEV; err = -ENODEV;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment