From 6a30abaa40b62aed46ef12ea4c16c48565bdb376 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Apr 2018 17:17:35 +0200 Subject: ALSA: hda - Fix incorrect usage of IS_REACHABLE() The commit c469652bb5e8 ("ALSA: hda - Use IS_REACHABLE() for dependency on input") simplified the dependencies with IS_REACHABLE() macro, but it broke due to its incorrect usage: it should have been IS_REACHABLE(CONFIG_INPUT) instead of IS_REACHABLE(INPUT). Fixes: c469652bb5e8 ("ALSA: hda - Use IS_REACHABLE() for dependency on input") Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8c238e51bb5a..2dd34dd77447 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3832,7 +3832,7 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec, } } -#if IS_REACHABLE(INPUT) +#if IS_REACHABLE(CONFIG_INPUT) static void gpio2_mic_hotkey_event(struct hda_codec *codec, struct hda_jack_callback *event) { -- cgit v1.2.3 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(-) 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 v1.2.3 From 52759c0963510a2843774aac9b65ccaed3308dc0 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 29 Apr 2018 15:01:46 +0900 Subject: ALSA: dice: fix kernel NULL pointer dereference due to invalid calculation for array index At a commit f91c9d7610a ('ALSA: firewire-lib: cache maximum length of payload to reduce function calls'), maximum size of payload for tx isochronous packet is cached to reduce the number of function calls. This cache was programmed to updated at a first callback of ohci1394 IR context. However, the maximum size is required to queueing packets before starting the isochronous context. As a result, the cached value is reused to queue packets in next time to starting the isochronous context. Then the cache is updated in a first callback of the isochronous context. This can cause kernel NULL pointer dereference in a below call graph: (sound/firewire/amdtp-stream.c) amdtp_stream_start() ->queue_in_packet() ->queue_packet() (drivers/firewire/core-iso.c) ->fw_iso_context_queue() ->struct fw_card_driver.queue_iso() (drivers/firewire/ohci.c) = ohci_queue_iso() ->queue_iso_packet_per_buffer() buffer->pages[page] The issued dereference occurs in a case that: - target unit supports different stream formats for sampling transmission frequency. - maximum length of payload for tx stream in a first trial is bigger than the length in a second trial. In this case, correct number of pages are allocated for DMA and the 'pages' array has enough elements, while index of the element is wrongly calculated according to the old value of length of payload in a call of 'queue_in_packet()'. Then it causes the issue. This commit fixes the critical bug. This affects all of drivers in ALSA firewire stack in Linux kernel v4.12 or later. [12665.302360] BUG: unable to handle kernel NULL pointer dereference at 0000000000000030 [12665.302415] IP: ohci_queue_iso+0x47c/0x800 [firewire_ohci] [12665.302439] PGD 0 [12665.302440] P4D 0 [12665.302450] [12665.302470] Oops: 0000 [#1] SMP PTI [12665.302487] Modules linked in: ... [12665.303096] CPU: 1 PID: 12760 Comm: jackd Tainted: P OE 4.13.0-38-generic #43-Ubuntu [12665.303154] Hardware name: /DH77DF, BIOS KCH7710H.86A.0069.2012.0224.1825 02/24/2012 [12665.303215] task: ffff9ce87da2ae80 task.stack: ffffb5b8823d0000 [12665.303258] RIP: 0010:ohci_queue_iso+0x47c/0x800 [firewire_ohci] [12665.303301] RSP: 0018:ffffb5b8823d3ab8 EFLAGS: 00010086 [12665.303337] RAX: ffff9ce4f4876930 RBX: 0000000000000008 RCX: ffff9ce88a3955e0 [12665.303384] RDX: 0000000000000000 RSI: 0000000034877f00 RDI: 0000000000000000 [12665.303427] RBP: ffffb5b8823d3b68 R08: ffff9ce8ccb390a0 R09: ffff9ce877639ab0 [12665.303475] R10: 0000000000000108 R11: 0000000000000000 R12: 0000000000000003 [12665.303513] R13: 0000000000000000 R14: ffff9ce4f4876950 R15: 0000000000000000 [12665.303554] FS: 00007f2ec467f8c0(0000) GS:ffff9ce8df280000(0000) knlGS:0000000000000000 [12665.303600] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [12665.303633] CR2: 0000000000000030 CR3: 00000002dcf90004 CR4: 00000000000606e0 [12665.303674] Call Trace: [12665.303698] fw_iso_context_queue+0x18/0x20 [firewire_core] [12665.303735] queue_packet+0x88/0xe0 [snd_firewire_lib] [12665.303770] amdtp_stream_start+0x19b/0x270 [snd_firewire_lib] [12665.303811] start_streams+0x276/0x3c0 [snd_dice] [12665.303840] snd_dice_stream_start_duplex+0x1bf/0x480 [snd_dice] [12665.303882] ? vma_gap_callbacks_rotate+0x1e/0x30 [12665.303914] ? __rb_insert_augmented+0xab/0x240 [12665.303936] capture_prepare+0x3c/0x70 [snd_dice] [12665.303961] snd_pcm_do_prepare+0x1d/0x30 [snd_pcm] [12665.303985] snd_pcm_action_single+0x3b/0x90 [snd_pcm] [12665.304009] snd_pcm_action_nonatomic+0x68/0x70 [snd_pcm] [12665.304035] snd_pcm_prepare+0x68/0x90 [snd_pcm] [12665.304058] snd_pcm_common_ioctl1+0x4c0/0x940 [snd_pcm] [12665.304083] snd_pcm_capture_ioctl1+0x19b/0x250 [snd_pcm] [12665.304108] snd_pcm_capture_ioctl+0x27/0x40 [snd_pcm] [12665.304131] do_vfs_ioctl+0xa8/0x630 [12665.304148] ? entry_SYSCALL_64_after_hwframe+0xe9/0x139 [12665.304172] ? entry_SYSCALL_64_after_hwframe+0xe2/0x139 [12665.304195] ? entry_SYSCALL_64_after_hwframe+0xdb/0x139 [12665.304218] ? entry_SYSCALL_64_after_hwframe+0xd4/0x139 [12665.304242] ? entry_SYSCALL_64_after_hwframe+0xcd/0x139 [12665.304265] ? entry_SYSCALL_64_after_hwframe+0xc6/0x139 [12665.304288] ? entry_SYSCALL_64_after_hwframe+0xbf/0x139 [12665.304312] ? entry_SYSCALL_64_after_hwframe+0xb8/0x139 [12665.304335] ? entry_SYSCALL_64_after_hwframe+0xb1/0x139 [12665.304358] SyS_ioctl+0x79/0x90 [12665.304374] ? entry_SYSCALL_64_after_hwframe+0x72/0x139 [12665.304397] entry_SYSCALL_64_fastpath+0x24/0xab [12665.304417] RIP: 0033:0x7f2ec3750ef7 [12665.304433] RSP: 002b:00007fff99e31388 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [12665.304465] RAX: ffffffffffffffda RBX: 00007fff99e312f0 RCX: 00007f2ec3750ef7 [12665.304494] RDX: 0000000000000000 RSI: 0000000000004140 RDI: 0000000000000007 [12665.304522] RBP: 0000556ebc63fd60 R08: 0000556ebc640560 R09: 0000000000000000 [12665.304553] R10: 0000000000000001 R11: 0000000000000246 R12: 0000556ebc63fcf0 [12665.304584] R13: 0000000000000000 R14: 0000000000000007 R15: 0000000000000000 [12665.304612] Code: 01 00 00 44 89 eb 45 31 ed 45 31 db 66 41 89 1e 66 41 89 5e 0c 66 45 89 5e 0e 49 8b 49 08 49 63 d4 4d 85 c0 49 63 ff 48 8b 14 d1 <48> 8b 72 30 41 8d 14 37 41 89 56 04 48 63 d3 0f 84 ce 00 00 00 [12665.304713] RIP: ohci_queue_iso+0x47c/0x800 [firewire_ohci] RSP: ffffb5b8823d3ab8 [12665.304743] CR2: 0000000000000030 [12665.317701] ---[ end trace 9d55b056dd52a19f ]--- Fixes: f91c9d7610a ('ALSA: firewire-lib: cache maximum length of payload to reduce function calls') Cc: # v4.12+ Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 4a1dc145327b..cb9acfe60f6a 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -773,8 +773,6 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, u32 cycle; unsigned int packets; - s->max_payload_length = amdtp_stream_get_max_payload(s); - /* * For in-stream, first packet has come. * For out-stream, prepared to transmit first packet @@ -879,6 +877,9 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) amdtp_stream_update(s); + if (s->direction == AMDTP_IN_STREAM) + s->max_payload_length = amdtp_stream_get_max_payload(s); + if (s->flags & CIP_NO_HEADER) s->tag = TAG_NO_CIP_HEADER; else -- cgit v1.2.3 From 76b3421b39bd610546931fc923edcf90c18fa395 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Apr 2018 10:06:48 +0200 Subject: ALSA: aloop: Add missing cable lock to ctl API callbacks Some control API callbacks in aloop driver are too lazy to take the loopback->cable_lock and it results in possible races of cable access while it's being freed. It eventually lead to a UAF, as reported by fuzzer recently. This patch covers such control API callbacks and add the proper mutex locks. Reported-by: DaeRyong Jeong Cc: Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 58e349fc893f..eab7f594ebe7 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -831,9 +831,11 @@ static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); + mutex_lock(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].rate_shift; + mutex_unlock(&loopback->cable_lock); return 0; } @@ -865,9 +867,11 @@ static int loopback_notify_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); + mutex_lock(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].notify; + mutex_unlock(&loopback->cable_lock); return 0; } @@ -879,12 +883,14 @@ static int loopback_notify_put(struct snd_kcontrol *kcontrol, int change = 0; val = ucontrol->value.integer.value[0] ? 1 : 0; + mutex_lock(&loopback->cable_lock); if (val != loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].notify) { loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].notify = val; change = 1; } + mutex_unlock(&loopback->cable_lock); return change; } @@ -892,15 +898,18 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct loopback *loopback = snd_kcontrol_chip(kcontrol); - struct loopback_cable *cable = loopback->cables - [kcontrol->id.subdevice][kcontrol->id.device ^ 1]; + struct loopback_cable *cable; + unsigned int val = 0; + mutex_lock(&loopback->cable_lock); + cable = loopback->cables[kcontrol->id.subdevice][kcontrol->id.device ^ 1]; if (cable != NULL) { unsigned int running = cable->running ^ cable->pause; val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0; } + mutex_unlock(&loopback->cable_lock); ucontrol->value.integer.value[0] = val; return 0; } @@ -943,9 +952,11 @@ static int loopback_rate_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); + mutex_lock(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].rate; + mutex_unlock(&loopback->cable_lock); return 0; } @@ -965,9 +976,11 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol, { struct loopback *loopback = snd_kcontrol_chip(kcontrol); + mutex_lock(&loopback->cable_lock); ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] [kcontrol->id.device].channels; + mutex_unlock(&loopback->cable_lock); return 0; } -- cgit v1.2.3 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(+) 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 v1.2.3