summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCen Zhang <zzzccc427@gmail.com>2026-10-16 10:02:29 +0800
committerTakashi Iwai <tiwai@suse.de>2026-10-16 10:21:27 +0200
commitdb2db2dec96e24d067cc5692ac5eec35830ee8d9 (patch)
treee3b957c2989533c21058e93b0e17ec362121efee
parentd9f52113f263498f000cecce5c4a82b7d2abf9d2 (diff)
downloadlinux-db2db2dec96e24d067cc5692ac5eec35830ee8d9.tar.gz
linux-db2db2dec96e24d067cc5692ac5eec35830ee8d9.zip
ALSA: vmaster: Protect follower lookup and setup
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> Link: https://patch.msgid.link/pm-pmb-6c0b7e841529ddd0b21a-v2-b53dbcd593a7a4bd9582@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/core/vmaster.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 3d57182031d9..f43144ba2797 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) {