* [PATCH] ALSA: vmaster: Protect follower lookup and setup
@ 2026-10-16 2:02 Cen Zhang
2026-10-16 8:21 ` Takashi Iwai
0 siblings, 1 reply; 2+ messages in thread
From: Cen Zhang @ 2026-10-16 2:02 UTC (permalink / raw)
To: perex, tiwai, kees
Cc: linux-sound, linux-kernel, baijiaju1990, jjzuming, zzzccc427
A control selected by snd_ctl_add_followers() must remain alive until
_snd_ctl_add_follower() has copied it and installed its wrapper. The
lookup returns a raw pointer without retaining the control, and neither
the short-lived list lookup lock nor the fast lookup protects later use.
If a kernel client adds followers to a live virtual master while another
client removes or replaces a published follower, the following order is
possible, with the card and master kept alive:
Follower setup Control removal
snd_ctl_add_followers()
snd_ctl_find_id_mixer()
return follower
snd_ctl_remove()
down_write(controls_rwsem)
__snd_ctl_remove()
unlink follower
snd_ctl_free_one(follower)
up_write(controls_rwsem)
_snd_ctl_add_follower()
read follower->count
Removal completes after lookup returns and before setup reads the
control. Since setup holds neither controls_rwsem nor a reference, the
count read and subsequent control copies can access freed memory.
Hold controls_rwsem for writing across the lookup and follower setup.
This prevents removal or replacement from freeing the selected control
until wrapper installation is complete. Write ownership also excludes
control callbacks while setup changes the callback and private fields.
KASAN report as below:
BUG: KASAN: slab-use-after-free in _snd_ctl_add_follower+0x452/0x520
Read of size 4 at addr ffff888107957d50 by task loadmodule/491
CPU: 3 UID: 0 PID: 491 Comm: loadmodule Tainted: G O 7.2.0-rc6-pmb-bt-functional-v1+ #1 PREEMPT(lazy)
Tainted: [O]=OOT_MODULE
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_ctl_add_follower+0x452/0x520
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20d/0x410
? _snd_ctl_add_follower+0x452/0x520
kasan_report+0xe0/0x110
? _snd_ctl_add_follower+0x452/0x520
_snd_ctl_add_follower+0x452/0x520
snd_ctl_add_followers+0x153/0x2b0
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_snd_ctl_add_followers+0x10/0x10
? __might_fault+0x135/0x190
? srso_alias_return_thunk+0x5/0xfbef5
? __might_fault+0x14e/0x190
? __pfx_fixture_write+0x10/0x10 [pmbd_vmaster_fixture]
fixture_write+0x174/0x1f0 [pmbd_vmaster_fixture]
? __pfx_fixture_write+0x10/0x10 [pmbd_vmaster_fixture]
? __pfx___might_resched+0x10/0x10
proc_reg_write+0x1fb/0x2d0
vfs_write+0x25a/0x1010
? __pfx_proc_reg_write+0x10/0x10
? kmem_cache_free+0x242/0x580
? __pfx_vfs_write+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? putname+0x93/0xe0
? srso_alias_return_thunk+0x5/0xfbef5
? do_sys_openat2+0x12a/0x1b0
? __pfx_do_sys_openat2+0x10/0x10
ksys_write+0x111/0x200
? __pfx_ksys_write+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:0x7f0b835a9687
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:00007ffc82ea0360 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 00007f0b83517780 RCX: 00007f0b835a9687
RDX: 0000000000000005 RSI: 0000564f8a21d074 RDI: 0000000000000003
RBP: 0000000000000003 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000000
R13: 00007ffc82ea04f0 R14: 00007f0b83755000 R15: 0000564f8a21ed78
</TASK>
Allocated by task 485:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_noprof+0x2d7/0x770
snd_ctl_new+0x51/0x190
snd_ctl_new1+0x13c/0x650
0xffffffffc04011b5
do_one_initcall+0xf3/0x4e0
do_init_module+0x281/0x8e0
load_module+0x658c/0x7cc0
init_module_from_file+0x15b/0x180
idempotent_init_module+0x22d/0x770
__x64_sys_finit_module+0xd2/0x160
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 492:
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_ctl_remove+0x2ac/0x3d0
snd_ctl_remove+0x46/0x70
fixture_write+0x1ae/0x1f0 [pmbd_vmaster_fixture]
proc_reg_write+0x1fb/0x2d0
vfs_write+0x25a/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 ffff888107957d00
which belongs to the cache kmalloc-192 of size 192
The buggy address is located 80 bytes inside of
freed 192-byte region [ffff888107957d00, ffff888107957dc0)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x107957
flags: 0x200000000000000(node=0|zone=2)
page_type: f5(slab)
raw: 0200000000000000 ffff8881000423c0 dead000000000100 dead000000000122
raw: 0000000000000000 0000000000100010 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff888107957c00: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff888107957c80: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
>ffff888107957d00: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff888107957d80: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
ffff888107957e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
==================================================================
Fixes: ae07eb9bf23e ("ALSA: vmaster: Add snd_ctl_add_followers() helper")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index cd3dcaaf9f720e723ad6667e3df5e384a121542d..f4dad747717a4f52983e27d35575a8511d2317c3 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -287,6 +287,8 @@ EXPORT_SYMBOL(_snd_ctl_add_follower);
*
* Adds the multiple follower kcontrols with the given names.
* Returns 0 for success or a negative error code.
+ *
+ * Note that this function takes card->controls_rwsem lock internally.
*/
int snd_ctl_add_followers(struct snd_card *card, struct snd_kcontrol *master,
const char * const *list)
@@ -294,6 +296,7 @@ int snd_ctl_add_followers(struct snd_card *card, struct snd_kcontrol *master,
struct snd_kcontrol *follower;
int err;
+ guard(rwsem_write)(&card->controls_rwsem);
for (; *list; list++) {
follower = snd_ctl_find_id_mixer(card, *list);
if (follower) {
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] ALSA: vmaster: Protect follower lookup and setup
2026-10-16 2:02 [PATCH] ALSA: vmaster: Protect follower lookup and setup Cen Zhang
@ 2026-10-16 8:21 ` Takashi Iwai
0 siblings, 0 replies; 2+ messages in thread
From: Takashi Iwai @ 2026-10-16 8:21 UTC (permalink / raw)
To: Cen Zhang
Cc: perex, tiwai, kees, linux-sound, linux-kernel, baijiaju1990,
jjzuming
On Fri, 16 Oct 2026 04:02:29 +0200,
Cen Zhang wrote:
>
> A control selected by snd_ctl_add_followers() must remain alive until
> _snd_ctl_add_follower() has copied it and installed its wrapper. The
> lookup returns a raw pointer without retaining the control, and neither
> the short-lived list lookup lock nor the fast lookup protects later use.
>
> If a kernel client adds followers to a live virtual master while another
> client removes or replaces a published follower, the following order is
> possible, with the card and master kept alive:
>
> Follower setup Control removal
> snd_ctl_add_followers()
> snd_ctl_find_id_mixer()
> return follower
> snd_ctl_remove()
> down_write(controls_rwsem)
> __snd_ctl_remove()
> unlink follower
> snd_ctl_free_one(follower)
> up_write(controls_rwsem)
> _snd_ctl_add_follower()
> read follower->count
>
> Removal completes after lookup returns and before setup reads the
> control. Since setup holds neither controls_rwsem nor a reference, the
> count read and subsequent control copies can access freed memory.
>
> Hold controls_rwsem for writing across the lookup and follower setup.
> This prevents removal or replacement from freeing the selected control
> until wrapper installation is complete. Write ownership also excludes
> control callbacks while setup changes the callback and private fields.
>
> KASAN report as below:
>
> BUG: KASAN: slab-use-after-free in _snd_ctl_add_follower+0x452/0x520
> Read of size 4 at addr ffff888107957d50 by task loadmodule/491
>
> CPU: 3 UID: 0 PID: 491 Comm: loadmodule Tainted: G O 7.2.0-rc6-pmb-bt-functional-v1+ #1 PREEMPT(lazy)
> Tainted: [O]=OOT_MODULE
> 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_ctl_add_follower+0x452/0x520
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? __virt_addr_valid+0x20d/0x410
> ? _snd_ctl_add_follower+0x452/0x520
> kasan_report+0xe0/0x110
> ? _snd_ctl_add_follower+0x452/0x520
> _snd_ctl_add_follower+0x452/0x520
> snd_ctl_add_followers+0x153/0x2b0
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? __pfx_snd_ctl_add_followers+0x10/0x10
> ? __might_fault+0x135/0x190
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? __might_fault+0x14e/0x190
> ? __pfx_fixture_write+0x10/0x10 [pmbd_vmaster_fixture]
> fixture_write+0x174/0x1f0 [pmbd_vmaster_fixture]
> ? __pfx_fixture_write+0x10/0x10 [pmbd_vmaster_fixture]
> ? __pfx___might_resched+0x10/0x10
> proc_reg_write+0x1fb/0x2d0
> vfs_write+0x25a/0x1010
> ? __pfx_proc_reg_write+0x10/0x10
> ? kmem_cache_free+0x242/0x580
> ? __pfx_vfs_write+0x10/0x10
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? putname+0x93/0xe0
> ? srso_alias_return_thunk+0x5/0xfbef5
> ? do_sys_openat2+0x12a/0x1b0
> ? __pfx_do_sys_openat2+0x10/0x10
> ksys_write+0x111/0x200
> ? __pfx_ksys_write+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:0x7f0b835a9687
> 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:00007ffc82ea0360 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
> RAX: ffffffffffffffda RBX: 00007f0b83517780 RCX: 00007f0b835a9687
> RDX: 0000000000000005 RSI: 0000564f8a21d074 RDI: 0000000000000003
> RBP: 0000000000000003 R08: 0000000000000000 R09: 0000000000000000
> R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000000
> R13: 00007ffc82ea04f0 R14: 00007f0b83755000 R15: 0000564f8a21ed78
> </TASK>
>
> Allocated by task 485:
> kasan_save_stack+0x33/0x60
> kasan_save_track+0x14/0x30
> __kasan_kmalloc+0xaa/0xb0
> __kmalloc_noprof+0x2d7/0x770
> snd_ctl_new+0x51/0x190
> snd_ctl_new1+0x13c/0x650
> 0xffffffffc04011b5
> do_one_initcall+0xf3/0x4e0
> do_init_module+0x281/0x8e0
> load_module+0x658c/0x7cc0
> init_module_from_file+0x15b/0x180
> idempotent_init_module+0x22d/0x770
> __x64_sys_finit_module+0xd2/0x160
> do_syscall_64+0x115/0x6a0
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> Freed by task 492:
> 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_ctl_remove+0x2ac/0x3d0
> snd_ctl_remove+0x46/0x70
> fixture_write+0x1ae/0x1f0 [pmbd_vmaster_fixture]
> proc_reg_write+0x1fb/0x2d0
> vfs_write+0x25a/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 ffff888107957d00
> which belongs to the cache kmalloc-192 of size 192
> The buggy address is located 80 bytes inside of
> freed 192-byte region [ffff888107957d00, ffff888107957dc0)
>
> The buggy address belongs to the physical page:
> page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x107957
> flags: 0x200000000000000(node=0|zone=2)
> page_type: f5(slab)
> raw: 0200000000000000 ffff8881000423c0 dead000000000100 dead000000000122
> raw: 0000000000000000 0000000000100010 00000000f5000000 0000000000000000
> page dumped because: kasan: bad access detected
>
> Memory state around the buggy address:
> ffff888107957c00: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff888107957c80: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
> >ffff888107957d00: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ^
> ffff888107957d80: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
> ffff888107957e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> ==================================================================
>
> Fixes: ae07eb9bf23e ("ALSA: vmaster: Add snd_ctl_add_followers() helper")
> Assisted-by: LLM
> Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Applied to for-next branch. Thanks.
Takashi
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-16 8:21 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-16 2:02 [PATCH] ALSA: vmaster: Protect follower lookup and setup Cen Zhang
2026-10-16 8:21 ` Takashi Iwai
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.