* [PATCH] ALSA: pcm: oss: Serialize final setup list cleanup
@ 2026-10-17 7:27 Cen Zhang
2026-10-17 8:19 ` Takashi Iwai
0 siblings, 1 reply; 3+ messages in thread
From: Cen Zhang @ 2026-10-17 7:27 UTC (permalink / raw)
To: perex, tiwai; +Cc: linux-sound, linux-kernel, baijiaju1990, jjzuming, zzzccc427
OSS setup nodes and their task names must remain valid throughout
snd_pcm_oss_look_for_setup(). The lookup holds setup_mutex while
comparing names, traversing the list and copying a matched record, but
snd_pcm_oss_proc_done() frees that list without taking the mutex.
With verbose proc support enabled, an OSS open on a stream with a
populated setup list can overlap HDA codec unbind. The card remains
registered, so the card-file reference does not prevent the PCM
component from being freed.
The lookup runs before pcm->open_mutex is taken and before the driver
acquires a PCM reference. Codec unbind disconnects the PCM and drains
existing codec PCM references first. Its cleanup then reaches
snd_pcm_free() through codec_release_pcms() and snd_device_free(). The
n_unregister callback invokes snd_pcm_oss_unregister_minor() and
snd_pcm_oss_proc_done().
Both columns below access the setup list of the same PCM stream. Without
this fix, cleanup does not take setup_mutex:
OSS open HDA PCM teardown
-------- ----------------
snd_pcm_oss_look_for_setup()
lock(setup_mutex)
setup = setup_list
snd_pcm_oss_proc_done()
snd_info_free_entry()
/* no setup_mutex held */
snd_pcm_oss_proc_free_setup_list()
kfree(setup->task_name)
kfree(setup)
read setup->task_name
or setup->next -> UAF
Take setup_mutex around final list cleanup, as the proc clear/erase path
already does. This waits for the active lookup to finish its reads and
copy before freeing the nodes. Acquire the mutex after
snd_info_free_entry() so proc callback rundown can finish without
waiting on a mutex held by teardown.
KASAN report as below:
BUG: KASAN: slab-use-after-free in snd_pcm_oss_look_for_setup+0x30c/0x3c0
Read of size 8 at addr ffff888106ecc2c0 by task pmbdossuaf/427
CPU: 3 UID: 0 PID: 427 Comm: pmbdossuaf Not tainted 7.2.0-rc6-pmb-alsa-functional-v2+ #1 PREEMPT(lazy)
Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x93/0xd0
print_report+0xce/0x630
? snd_pcm_oss_look_for_setup+0x30c/0x3c0
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20d/0x410
? snd_pcm_oss_look_for_setup+0x30c/0x3c0
kasan_report+0xe0/0x110
? snd_pcm_oss_look_for_setup+0x30c/0x3c0
snd_pcm_oss_look_for_setup+0x30c/0x3c0
snd_pcm_oss_open+0xd38/0x1240
? srso_alias_return_thunk+0x5/0xfbef5
? avc_has_perm_noaudit+0x4a/0x330
? srso_alias_return_thunk+0x5/0xfbef5
? find_held_lock+0x2b/0x80
? __pfx_snd_pcm_oss_open+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __lock_acquire+0x466/0x2260
? srso_alias_return_thunk+0x5/0xfbef5
? srso_alias_return_thunk+0x5/0xfbef5
? srso_alias_return_thunk+0x5/0xfbef5
? lock_release+0xc8/0x280
? __pfx_snd_pcm_oss_open+0x10/0x10
soundcore_open+0x3ae/0x510
? __pfx_soundcore_open+0x10/0x10
chrdev_open+0x21f/0x660
? __pfx_chrdev_open+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
do_dentry_open+0x5c8/0x1300
? __pfx_chrdev_open+0x10/0x10
? security_inode_permission+0x5d/0xb0
vfs_open+0x87/0x390
? srso_alias_return_thunk+0x5/0xfbef5
path_openat+0x2460/0x3cd0
? do_syscall_64+0x115/0x6a0
? entry_SYSCALL_64_after_hwframe+0x77/0x7f
? __pfx_path_openat+0x10/0x10
do_file_open+0x21e/0x470
? __pfx_do_file_open+0x10/0x10
? _raw_spin_unlock+0x23/0x40
? srso_alias_return_thunk+0x5/0xfbef5
? alloc_fd+0x3a6/0x6b0
do_sys_openat2+0xf4/0x1b0
? __pfx_do_sys_openat2+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
__x64_sys_openat+0x136/0x1e0
? __pfx___x64_sys_openat+0x10/0x10
? irqentry_exit+0xbe/0x820
? srso_alias_return_thunk+0x5/0xfbef5
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f687d8c4687
Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
RSP: 002b:00007ffca02dde50 EFLAGS: 00000202 ORIG_RAX: 0000000000000101
RAX: ffffffffffffffda RBX: 00007f687d830780 RCX: 00007f687d8c4687
RDX: 0000000000080801 RSI: 00007f687d518b90 RDI: ffffffffffffff9c
RBP: 00007f687d66e1c8 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 00000000000001ff
R13: 00007f687d356830 R14: 00007ffca02ddf30 R15: 00007f687d518b90
</TASK>
Allocated by task 426:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_cache_noprof+0x251/0x610
snd_pcm_oss_proc_write+0x619/0x950
snd_info_text_entry_release+0x100/0x260
close_pdeo.part.0+0xe0/0x2e0
close_pdeo+0x161/0x180
proc_reg_release+0x185/0x1f0
__fput+0x39f/0xa60
fput_close_sync+0xff/0x200
__x64_sys_close+0x8c/0xf0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 428:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
kasan_save_free_info+0x3b/0x60
__kasan_slab_free+0x5f/0x80
kfree+0x307/0x580
snd_pcm_oss_proc_free_setup_list+0x9c/0x140
snd_pcm_oss_unregister_minor+0x203/0x450
snd_pcm_free+0xb0/0x180
__snd_device_free+0x193/0x3f0
snd_device_free+0xcf/0x190
snd_hda_codec_cleanup_for_unbind+0x1b3/0xad0
hda_codec_driver_remove+0x1c4/0x2e0
device_remove+0x12a/0x170
device_release_driver_internal+0x471/0x650
unbind_store+0xfd/0x110
drv_attr_store+0x79/0xb0
sysfs_kf_write+0xed/0x140
kernfs_fop_write_iter+0x34b/0x500
vfs_write+0x637/0x1010
ksys_write+0x111/0x200
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff888106ecc2c0
which belongs to the cache kmalloc-32 of size 32
The buggy address is located 0 bytes inside of
freed 32-byte region [ffff888106ecc2c0, ffff888106ecc2e0)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x106ecc
flags: 0x200000000000000(node=0|zone=2)
page_type: f5(slab)
raw: 0200000000000000 ffff888100042780 dead000000000100 dead000000000122
raw: 0000000000000000 0000000000400040 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888106ecc180: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
ffff888106ecc200: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
>ffff888106ecc280: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
^
ffff888106ecc300: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
ffff888106ecc380: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
==================================================================
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Assisted-by: LLM
---
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index bd19328dca9e..ac7f6f1384fc 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -3111,6 +3111,7 @@ static void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
struct snd_pcm_str *pstr = &pcm->streams[stream];
snd_info_free_entry(pstr->oss.proc_entry);
pstr->oss.proc_entry = NULL;
+ guard(mutex)(&pstr->oss.setup_mutex);
snd_pcm_oss_proc_free_setup_list(pstr);
}
}
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] ALSA: pcm: oss: Serialize final setup list cleanup
2026-10-17 7:27 [PATCH] ALSA: pcm: oss: Serialize final setup list cleanup Cen Zhang
@ 2026-10-17 8:19 ` Takashi Iwai
2026-10-17 8:43 ` Cen Zhang
0 siblings, 1 reply; 3+ messages in thread
From: Takashi Iwai @ 2026-10-17 8:19 UTC (permalink / raw)
To: Cen Zhang; +Cc: perex, tiwai, linux-sound, linux-kernel, baijiaju1990, jjzuming
On Sat, 17 Oct 2026 09:27:19 +0200,
Cen Zhang wrote:
>
> OSS setup nodes and their task names must remain valid throughout
> snd_pcm_oss_look_for_setup(). The lookup holds setup_mutex while
> comparing names, traversing the list and copying a matched record, but
> snd_pcm_oss_proc_done() frees that list without taking the mutex.
>
> With verbose proc support enabled, an OSS open on a stream with a
> populated setup list can overlap HDA codec unbind. The card remains
> registered, so the card-file reference does not prevent the PCM
> component from being freed.
>
> The lookup runs before pcm->open_mutex is taken and before the driver
> acquires a PCM reference. Codec unbind disconnects the PCM and drains
> existing codec PCM references first. Its cleanup then reaches
> snd_pcm_free() through codec_release_pcms() and snd_device_free(). The
> n_unregister callback invokes snd_pcm_oss_unregister_minor() and
> snd_pcm_oss_proc_done().
>
> Both columns below access the setup list of the same PCM stream. Without
> this fix, cleanup does not take setup_mutex:
>
> OSS open HDA PCM teardown
> -------- ----------------
> snd_pcm_oss_look_for_setup()
> lock(setup_mutex)
> setup = setup_list
> snd_pcm_oss_proc_done()
> snd_info_free_entry()
> /* no setup_mutex held */
> snd_pcm_oss_proc_free_setup_list()
> kfree(setup->task_name)
> kfree(setup)
> read setup->task_name
> or setup->next -> UAF
>
> Take setup_mutex around final list cleanup, as the proc clear/erase path
> already does. This waits for the active lookup to finish its reads and
> copy before freeing the nodes. Acquire the mutex after
> snd_info_free_entry() so proc callback rundown can finish without
> waiting on a mutex held by teardown.
>
> KASAN report as below:
>
> BUG: KASAN: slab-use-after-free in snd_pcm_oss_look_for_setup+0x30c/0x3c0
> Read of size 8 at addr ffff888106ecc2c0 by task pmbdossuaf/427
>
> CPU: 3 UID: 0 PID: 427 Comm: pmbdossuaf Not tainted 7.2.0-rc6-pmb-alsa-functional-v2+ #1 PREEMPT(lazy)
> Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
> Call Trace:
> <TASK>
> dump_stack_lvl+0x93/0xd0
> print_report+0xce/0x630
> ? snd_pcm_oss_look_for_setup+0x30c/0x3c0
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? __virt_addr_valid+0x20d/0x410
> ? snd_pcm_oss_look_for_setup+0x30c/0x3c0
> kasan_report+0xe0/0x110
> ? snd_pcm_oss_look_for_setup+0x30c/0x3c0
> snd_pcm_oss_look_for_setup+0x30c/0x3c0
> snd_pcm_oss_open+0xd38/0x1240
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? avc_has_perm_noaudit+0x4a/0x330
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? find_held_lock+0x2b/0x80
> ? __pfx_snd_pcm_oss_open+0x10/0x10
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? __lock_acquire+0x466/0x2260
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? lock_release+0xc8/0x280
> ? __pfx_snd_pcm_oss_open+0x10/0x10
> soundcore_open+0x3ae/0x510
> ? __pfx_soundcore_open+0x10/0x10
> chrdev_open+0x21f/0x660
> ? __pfx_chrdev_open+0x10/0x10
> ? srso_alias_return_thunk+0x5/0xfbef5
> do_dentry_open+0x5c8/0x1300
> ? __pfx_chrdev_open+0x10/0x10
> ? security_inode_permission+0x5d/0xb0
> vfs_open+0x87/0x390
> ? srso_alias_return_thunk+0x5/0xfbef5
> path_openat+0x2460/0x3cd0
> ? do_syscall_64+0x115/0x6a0
> ? entry_SYSCALL_64_after_hwframe+0x77/0x7f
> ? __pfx_path_openat+0x10/0x10
> do_file_open+0x21e/0x470
> ? __pfx_do_file_open+0x10/0x10
> ? _raw_spin_unlock+0x23/0x40
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? alloc_fd+0x3a6/0x6b0
> do_sys_openat2+0xf4/0x1b0
> ? __pfx_do_sys_openat2+0x10/0x10
> ? srso_alias_return_thunk+0x5/0xfbef5
> __x64_sys_openat+0x136/0x1e0
> ? __pfx___x64_sys_openat+0x10/0x10
> ? irqentry_exit+0xbe/0x820
> ? srso_alias_return_thunk+0x5/0xfbef5
> do_syscall_64+0x115/0x6a0
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
> RIP: 0033:0x7f687d8c4687
> Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
> RSP: 002b:00007ffca02dde50 EFLAGS: 00000202 ORIG_RAX: 0000000000000101
> RAX: ffffffffffffffda RBX: 00007f687d830780 RCX: 00007f687d8c4687
> RDX: 0000000000080801 RSI: 00007f687d518b90 RDI: ffffffffffffff9c
> RBP: 00007f687d66e1c8 R08: 0000000000000000 R09: 0000000000000000
> R10: 0000000000000000 R11: 0000000000000202 R12: 00000000000001ff
> R13: 00007f687d356830 R14: 00007ffca02ddf30 R15: 00007f687d518b90
> </TASK>
>
> Allocated by task 426:
> kasan_save_stack+0x33/0x60
> kasan_save_track+0x14/0x30
> __kasan_kmalloc+0xaa/0xb0
> __kmalloc_cache_noprof+0x251/0x610
> snd_pcm_oss_proc_write+0x619/0x950
> snd_info_text_entry_release+0x100/0x260
> close_pdeo.part.0+0xe0/0x2e0
> close_pdeo+0x161/0x180
> proc_reg_release+0x185/0x1f0
> __fput+0x39f/0xa60
> fput_close_sync+0xff/0x200
> __x64_sys_close+0x8c/0xf0
> do_syscall_64+0x115/0x6a0
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> Freed by task 428:
> kasan_save_stack+0x33/0x60
> kasan_save_track+0x14/0x30
> kasan_save_free_info+0x3b/0x60
> __kasan_slab_free+0x5f/0x80
> kfree+0x307/0x580
> snd_pcm_oss_proc_free_setup_list+0x9c/0x140
> snd_pcm_oss_unregister_minor+0x203/0x450
> snd_pcm_free+0xb0/0x180
> __snd_device_free+0x193/0x3f0
> snd_device_free+0xcf/0x190
> snd_hda_codec_cleanup_for_unbind+0x1b3/0xad0
> hda_codec_driver_remove+0x1c4/0x2e0
> device_remove+0x12a/0x170
> device_release_driver_internal+0x471/0x650
> unbind_store+0xfd/0x110
> drv_attr_store+0x79/0xb0
> sysfs_kf_write+0xed/0x140
> kernfs_fop_write_iter+0x34b/0x500
> vfs_write+0x637/0x1010
> ksys_write+0x111/0x200
> do_syscall_64+0x115/0x6a0
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> The buggy address belongs to the object at ffff888106ecc2c0
> which belongs to the cache kmalloc-32 of size 32
> The buggy address is located 0 bytes inside of
> freed 32-byte region [ffff888106ecc2c0, ffff888106ecc2e0)
>
> The buggy address belongs to the physical page:
> page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x106ecc
> flags: 0x200000000000000(node=0|zone=2)
> page_type: f5(slab)
> raw: 0200000000000000 ffff888100042780 dead000000000100 dead000000000122
> raw: 0000000000000000 0000000000400040 00000000f5000000 0000000000000000
> page dumped because: kasan: bad access detected
>
> Memory state around the buggy address:
> ffff888106ecc180: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
> ffff888106ecc200: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
> >ffff888106ecc280: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
> ^
> ffff888106ecc300: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
> ffff888106ecc380: fa fb fb fb fc fc fc fc fa fb fb fb fc fc fc fc
> ==================================================================
>
> Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
> Assisted-by: LLM
How can this happen? The PCM proc file belongs to the card, and
snd_oss_proc_done() is called from snd_pcm_free() at the card removal,
where all opened descriptors must have been released before reaching
this point and no new open is allowed any longer.
thanks,
Takashi
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] ALSA: pcm: oss: Serialize final setup list cleanup
2026-10-17 8:19 ` Takashi Iwai
@ 2026-10-17 8:43 ` Cen Zhang
0 siblings, 0 replies; 3+ messages in thread
From: Cen Zhang @ 2026-10-17 8:43 UTC (permalink / raw)
To: Takashi Iwai
Cc: perex, tiwai, linux-sound, linux-kernel, baijiaju1990, jjzuming
Hi Takashi,
>
> How can this happen? The PCM proc file belongs to the card, and
> snd_oss_proc_done() is called from snd_pcm_free() at the card removal,
> where all opened descriptors must have been released before reaching
> this point and no new open is allowed any longer.
>
>
> thanks,
>
> Takashi
The whole-card removal waits for the open files but the reported
case used codec-only sysfs unbind while the card remained registered:
/sys/bus/hdaudio/drivers/snd_hda_codec_generic/unbind
The OSS open reaches snd_pcm_oss_look_for_setup() before acquiring
pcm->open_mutex and before azx_pcm_open() takes the codec PCM reference.
The card reference therefore does not make this early lookup visible
to the codec's snd_refcount_sync().
The original report came from a controlled QEMU run with scheduling
instrumentation. The teardown used the normal sysfs unbind path, and
the recorded free stack included:
snd_pcm_oss_proc_free_setup_list()
snd_pcm_oss_unregister_minor()
snd_pcm_free()
__snd_device_free()
snd_device_free()
snd_hda_codec_cleanup_for_unbind()
hda_codec_driver_remove()
...
unbind_store()
On rechecking the lifetime handling, I found that the added setup_mutex
only protects the setup-list lookup. It does not keep the PCM and codec
resources alive for the remainder of snd_pcm_oss_open(), so it is may not
a complete fix for the codec-unbind race.
Best regards,
Cen Zhang
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-17 8:44 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-17 7:27 [PATCH] ALSA: pcm: oss: Serialize final setup list cleanup Cen Zhang
2026-10-17 8:19 ` Takashi Iwai
2026-10-17 8:43 ` Cen Zhang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.