Skip to content

Commit 6f2b0ab

Browse files
tiwaigregkh
authored andcommitted
ALSA: dummy: Implement timer backend switching more safely
commit ddce57a upstream. Currently the selected timer backend is referred at any moment from the running PCM callbacks. When the backend is switched, it's possible to lead to inconsistency from the running backend. This was pointed by syzkaller fuzzer, and the commit [7ee9621: ALSA: dummy: Disable switching timer backend via sysfs] disabled the dynamic switching for avoiding the crash. This patch improves the handling of timer backend switching. It keeps the reference to the selected backend during the whole operation of an opened stream so that it won't be changed by other streams. Together with this change, the hrtimer parameter is reenabled as writable now. NOTE: this patch also turned out to fix the still remaining race. Namely, ops was still replaced dynamically at dummy_pcm_open: static int dummy_pcm_open(struct snd_pcm_substream *substream) { .... dummy->timer_ops = &dummy_systimer_ops; if (hrtimer) dummy->timer_ops = &dummy_hrtimer_ops; Since dummy->timer_ops is common among all streams, and when the replacement happens during accesses of other streams, it may lead to a crash. This was actually triggered by syzkaller fuzzer and KASAN. This patch rewrites the code not to use the ops shared by all streams any longer, too. BugLink: http://lkml.kernel.org/r/CACT4Y+aZ+xisrpuM6cOXbL21DuM0yVxPYXf4cD4Md9uw0C3dBQ@mail.gmail.com Reported-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a25dc44 commit 6f2b0ab

File tree

1 file changed

+19
-18
lines changed

1 file changed

+19
-18
lines changed

sound/drivers/dummy.c

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-128) for dummy driver.");
8787
module_param(fake_buffer, bool, 0444);
8888
MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations.");
8989
#ifdef CONFIG_HIGH_RES_TIMERS
90-
module_param(hrtimer, bool, 0444);
90+
module_param(hrtimer, bool, 0644);
9191
MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source.");
9292
#endif
9393

@@ -109,6 +109,9 @@ struct dummy_timer_ops {
109109
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
110110
};
111111

112+
#define get_dummy_ops(substream) \
113+
(*(const struct dummy_timer_ops **)(substream)->runtime->private_data)
114+
112115
struct dummy_model {
113116
const char *name;
114117
int (*playback_constraints)(struct snd_pcm_runtime *runtime);
@@ -137,7 +140,6 @@ struct snd_dummy {
137140
int iobox;
138141
struct snd_kcontrol *cd_volume_ctl;
139142
struct snd_kcontrol *cd_switch_ctl;
140-
const struct dummy_timer_ops *timer_ops;
141143
};
142144

143145
/*
@@ -231,6 +233,8 @@ static struct dummy_model *dummy_models[] = {
231233
*/
232234

233235
struct dummy_systimer_pcm {
236+
/* ops must be the first item */
237+
const struct dummy_timer_ops *timer_ops;
234238
spinlock_t lock;
235239
struct timer_list timer;
236240
unsigned long base_time;
@@ -366,6 +370,8 @@ static struct dummy_timer_ops dummy_systimer_ops = {
366370
*/
367371

368372
struct dummy_hrtimer_pcm {
373+
/* ops must be the first item */
374+
const struct dummy_timer_ops *timer_ops;
369375
ktime_t base_time;
370376
ktime_t period_time;
371377
atomic_t running;
@@ -492,31 +498,25 @@ static struct dummy_timer_ops dummy_hrtimer_ops = {
492498

493499
static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
494500
{
495-
struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
496-
497501
switch (cmd) {
498502
case SNDRV_PCM_TRIGGER_START:
499503
case SNDRV_PCM_TRIGGER_RESUME:
500-
return dummy->timer_ops->start(substream);
504+
return get_dummy_ops(substream)->start(substream);
501505
case SNDRV_PCM_TRIGGER_STOP:
502506
case SNDRV_PCM_TRIGGER_SUSPEND:
503-
return dummy->timer_ops->stop(substream);
507+
return get_dummy_ops(substream)->stop(substream);
504508
}
505509
return -EINVAL;
506510
}
507511

508512
static int dummy_pcm_prepare(struct snd_pcm_substream *substream)
509513
{
510-
struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
511-
512-
return dummy->timer_ops->prepare(substream);
514+
return get_dummy_ops(substream)->prepare(substream);
513515
}
514516

515517
static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream)
516518
{
517-
struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
518-
519-
return dummy->timer_ops->pointer(substream);
519+
return get_dummy_ops(substream)->pointer(substream);
520520
}
521521

522522
static struct snd_pcm_hardware dummy_pcm_hardware = {
@@ -562,17 +562,19 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
562562
struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
563563
struct dummy_model *model = dummy->model;
564564
struct snd_pcm_runtime *runtime = substream->runtime;
565+
const struct dummy_timer_ops *ops;
565566
int err;
566567

567-
dummy->timer_ops = &dummy_systimer_ops;
568+
ops = &dummy_systimer_ops;
568569
#ifdef CONFIG_HIGH_RES_TIMERS
569570
if (hrtimer)
570-
dummy->timer_ops = &dummy_hrtimer_ops;
571+
ops = &dummy_hrtimer_ops;
571572
#endif
572573

573-
err = dummy->timer_ops->create(substream);
574+
err = ops->create(substream);
574575
if (err < 0)
575576
return err;
577+
get_dummy_ops(substream) = ops;
576578

577579
runtime->hw = dummy->pcm_hw;
578580
if (substream->pcm->device & 1) {
@@ -594,16 +596,15 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
594596
err = model->capture_constraints(substream->runtime);
595597
}
596598
if (err < 0) {
597-
dummy->timer_ops->free(substream);
599+
get_dummy_ops(substream)->free(substream);
598600
return err;
599601
}
600602
return 0;
601603
}
602604

603605
static int dummy_pcm_close(struct snd_pcm_substream *substream)
604606
{
605-
struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
606-
dummy->timer_ops->free(substream);
607+
get_dummy_ops(substream)->free(substream);
607608
return 0;
608609
}
609610

0 commit comments

Comments
 (0)