[PATCH] ALSA: pcm: Fix NULL dereference in import_ubuf() during exit

Jiakai Xu posted 1 patch 1 week, 6 days ago
sound/core/pcm_lib.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
[PATCH] ALSA: pcm: Fix NULL dereference in import_ubuf() during exit
Posted by Jiakai Xu 1 week, 6 days ago
snd_pcm_oss_sync() calls snd_pcm_lib_write(substream, NULL, size) to
fill silence.  The in_kernel flag is hard-coded to false by the wrapper,
so do_transfer() falls through to import_ubuf() with a garbage pointer
(NULL + frame_offset).  When the process is in do_exit() and current->mm
is already NULL, import_ubuf()'s access_ok() crashes dereferencing 
mm->context.pmlen.

Add a NULL guard in do_transfer() to use iov_iter_kvec() with a dummy
kvec for the fill_silence path, avoiding the import_ubuf() call.  The
fill_silence transfer function ignores the iov_iter, so the dummy kvec
is safe.

Fixes: cf393babb37a1 ("ALSA: pcm: Add copy ops with iov_iter")
Signed-off-by: Jiakai Xu <xujiakai24@mails.ucas.ac.cn>
---
 sound/core/pcm_lib.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 09c421cd9319e..7429a33da0afa 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -2115,6 +2115,21 @@ static int do_transfer(struct snd_pcm_substream *substream, int c,
 		return transfer(substream, c, hwoff, &iter, bytes);
 	}
 
+	/*
+	 * When data is NULL (fill_silence path), import_ubuf() would
+	 * be called with a garbage userspace pointer that is neither a
+	 * valid kernel nor user address.  This can crash when current->mm
+	 * is NULL (e.g., during do_exit() -> exit_files() -> __fput()).
+	 * Since fill_silence ignores the iov_iter entirely, use a dummy
+	 * kvec to avoid the import_ubuf path.
+	 */
+	if (!data) {
+		struct kvec kvec = { NULL, 0 };
+
+		iov_iter_kvec(&iter, type, &kvec, 1, bytes);
+		return transfer(substream, c, hwoff, &iter, bytes);
+	}
+
 	err = import_ubuf(type, (__force void __user *)data, bytes, &iter);
 	if (err)
 		return err;
-- 
2.34.1

Found by fuzzing. Here is the report:

