aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2016-01-30 17:30:25 -0500
committerTakashi Iwai <tiwai@suse.de>2016-02-01 06:23:29 -0500
commit2cdc7b636d55cbcf42e1e6c8accd85e62d3e9ae8 (patch)
tree66f9915961442f22a4cd0e6f8330340b762d6d6b
parentb248371628aad599a48540962f6b85a21a8a0c3f (diff)
ALSA: seq: Fix yet another races among ALSA timer accesses
ALSA sequencer may open/close and control ALSA timer instance dynamically either via sequencer events or direct ioctls. These are done mostly asynchronously, and it may call still some timer action like snd_timer_start() while another is calling snd_timer_close(). Since the instance gets removed by snd_timer_close(), it may lead to a use-after-free. This patch tries to address such a race by protecting each snd_timer_*() call via the existing spinlock and also by avoiding the access to timer during close call. BugLink: http://lkml.kernel.org/r/CACT4Y+Z6RzW5MBr-HUdV-8zwg71WQfKTdPpYGvOeS7v4cyurNQ@mail.gmail.com Reported-by: Dmitry Vyukov <dvyukov@google.com> Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/core/seq/seq_timer.c87
1 files changed, 67 insertions, 20 deletions
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index 82b220c769c1..293104926098 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -90,6 +90,9 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr)
90 90
91void snd_seq_timer_defaults(struct snd_seq_timer * tmr) 91void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
92{ 92{
93 unsigned long flags;
94
95 spin_lock_irqsave(&tmr->lock, flags);
93 /* setup defaults */ 96 /* setup defaults */
94 tmr->ppq = 96; /* 96 PPQ */ 97 tmr->ppq = 96; /* 96 PPQ */
95 tmr->tempo = 500000; /* 120 BPM */ 98 tmr->tempo = 500000; /* 120 BPM */
@@ -105,21 +108,25 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
105 tmr->preferred_resolution = seq_default_timer_resolution; 108 tmr->preferred_resolution = seq_default_timer_resolution;
106 109
107 tmr->skew = tmr->skew_base = SKEW_BASE; 110 tmr->skew = tmr->skew_base = SKEW_BASE;
111 spin_unlock_irqrestore(&tmr->lock, flags);
108} 112}
109 113
110void snd_seq_timer_reset(struct snd_seq_timer * tmr) 114static void seq_timer_reset(struct snd_seq_timer *tmr)
111{ 115{
112 unsigned long flags;
113
114 spin_lock_irqsave(&tmr->lock, flags);
115
116 /* reset time & songposition */ 116 /* reset time & songposition */
117 tmr->cur_time.tv_sec = 0; 117 tmr->cur_time.tv_sec = 0;
118 tmr->cur_time.tv_nsec = 0; 118 tmr->cur_time.tv_nsec = 0;
119 119
120 tmr->tick.cur_tick = 0; 120 tmr->tick.cur_tick = 0;
121 tmr->tick.fraction = 0; 121 tmr->tick.fraction = 0;
122}
123
124void snd_seq_timer_reset(struct snd_seq_timer *tmr)
125{
126 unsigned long flags;
122 127
128 spin_lock_irqsave(&tmr->lock, flags);
129 seq_timer_reset(tmr);
123 spin_unlock_irqrestore(&tmr->lock, flags); 130 spin_unlock_irqrestore(&tmr->lock, flags);
124} 131}
125 132
@@ -138,8 +145,11 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
138 tmr = q->timer; 145 tmr = q->timer;
139 if (tmr == NULL) 146 if (tmr == NULL)
140 return; 147 return;
141 if (!tmr->running) 148 spin_lock_irqsave(&tmr->lock, flags);
149 if (!tmr->running) {
150 spin_unlock_irqrestore(&tmr->lock, flags);
142 return; 151 return;
152 }
143 153
144 resolution *= ticks; 154 resolution *= ticks;
145 if (tmr->skew != tmr->skew_base) { 155 if (tmr->skew != tmr->skew_base) {
@@ -148,8 +158,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
148 (((resolution & 0xffff) * tmr->skew) >> 16); 158 (((resolution & 0xffff) * tmr->skew) >> 16);
149 } 159 }
150 160
151 spin_lock_irqsave(&tmr->lock, flags);
152
153 /* update timer */ 161 /* update timer */
154 snd_seq_inc_time_nsec(&tmr->cur_time, resolution); 162 snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
155 163
@@ -296,26 +304,30 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
296 t->callback = snd_seq_timer_interrupt; 304 t->callback = snd_seq_timer_interrupt;
297 t->callback_data = q; 305 t->callback_data = q;
298 t->flags |= SNDRV_TIMER_IFLG_AUTO; 306 t->flags |= SNDRV_TIMER_IFLG_AUTO;
307 spin_lock_irq(&tmr->lock);
299 tmr->timeri = t; 308 tmr->timeri = t;
309 spin_unlock_irq(&tmr->lock);
300 return 0; 310 return 0;
301} 311}
302 312
303int snd_seq_timer_close(struct snd_seq_queue *q) 313int snd_seq_timer_close(struct snd_seq_queue *q)
304{ 314{
305 struct snd_seq_timer *tmr; 315 struct snd_seq_timer *tmr;
316 struct snd_timer_instance *t;
306 317
307 tmr = q->timer; 318 tmr = q->timer;
308 if (snd_BUG_ON(!tmr)) 319 if (snd_BUG_ON(!tmr))
309 return -EINVAL; 320 return -EINVAL;
310 if (tmr->timeri) { 321 spin_lock_irq(&tmr->lock);
311 snd_timer_stop(tmr->timeri); 322 t = tmr->timeri;
312 snd_timer_close(tmr->timeri); 323 tmr->timeri = NULL;
313 tmr->timeri = NULL; 324 spin_unlock_irq(&tmr->lock);
314 } 325 if (t)
326 snd_timer_close(t);
315 return 0; 327 return 0;
316} 328}
317 329
318int snd_seq_timer_stop(struct snd_seq_timer * tmr) 330static int seq_timer_stop(struct snd_seq_timer *tmr)
319{ 331{
320 if (! tmr->timeri) 332 if (! tmr->timeri)
321 return -EINVAL; 333 return -EINVAL;
@@ -326,6 +338,17 @@ int snd_seq_timer_stop(struct snd_seq_timer * tmr)
326 return 0; 338 return 0;
327} 339}
328 340
341int snd_seq_timer_stop(struct snd_seq_timer *tmr)
342{
343 unsigned long flags;
344 int err;
345
346 spin_lock_irqsave(&tmr->lock, flags);
347 err = seq_timer_stop(tmr);
348 spin_unlock_irqrestore(&tmr->lock, flags);
349 return err;
350}
351
329static int initialize_timer(struct snd_seq_timer *tmr) 352static int initialize_timer(struct snd_seq_timer *tmr)
330{ 353{
331 struct snd_timer *t; 354 struct snd_timer *t;
@@ -358,13 +381,13 @@ static int initialize_timer(struct snd_seq_timer *tmr)
358 return 0; 381 return 0;
359} 382}
360 383
361int snd_seq_timer_start(struct snd_seq_timer * tmr) 384static int seq_timer_start(struct snd_seq_timer *tmr)
362{ 385{
363 if (! tmr->timeri) 386 if (! tmr->timeri)
364 return -EINVAL; 387 return -EINVAL;
365 if (tmr->running) 388 if (tmr->running)
366 snd_seq_timer_stop(tmr); 389 seq_timer_stop(tmr);
367 snd_seq_timer_reset(tmr); 390 seq_timer_reset(tmr);
368 if (initialize_timer(tmr) < 0) 391 if (initialize_timer(tmr) < 0)
369 return -EINVAL; 392 return -EINVAL;
370 snd_timer_start(tmr->timeri, tmr->ticks); 393 snd_timer_start(tmr->timeri, tmr->ticks);
@@ -373,14 +396,25 @@ int snd_seq_timer_start(struct snd_seq_timer * tmr)
373 return 0; 396 return 0;
374} 397}
375 398
376int snd_seq_timer_continue(struct snd_seq_timer * tmr) 399int snd_seq_timer_start(struct snd_seq_timer *tmr)
400{
401 unsigned long flags;
402 int err;
403
404 spin_lock_irqsave(&tmr->lock, flags);
405 err = seq_timer_start(tmr);
406 spin_unlock_irqrestore(&tmr->lock, flags);
407 return err;
408}
409
410static int seq_timer_continue(struct snd_seq_timer *tmr)
377{ 411{
378 if (! tmr->timeri) 412 if (! tmr->timeri)
379 return -EINVAL; 413 return -EINVAL;
380 if (tmr->running) 414 if (tmr->running)
381 return -EBUSY; 415 return -EBUSY;
382 if (! tmr->initialized) { 416 if (! tmr->initialized) {
383 snd_seq_timer_reset(tmr); 417 seq_timer_reset(tmr);
384 if (initialize_timer(tmr) < 0) 418 if (initialize_timer(tmr) < 0)
385 return -EINVAL; 419 return -EINVAL;
386 } 420 }
@@ -390,11 +424,24 @@ int snd_seq_timer_continue(struct snd_seq_timer * tmr)
390 return 0; 424 return 0;
391} 425}
392 426
427int snd_seq_timer_continue(struct snd_seq_timer *tmr)
428{
429 unsigned long flags;
430 int err;
431
432 spin_lock_irqsave(&tmr->lock, flags);
433 err = seq_timer_continue(tmr);
434 spin_unlock_irqrestore(&tmr->lock, flags);
435 return err;
436}
437
393/* return current 'real' time. use timeofday() to get better granularity. */ 438/* return current 'real' time. use timeofday() to get better granularity. */
394snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) 439snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
395{ 440{
396 snd_seq_real_time_t cur_time; 441 snd_seq_real_time_t cur_time;
442 unsigned long flags;
397 443
444 spin_lock_irqsave(&tmr->lock, flags);
398 cur_time = tmr->cur_time; 445 cur_time = tmr->cur_time;
399 if (tmr->running) { 446 if (tmr->running) {
400 struct timeval tm; 447 struct timeval tm;
@@ -410,7 +457,7 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
410 } 457 }
411 snd_seq_sanity_real_time(&cur_time); 458 snd_seq_sanity_real_time(&cur_time);
412 } 459 }
413 460 spin_unlock_irqrestore(&tmr->lock, flags);
414 return cur_time; 461 return cur_time;
415} 462}
416 463