From 8a56ef4f3ffba9ebf4967b61ef600b0a7ba10f11 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Apr 2018 18:16:15 +0200 Subject: ALSA: rawmidi: Fix missing input substream checks in compat ioctls Some rawmidi compat ioctls lack of the input substream checks (although they do check only for rfile->output). This many eventually lead to an Oops as NULL substream is passed to the rawmidi core functions. Fix it by adding the proper checks before each function call. The bug was spotted by syzkaller. Reported-by: syzbot+f7a0348affc3b67bc617@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai --- sound/core/rawmidi_compat.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'sound/core') diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c index f69764d7cdd7..e30e30ba6e39 100644 --- a/sound/core/rawmidi_compat.c +++ b/sound/core/rawmidi_compat.c @@ -36,8 +36,6 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, struct snd_rawmidi_params params; unsigned int val; - if (rfile->output == NULL) - return -EINVAL; if (get_user(params.stream, &src->stream) || get_user(params.buffer_size, &src->buffer_size) || get_user(params.avail_min, &src->avail_min) || @@ -46,8 +44,12 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, params.no_active_sensing = val; switch (params.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: + if (!rfile->output) + return -EINVAL; return snd_rawmidi_output_params(rfile->output, ¶ms); case SNDRV_RAWMIDI_STREAM_INPUT: + if (!rfile->input) + return -EINVAL; return snd_rawmidi_input_params(rfile->input, ¶ms); } return -EINVAL; @@ -67,16 +69,18 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, int err; struct snd_rawmidi_status status; - if (rfile->output == NULL) - return -EINVAL; if (get_user(status.stream, &src->stream)) return -EFAULT; switch (status.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: + if (!rfile->output) + return -EINVAL; err = snd_rawmidi_output_status(rfile->output, &status); break; case SNDRV_RAWMIDI_STREAM_INPUT: + if (!rfile->input) + return -EINVAL; err = snd_rawmidi_input_status(rfile->input, &status); break; default: @@ -112,16 +116,18 @@ static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile, int err; struct snd_rawmidi_status status; - if (rfile->output == NULL) - return -EINVAL; if (get_user(status.stream, &src->stream)) return -EFAULT; switch (status.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: + if (!rfile->output) + return -EINVAL; err = snd_rawmidi_output_status(rfile->output, &status); break; case SNDRV_RAWMIDI_STREAM_INPUT: + if (!rfile->input) + return -EINVAL; err = snd_rawmidi_input_status(rfile->input, &status); break; default: -- cgit From 912e4c332037e7ed063c164985c36fb2b549ea3a Mon Sep 17 00:00:00 2001 From: Jeffery Miller Date: Fri, 20 Apr 2018 23:20:46 -0500 Subject: ALSA: pcm: Return negative delays from SNDRV_PCM_IOCTL_DELAY. The commit c2c86a97175f ("ALSA: pcm: Remove set_fs() in PCM core code") changed SNDRV_PCM_IOCTL_DELAY to return an inconsistent error instead of a negative delay. Originally the call would succeed and return the negative delay. The Chromium OS Audio Server (CRAS) gets confused and hangs when the error is returned instead of the negative delay. Help CRAS avoid the issue by rolling back the behavior to return a negative delay instead of an error. Fixes: c2c86a97175f ("ALSA: pcm: Remove set_fs() in PCM core code") Signed-off-by: Jeffery Miller Cc: # v4.13+ Signed-off-by: Takashi Iwai --- sound/core/pcm_compat.c | 7 ++++--- sound/core/pcm_native.c | 23 +++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'sound/core') diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index b719d0bd833e..06d7c40af570 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -27,10 +27,11 @@ static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream, s32 __user *src) { snd_pcm_sframes_t delay; + int err; - delay = snd_pcm_delay(substream); - if (delay < 0) - return delay; + err = snd_pcm_delay(substream, &delay); + if (err) + return err; if (put_user(delay, src)) return -EFAULT; return 0; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 35ffccea94c3..06aa499543b6 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2692,7 +2692,8 @@ static int snd_pcm_hwsync(struct snd_pcm_substream *substream) return err; } -static snd_pcm_sframes_t snd_pcm_delay(struct snd_pcm_substream *substream) +static int snd_pcm_delay(struct snd_pcm_substream *substream, + snd_pcm_sframes_t *delay) { struct snd_pcm_runtime *runtime = substream->runtime; int err; @@ -2708,7 +2709,9 @@ static snd_pcm_sframes_t snd_pcm_delay(struct snd_pcm_substream *substream) n += runtime->delay; } snd_pcm_stream_unlock_irq(substream); - return err < 0 ? err : n; + if (!err) + *delay = n; + return err; } static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, @@ -2916,11 +2919,13 @@ static int snd_pcm_common_ioctl(struct file *file, return snd_pcm_hwsync(substream); case SNDRV_PCM_IOCTL_DELAY: { - snd_pcm_sframes_t delay = snd_pcm_delay(substream); + snd_pcm_sframes_t delay; snd_pcm_sframes_t __user *res = arg; + int err; - if (delay < 0) - return delay; + err = snd_pcm_delay(substream, &delay); + if (err) + return err; if (put_user(delay, res)) return -EFAULT; return 0; @@ -3008,13 +3013,7 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, case SNDRV_PCM_IOCTL_DROP: return snd_pcm_drop(substream); case SNDRV_PCM_IOCTL_DELAY: - { - result = snd_pcm_delay(substream); - if (result < 0) - return result; - *frames = result; - return 0; - } + return snd_pcm_delay(substream, frames); default: return -EINVAL; } -- cgit From f853dcaae2f5bbe021161e421bd1576845bae8f6 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Sat, 21 Apr 2018 14:57:40 +0200 Subject: ALSA: core: Report audio_tstamp in snd_pcm_sync_ptr It looks like a simple mistake that this struct member was forgotten. Audio_tstamp isn't used much, and on some archs (such as x86) this ioctl is not used by default, so that might be the reason why this has slipped for so long. Fixes: 4eeaaeaea1ce ("ALSA: core: add hooks for audio timestamps") Signed-off-by: David Henningsson Reviewed-by: Takashi Sakamoto Cc: # v3.8+ Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/core') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 06aa499543b6..159706cf8f05 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2754,6 +2754,7 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, sync_ptr.s.status.hw_ptr = status->hw_ptr; sync_ptr.s.status.tstamp = status->tstamp; sync_ptr.s.status.suspended_state = status->suspended_state; + sync_ptr.s.status.audio_tstamp = status->audio_tstamp; snd_pcm_stream_unlock_irq(substream); if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) return -EFAULT; -- cgit From 1ba7862f1f5a7a3b268cf79ac236611546888a90 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Apr 2018 15:01:44 +0200 Subject: ALSA: control: Fix missing __user annotation There is one place missing __user annotation to the pointer used by the recent code refactoring. Reported by sparse. Fixes: 450296f305f1 ("ALSA: control: code refactoring TLV ioctl handler") Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/core') diff --git a/sound/core/control.c b/sound/core/control.c index 69734b0eafd0..9aa15bfc7936 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1492,7 +1492,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, int op_flag) { struct snd_ctl_tlv header; - unsigned int *container; + unsigned int __user *container; unsigned int container_size; struct snd_kcontrol *kctl; struct snd_ctl_elem_id id; -- cgit From 41412fe921188a2929832ebd643e63bdbb61d326 Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Wed, 25 Apr 2018 09:50:29 +0530 Subject: ALSA: pcm: Change return type to vm_fault_t Use new return type vm_fault_t for fault handler. For now, this is just documenting that the function returns a VM_FAULT value rather than an errno. Once all instances are converted, vm_fault_t will become a distinct type. Commit 1c8f422059ae ("mm: change return type to vm_fault_t") Signed-off-by: Souptick Joarder Reviewed-by: Matthew Wilcox Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/core') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 159706cf8f05..0e875d5a9e86 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3234,7 +3234,7 @@ static __poll_t snd_pcm_capture_poll(struct file *file, poll_table * wait) /* * mmap status record */ -static int snd_pcm_mmap_status_fault(struct vm_fault *vmf) +static vm_fault_t snd_pcm_mmap_status_fault(struct vm_fault *vmf) { struct snd_pcm_substream *substream = vmf->vma->vm_private_data; struct snd_pcm_runtime *runtime; @@ -3270,7 +3270,7 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file /* * mmap control record */ -static int snd_pcm_mmap_control_fault(struct vm_fault *vmf) +static vm_fault_t snd_pcm_mmap_control_fault(struct vm_fault *vmf) { struct snd_pcm_substream *substream = vmf->vma->vm_private_data; struct snd_pcm_runtime *runtime; @@ -3359,7 +3359,7 @@ snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) /* * fault callback for mmapping a RAM page */ -static int snd_pcm_mmap_data_fault(struct vm_fault *vmf) +static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf) { struct snd_pcm_substream *substream = vmf->vma->vm_private_data; struct snd_pcm_runtime *runtime; -- cgit From f5e94b4c6ebdabe0f602d796e0430180927521a0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:26:59 +0200 Subject: ALSA: seq: oss: Fix unbalanced use lock for synth MIDI device When get_synthdev() is called for a MIDI device, it returns the fixed midi_synth_dev without the use refcounting. OTOH, the caller is supposed to unreference unconditionally after the usage, so this would lead to unbalanced refcount. This patch corrects the behavior and keep up the refcount balance also for the MIDI synth device. Cc: Signed-off-by: Takashi Iwai --- sound/core/seq/oss/seq_oss_synth.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sound/core') diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index cd0e0ebbfdb1..9e2b250ae780 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -363,10 +363,14 @@ get_synthdev(struct seq_oss_devinfo *dp, int dev) return NULL; if (! dp->synths[dev].opened) return NULL; - if (dp->synths[dev].is_midi) - return &midi_synth_dev; - if ((rec = get_sdev(dev)) == NULL) - return NULL; + if (dp->synths[dev].is_midi) { + rec = &midi_synth_dev; + snd_use_lock_use(&rec->use_lock); + } else { + rec = get_sdev(dev); + if (!rec) + return NULL; + } if (! rec->opened) { snd_use_lock_free(&rec->use_lock); return NULL; -- cgit From 8d218dd8116695ecda7164f97631c069938aa22e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:31:54 +0200 Subject: ALSA: seq: oss: Hardening for potential Spectre v1 As Smatch recently suggested, a few places in OSS sequencer codes may expand the array directly from the user-space value with speculation, namely there are a significant amount of references to either info->ch[] or dp->synths[] array: sound/core/seq/oss/seq_oss_event.c:315 note_on_event() warn: potential spectre issue 'info->ch' (local cap) sound/core/seq/oss/seq_oss_event.c:362 note_off_event() warn: potential spectre issue 'info->ch' (local cap) sound/core/seq/oss/seq_oss_synth.c:470 snd_seq_oss_synth_load_patch() warn: potential spectre issue 'dp->synths' (local cap) sound/core/seq/oss/seq_oss_event.c:293 note_on_event() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_event.c:353 note_off_event() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_synth.c:506 snd_seq_oss_synth_sysex() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_synth.c:580 snd_seq_oss_synth_ioctl() warn: potential spectre issue 'dp->synths' Although all these seem doing only the first load without further reference, we may want to stay in a safer side, so hardening with array_index_nospec() would still make sense. We may put array_index_nospec() at each place, but here we take a different approach: - For dp->synths[], change the helpers to retrieve seq_oss_synthinfo pointer directly instead of the array expansion at each place - For info->ch[], harden in a normal way, as there are only a couple of places As a result, the existing helper, snd_seq_oss_synth_is_valid() is replaced with snd_seq_oss_synth_info(). Also, we cover MIDI device where a similar array expansion is done, too, although it wasn't reported by Smatch. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai --- sound/core/seq/oss/seq_oss_event.c | 15 +++++--- sound/core/seq/oss/seq_oss_midi.c | 2 + sound/core/seq/oss/seq_oss_synth.c | 75 +++++++++++++++++++++----------------- sound/core/seq/oss/seq_oss_synth.h | 3 +- 4 files changed, 55 insertions(+), 40 deletions(-) (limited to 'sound/core') diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c index c3908862bc8b..86ca584c27b2 100644 --- a/sound/core/seq/oss/seq_oss_event.c +++ b/sound/core/seq/oss/seq_oss_event.c @@ -26,6 +26,7 @@ #include #include "seq_oss_readq.h" #include "seq_oss_writeq.h" +#include /* @@ -287,10 +288,10 @@ note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, st { struct seq_oss_synthinfo *info; - if (!snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - info = &dp->synths[dev]; switch (info->arg.event_passing) { case SNDRV_SEQ_OSS_PROCESS_EVENTS: if (! info->ch || ch < 0 || ch >= info->nr_voices) { @@ -298,6 +299,7 @@ note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, st return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); } + ch = array_index_nospec(ch, info->nr_voices); if (note == 255 && info->ch[ch].note >= 0) { /* volume control */ int type; @@ -347,10 +349,10 @@ note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, s { struct seq_oss_synthinfo *info; - if (!snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - info = &dp->synths[dev]; switch (info->arg.event_passing) { case SNDRV_SEQ_OSS_PROCESS_EVENTS: if (! info->ch || ch < 0 || ch >= info->nr_voices) { @@ -358,6 +360,7 @@ note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, s return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); } + ch = array_index_nospec(ch, info->nr_voices); if (info->ch[ch].note >= 0) { note = info->ch[ch].note; info->ch[ch].vel = 0; @@ -381,7 +384,7 @@ note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, s static int set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + if (!snd_seq_oss_synth_info(dp, dev)) return -ENXIO; ev->type = type; @@ -399,7 +402,7 @@ set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, static int set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + if (!snd_seq_oss_synth_info(dp, dev)) return -ENXIO; ev->type = type; diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index b30b2139e3f0..9debd1b8fd28 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -29,6 +29,7 @@ #include "../seq_lock.h" #include #include +#include /* @@ -315,6 +316,7 @@ get_mididev(struct seq_oss_devinfo *dp, int dev) { if (dev < 0 || dev >= dp->max_mididev) return NULL; + dev = array_index_nospec(dev, dp->max_mididev); return get_mdev(dev); } diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 9e2b250ae780..278ebb993122 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -26,6 +26,7 @@ #include #include #include +#include /* * constants @@ -339,17 +340,13 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) dp->max_synthdev = 0; } -/* - * check if the specified device is MIDI mapped device - */ -static int -is_midi_dev(struct seq_oss_devinfo *dp, int dev) +static struct seq_oss_synthinfo * +get_synthinfo_nospec(struct seq_oss_devinfo *dp, int dev) { if (dev < 0 || dev >= dp->max_synthdev) - return 0; - if (dp->synths[dev].is_midi) - return 1; - return 0; + return NULL; + dev = array_index_nospec(dev, SNDRV_SEQ_OSS_MAX_SYNTH_DEVS); + return &dp->synths[dev]; } /* @@ -359,11 +356,13 @@ static struct seq_oss_synth * get_synthdev(struct seq_oss_devinfo *dp, int dev) { struct seq_oss_synth *rec; - if (dev < 0 || dev >= dp->max_synthdev) + struct seq_oss_synthinfo *info = get_synthinfo_nospec(dp, dev); + + if (!info) return NULL; - if (! dp->synths[dev].opened) + if (!info->opened) return NULL; - if (dp->synths[dev].is_midi) { + if (info->is_midi) { rec = &midi_synth_dev; snd_use_lock_use(&rec->use_lock); } else { @@ -406,10 +405,8 @@ snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev) struct seq_oss_synth *rec; struct seq_oss_synthinfo *info; - if (snd_BUG_ON(dev < 0 || dev >= dp->max_synthdev)) - return; - info = &dp->synths[dev]; - if (! info->opened) + info = get_synthinfo_nospec(dp, dev); + if (!info || !info->opened) return; if (info->sysex) info->sysex->len = 0; /* reset sysex */ @@ -458,12 +455,14 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, const char __user *buf, int p, int c) { struct seq_oss_synth *rec; + struct seq_oss_synthinfo *info; int rc; - if (dev < 0 || dev >= dp->max_synthdev) + info = get_synthinfo_nospec(dp, dev); + if (!info) return -ENXIO; - if (is_midi_dev(dp, dev)) + if (info->is_midi) return 0; if ((rec = get_synthdev(dp, dev)) == NULL) return -ENXIO; @@ -471,24 +470,25 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, if (rec->oper.load_patch == NULL) rc = -ENXIO; else - rc = rec->oper.load_patch(&dp->synths[dev].arg, fmt, buf, p, c); + rc = rec->oper.load_patch(&info->arg, fmt, buf, p, c); snd_use_lock_free(&rec->use_lock); return rc; } /* - * check if the device is valid synth device + * check if the device is valid synth device and return the synth info */ -int -snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev) +struct seq_oss_synthinfo * +snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, int dev) { struct seq_oss_synth *rec; + rec = get_synthdev(dp, dev); if (rec) { snd_use_lock_free(&rec->use_lock); - return 1; + return get_synthinfo_nospec(dp, dev); } - return 0; + return NULL; } @@ -503,16 +503,18 @@ snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, int i, send; unsigned char *dest; struct seq_oss_synth_sysex *sysex; + struct seq_oss_synthinfo *info; - if (! snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - sysex = dp->synths[dev].sysex; + sysex = info->sysex; if (sysex == NULL) { sysex = kzalloc(sizeof(*sysex), GFP_KERNEL); if (sysex == NULL) return -ENOMEM; - dp->synths[dev].sysex = sysex; + info->sysex = sysex; } send = 0; @@ -557,10 +559,12 @@ snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, int snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + struct seq_oss_synthinfo *info = snd_seq_oss_synth_info(dp, dev); + + if (!info) return -EINVAL; - snd_seq_oss_fill_addr(dp, ev, dp->synths[dev].arg.addr.client, - dp->synths[dev].arg.addr.port); + snd_seq_oss_fill_addr(dp, ev, info->arg.addr.client, + info->arg.addr.port); return 0; } @@ -572,16 +576,18 @@ int snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, unsigned long addr) { struct seq_oss_synth *rec; + struct seq_oss_synthinfo *info; int rc; - if (is_midi_dev(dp, dev)) + info = get_synthinfo_nospec(dp, dev); + if (!info || info->is_midi) return -ENXIO; if ((rec = get_synthdev(dp, dev)) == NULL) return -ENXIO; if (rec->oper.ioctl == NULL) rc = -ENXIO; else - rc = rec->oper.ioctl(&dp->synths[dev].arg, cmd, addr); + rc = rec->oper.ioctl(&info->arg, cmd, addr); snd_use_lock_free(&rec->use_lock); return rc; } @@ -593,7 +599,10 @@ snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, u int snd_seq_oss_synth_raw_event(struct seq_oss_devinfo *dp, int dev, unsigned char *data, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev) || is_midi_dev(dp, dev)) + struct seq_oss_synthinfo *info; + + info = snd_seq_oss_synth_info(dp, dev); + if (!info || info->is_midi) return -ENXIO; ev->type = SNDRV_SEQ_EVENT_OSS; memcpy(ev->data.raw8.d, data, 8); diff --git a/sound/core/seq/oss/seq_oss_synth.h b/sound/core/seq/oss/seq_oss_synth.h index 74ac55f166b6..a63f9e22974d 100644 --- a/sound/core/seq/oss/seq_oss_synth.h +++ b/sound/core/seq/oss/seq_oss_synth.h @@ -37,7 +37,8 @@ void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp); void snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev); int snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, const char __user *buf, int p, int c); -int snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev); +struct seq_oss_synthinfo *snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, + int dev); int snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, struct snd_seq_event *ev); int snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev); -- cgit From 8f22e52528cc372b218b5f100457469615c733ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Apr 2018 09:17:45 +0200 Subject: ALSA: seq: Fix races at MIDI encoding in snd_virmidi_output_trigger() The sequencer virmidi code has an open race at its output trigger callback: namely, virmidi keeps only one event packet for processing while it doesn't protect for concurrent output trigger calls. snd_virmidi_output_trigger() tries to process the previously unfinished event before starting encoding the given MIDI stream, but this is done without any lock. Meanwhile, if another rawmidi stream starts the output trigger, this proceeds further, and overwrites the event package that is being processed in another thread. This eventually corrupts and may lead to the invalid memory access if the event type is like SYSEX. The fix is just to move the spinlock to cover both the pending event and the new stream. The bug was spotted by a new fuzzer, RaceFuzzer. BugLink: http://lkml.kernel.org/r/20180426045223.GA15307@dragonet.kaist.ac.kr Reported-by: DaeRyong Jeong Cc: Signed-off-by: Takashi Iwai --- sound/core/seq/seq_virmidi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/core') diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index f48a4cd24ffc..289ae6bb81d9 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -174,12 +174,12 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, } return; } + spin_lock_irqsave(&substream->runtime->lock, flags); if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) - return; + goto out; vmidi->event.type = SNDRV_SEQ_EVENT_NONE; } - spin_lock_irqsave(&substream->runtime->lock, flags); while (1) { count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); if (count <= 0) -- cgit From f13876e2c33a657a71bcbb10f767c0951b165020 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 May 2018 08:48:46 +0200 Subject: ALSA: pcm: Check PCM state at xfern compat ioctl Since snd_pcm_ioctl_xfern_compat() has no PCM state check, it may go further and hit the sanity check pcm_sanity_check() when the ioctl is called right after open. It may eventually spew a kernel warning, as triggered by syzbot, depending on kconfig. The lack of PCM state check there was just an oversight. Although it's no real crash, the spurious kernel warning is annoying, so let's add the proper check. Reported-by: syzbot+1dac3a4f6bc9c1c675d4@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai --- sound/core/pcm_compat.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/core') diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 06d7c40af570..6491afbb5fd5 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -423,6 +423,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, return -ENOTTY; if (substream->stream != dir) return -EINVAL; + if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; if ((ch = substream->runtime->channels) > 128) return -EINVAL; -- cgit From 3f12888dfae2a48741c4caa9214885b3aaf350f9 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Sat, 5 May 2018 13:38:03 -0500 Subject: ALSA: control: fix a redundant-copy issue In snd_ctl_elem_add_compat(), the fields of the struct 'data' need to be copied from the corresponding fields of the struct 'data32' in userspace. This is achieved by invoking copy_from_user() and get_user() functions. The problem here is that the 'type' field is copied twice. One is by copy_from_user() and one is by get_user(). Given that the 'type' field is not used between the two copies, the second copy is *completely* redundant and should be removed for better performance and cleanup. Also, these two copies can cause inconsistent data: as the struct 'data32' resides in userspace and a malicious userspace process can race to change the 'type' field between the two copies to cause inconsistent data. Depending on how the data is used in the future, such an inconsistency may cause potential security risks. For above reasons, we should take out the second copy. Signed-off-by: Wenwen Wang Cc: Signed-off-by: Takashi Iwai --- sound/core/control_compat.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/core') diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index a848836a5de0..507fd5210c1c 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -396,8 +396,7 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) || copy_from_user(&data->type, &data32->type, 3 * sizeof(u32))) goto error; - if (get_user(data->owner, &data32->owner) || - get_user(data->type, &data32->type)) + if (get_user(data->owner, &data32->owner)) goto error; switch (data->type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: -- cgit