Unable to handle kernel paging request at virtual address dfffffff00000124
Current syz.3.559 pgtable: 4K pagesize, 57-bit VAs, pgdp=0x000000008a70e000
[dfffffff00000124] pgd=000000005fffe401, p4d=000000005fffe001, pud=0000000000000000
Oops [#1]
Modules linked in:
CPU: 1 UID: 0 PID: 16564 Comm: syz.3.559 Tainted: G        W    L      7.1.0-rc1-gdb909bd7986c #1 PREEMPT 
Tainted: [W]=WARN, [L]=SOFTLOCKUP
Hardware name: riscv-virtio,qemu (DT)
epc : __untagged_addr_remote arch/riscv/include/asm/uaccess.h:19 [inline]
epc : __untagged_addr_remote arch/riscv/include/asm/uaccess.h:16 [inline]
epc : import_ubuf+0x2a2/0x3a2 lib/iov_iter.c:1449
 ra : import_ubuf+0x270/0x3a2 lib/iov_iter.c:1449
epc : ffffffff818b2f64 ra : ffffffff818b2f32 sp : ff200000025072d0
 gp : ffffffff8a395420 tp : ff600000b3628000 t0 : ff20000002507610
 t1 : 000000000000f2f2 t2 : ffffffff8537e050 s0 : ff20000002507320
 s1 : ff20000002507390 a0 : 0000000000000920 a1 : 0000000000000000
 a2 : 0000000000000002 a3 : ffffffff818b2f32 a4 : 0000000000000124
 a5 : dfffffff00000124 a6 : 0000000000000003 a7 : 0000000000000001
 s2 : 0000000000000001 s3 : 0000000000001ed0 s4 : 0000000000000000
 s5 : 0000000000000000 s6 : 1fe40000004a0e68 s7 : ffffffff850652f4
 s8 : 0000000000000000 s9 : 0000000000002130 s10: ff20000002507390
 s11: 0000000000000001 t3 : 000000000000f1f1 t4 : ffebffff1198b11f
 t5 : ffebffff1198b120 t6 : 0000000000000002 ssp : 0000000000000000
status: 0000000200000120 badaddr: dfffffff00000124 cause: 000000000000000d
[<ffffffff818b2f64>] __untagged_addr_remote arch/riscv/include/asm/uaccess.h:19 [inline]
[<ffffffff818b2f64>] __untagged_addr_remote arch/riscv/include/asm/uaccess.h:16 [inline]
[<ffffffff818b2f64>] import_ubuf+0x2a2/0x3a2 lib/iov_iter.c:1449
[<ffffffff85065670>] do_transfer+0x128/0x1dc sound/core/pcm_lib.c:2118
[<ffffffff850657ce>] interleaved_copy+0xaa/0xd6 sound/core/pcm_lib.c:2141
[<ffffffff85071c84>] __snd_pcm_lib_xfer+0xc98/0x1c3a sound/core/pcm_lib.c:2380
[<ffffffff850b4376>] snd_pcm_lib_write include/sound/pcm.h:1194 [inline]
[<ffffffff850b4376>] snd_pcm_oss_sync+0x5f2/0x6e8 sound/core/oss/pcm_oss.c:1713
[<ffffffff850b469a>] snd_pcm_oss_release+0x22e/0x2aa sound/core/oss/pcm_oss.c:2584
[<ffffffff80cf2748>] __fput+0x382/0xac6 fs/file_table.c:510
[<ffffffff80cf2f3a>] ____fput+0x1c/0x26 fs/file_table.c:538
[<ffffffff801f13b2>] task_work_run+0x16a/0x25e kernel/task_work.c:233
[<ffffffff80169d02>] exit_task_work include/linux/task_work.h:40 [inline]
[<ffffffff80169d02>] do_exit+0x8e4/0x2a6c kernel/exit.c:975
[<ffffffff8016c3ea>] do_group_exit+0xd4/0x26c kernel/exit.c:1117
[<ffffffff801a6fb0>] get_signal+0x2070/0x22aa kernel/signal.c:3037
[<ffffffff80073690>] arch_do_signal_or_restart+0xc12/0x1d72 arch/riscv/kernel/signal.c:534
[<ffffffff803eca40>] __exit_to_user_mode_loop kernel/entry/common.c:64 [inline]
[<ffffffff803eca40>] exit_to_user_mode_loop+0x9c/0x7a4 kernel/entry/common.c:98
[<ffffffff866faa3c>] __exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
[<ffffffff866faa3c>] syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:238 [inline]
[<ffffffff866faa3c>] syscall_exit_to_user_mode include/linux/entry-common.h:318 [inline]
[<ffffffff866faa3c>] do_trap_ecall_u+0x490/0x5de arch/riscv/kernel/traps.c:345
[<ffffffff867267f6>] handle_exception+0x15e/0x16a arch/riscv/kernel/entry.S:232
Code: 0513 9205 07b7 e000 9556 17fd 5713 0035 1782 97ba (8783) 0007 
---[ end trace 0000000000000000 ]---
----------------
Code disassembly (best guess):
   0:	92050513          	addi	a0,a0,-1760
   4:	e00007b7          	lui	a5,0xe0000
   8:	9556                	add	a0,a0,s5
   a:	17fd                	addi	a5,a5,-1 # 0xffffffffdfffffff
   c:	00355713          	srli	a4,a0,0x3
  10:	1782                	slli	a5,a5,0x20
  12:	97ba                	add	a5,a5,a4
* 14:	00078783          	lb	a5,0(a5) <-- trapping instruction

<<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>>
Re: [PATCH] ALSA: pcm: Fix NULL dereference in import_ubuf() during exit
Posted by Takashi Iwai 1 week, 6 days ago
On Tue, 26 May 2026 03:32:45 +0200,
Jiakai Xu wrote:
> 
> snd_pcm_oss_sync() calls snd_pcm_lib_write(substream, NULL, size) to
> fill silence.  The in_kernel flag is hard-coded to false by the wrapper,
> so do_transfer() falls through to import_ubuf() with a garbage pointer
> (NULL + frame_offset).  When the process is in do_exit() and current->mm
> is already NULL, import_ubuf()'s access_ok() crashes dereferencing 
> mm->context.pmlen.
> 
> Add a NULL guard in do_transfer() to use iov_iter_kvec() with a dummy
> kvec for the fill_silence path, avoiding the import_ubuf() call.  The
> fill_silence transfer function ignores the iov_iter, so the dummy kvec
> is safe.
> 
> Fixes: cf393babb37a1 ("ALSA: pcm: Add copy ops with iov_iter")
> Signed-off-by: Jiakai Xu <xujiakai24@mails.ucas.ac.cn>

This is already fixed by the upstream commit e4d3386b74fb ("ALSA: pcm:
Don't setup bogus iov_iter for silencing").


thanks,

Takashi