summaryrefslogtreecommitdiff
path: root/sound/core/seq
AgeCommit message (Collapse)Author
8 daysALSA: seq: oss: Skip events until fully initializedTakashi Iwai
When an OSS sequencer device is opened, it creates a sequencer port, then further initializes the internal states like a timer instance, etc. Since the sequencer port is published, an event can be already delivered, and this may hit unexpected event handling, which can eventually cause a NULL dereference (like the timer start/stop event triggered before the timer initialization). For avoiding such a race, introduce a simple guard and skips the event processing until the port is fully initialized. At releasing the device, in turn, clear this guard, so that any input events will be discarded during the teardown. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: Sashiko <sashiko-bot@kernel.org> Cc: <stable@vger.kernel.org> Link: https://patch.msgid.link/20261016161930.482309-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
9 daysALSA: seq: oss: Ignore sync echoes without a write queueCen Zhang
The sync-echo callback needs a write queue before it can wake up a synchronizing writer. However, snd_seq_oss_open() publishes the session's port with snd_seq_oss_event_input() as its callback before allocating and assigning dp->writeq. A kernel caller using snd_seq_kernel_client_dispatch() with the OSS client ID can deliver an ECHO containing SEQ_SYNCTIMER to this port before the write queue is assigned. The helper stamps the supplied client ID into the event, so the callback's source-client check accepts it. Regular userspace events carry their own client ID and are rejected. The failing ordering is: OSS open Kernel direct dispatch -------- ---------------------- Zero-allocate dp Set dp->cseq Publish callback port Dispatch ECHO as the OSS client Look up and pin that port Enter snd_seq_oss_event_input() Pass NULL to writeq_wakeup() Allocate and assign dp->writeq Dispatch reaches the callback after port publication and before the queue assignment. OSS register_mutex serializes open and release, but direct dispatch does not take it. The port use reference keeps dp alive through the callback; it does not wait for constructor initialization. The wakeup helper therefore attempts to acquire sync_lock through a NULL queue pointer, causing a fault. Sample dp->writeq once in the SEQ_SYNCTIMER branch and ignore the echo when the queue is absent, matching the adjacent read-queue check. Pass the checked pointer to the wakeup helper so a NULL sample cannot reach the lock access. The existing port reference protects the queue's lifetime through this call, since port deletion drains callbacks before free_devinfo() frees the queue. KASAN report as below: Oops: general protection fault, probably for non-canonical address 0xdffffc000000000d: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000068-0x000000000000006f] CPU: 2 UID: 0 PID: 69 Comm: kworker/2:1 Tainted: G W 7.2.0-rc6-pmb-bt-functional-v1+ #1 PREEMPT(lazy) Tainted: [W]=WARN 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 Workqueue: events pmbd_dispatch_early_sync_echo RIP: 0010:do_raw_spin_lock+0x71/0x270 Code: d0 60 81 49 8d 14 04 c7 02 f1 f1 f1 f1 c7 42 04 04 f3 f3 f3 65 48 8b 15 05 df 88 09 48 89 54 24 60 31 d2 48 89 fa 48 c1 ea 03 <0f> b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 08 84 d2 0f 85 b9 RSP: 0018:ffff88810450f878 EFLAGS: 00010013 RAX: dffffc0000000000 RBX: 0000000000000068 RCX: 0000000000000000 RDX: 000000000000000d RSI: 0000000000000000 RDI: 000000000000006c RBP: 0000000000000293 R08: 0000000000000001 R09: 0000000000000000 R10: ffffffff8940fe57 R11: 0000000000000000 R12: 1ffff110208a1f10 R13: 0000000000000068 R14: 0000000000000001 R15: ffff88810450fbee FS: 0000000000000000(0000) GS:ffff8881fd885000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000006d2890 CR3: 0000000106cbf002 CR4: 0000000000770ef0 PKRU: 55555554 Call Trace: <TASK> ? pmbd_probe_hit_cookie+0xee/0x1c0 ? __pfx_do_raw_spin_lock+0x10/0x10 ? lock_acquire+0x2b8/0x2f0 ? __pfx_pmbd_probe_hit_cookie+0x10/0x10 _raw_spin_lock_irqsave+0x44/0x60 ? snd_seq_oss_writeq_wakeup+0x30/0xf0 snd_seq_oss_writeq_wakeup+0x30/0xf0 snd_seq_oss_event_input+0x1e4/0x2a0 ? do_raw_read_unlock+0x49/0xe0 ? __pfx_snd_seq_oss_event_input+0x10/0x10 __snd_seq_deliver_single_event+0x105/0x1a0 ? snd_seq_port_use_ptr+0x111/0x170 snd_seq_deliver_single_event+0x2fc/0x770 ? __pfx_snd_seq_deliver_single_event+0x10/0x10 ? __pfx_pmbd_hold_maybe+0x10/0x10 snd_seq_deliver_event+0x45a/0x760 ? __pfx_do_raw_spin_lock+0x10/0x10 ? lock_acquire+0x2b8/0x2f0 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_snd_seq_deliver_event+0x10/0x10 ? _raw_spin_unlock_irqrestore+0x44/0x60 ? srso_alias_return_thunk+0x5/0xfbef5 ? trace_hardirqs_on+0x18/0x160 ? srso_alias_return_thunk+0x5/0xfbef5 ? _raw_spin_unlock_irqrestore+0x44/0x60 ? srso_alias_return_thunk+0x5/0xfbef5 snd_seq_kernel_client_dispatch+0x19c/0x1e0 pmbd_dispatch_early_sync_echo+0x121/0x1c0 ? __pfx_pmbd_dispatch_early_sync_echo+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? finish_task_switch.isra.0+0x1dc/0x980 process_one_work+0x908/0x19c0 ? __pfx_process_one_work+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 worker_thread+0x65c/0xe40 ? srso_alias_return_thunk+0x5/0xfbef5 ? __kthread_parkme+0x175/0x220 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_worker_thread+0x10/0x10 kthread+0x34f/0x460 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x659/0x940 ? __pfx_ret_from_fork+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __switch_to+0x74f/0xf80 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Modules linked in: ---[ end trace 0000000000000000 ]--- RIP: 0010:do_raw_spin_lock+0x71/0x270 Code: d0 60 81 49 8d 14 04 c7 02 f1 f1 f1 f1 c7 42 04 04 f3 f3 f3 65 48 8b 15 05 df 88 09 48 89 54 24 60 31 d2 48 89 fa 48 c1 ea 03 <0f> b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 08 84 d2 0f 85 b9 RSP: 0018:ffff88810450f878 EFLAGS: 00010013 RAX: dffffc0000000000 RBX: 0000000000000068 RCX: 0000000000000000 RDX: 000000000000000d RSI: 0000000000000000 RDI: 000000000000006c RBP: 0000000000000293 R08: 0000000000000001 R09: 0000000000000000 R10: ffffffff8940fe57 R11: 0000000000000000 R12: 1ffff110208a1f10 R13: 0000000000000068 R14: 0000000000000001 R15: ffff88810450fbee FS: 0000000000000000(0000) GS:ffff8881fd885000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000006d2890 CR3: 0000000106cbf002 CR4: 0000000000770ef0 PKRU: 55555554 Kernel panic - not syncing: Fatal exception Kernel Offset: disabled Rebooting in 1 seconds.. Assisted-by: LLM Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Link: https://patch.msgid.link/pm-pmb-3634251be738461947da-v2-64371e8c8d6cbf6956a3@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
11 daysALSA: seq: oss: Prevent duplicate MIDI device teardownCen Zhang
Each OSS MIDI alias and its coder must have one final-release owner. find_slot() pins the alias under register_lock, but snd_seq_oss_midi_check_exit_port() clears its slot in a separate critical section without checking whether another callback already removed it. The use counter protects active users, but draining it does not elect a single remover. This requires overlapping raw kernel-client port controls for the same client. snd_seq_kernel_client_ctl() does not take ioctl_mutex, and snd_seq_delete_port() releases ports_mutex before returning to the DELETE_PORT handler's PORT_EXIT broadcast. If the old deletion is delayed before that broadcast, a new port can reuse the vacant address. Its PORT_START finds and keeps the old alias. Deleting the replacement then produces a second PORT_EXIT for the same address. Non-atomic subscriber delivery holds a read rwsem, so the two receive_announce() callbacks can run concurrently: Old-port deletion Replacement-port controls ----------------- ------------------------- Unlink and drain old port Delay before PORT_EXIT Create port at the same address PORT_START keeps existing alias Delete port; PORT_EXIT pins mdev PORT_EXIT pins the same mdev Clear slot; drop pin Clear slot; drop pin Wait for users to drain Wait for users to drain Free coder; pause before kfree(mdev) Free coder again: read freed coder->buf Both callbacks can select the same alias before either clears its slot. After both drop their pins, both waits can return. The second call to snd_midi_event_free() can then read the freed coder's buffer pointer, as in the report below, and attempt to release the same objects twice. Check that the pinned alias still occupies its slot under register_lock before clearing it. A callback that finds it already removed drops its pin and returns. Only the callback that removes the alias drains users and frees the coder and record. The pin keeps the record alive through this check, and the wait remains outside the spinlock. KASAN report as below: ================================================================== BUG: KASAN: slab-use-after-free in snd_midi_event_free+0x53/0x60 Read of size 8 at addr ffff888107074518 by task alsa-seq-fixtur/492 CPU: 3 UID: 0 PID: 492 Comm: alsa-seq-fixtur Not tainted 7.2.0-rc6-pmb-bt-functional-v1+ #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_midi_event_free+0x53/0x60 ? srso_alias_return_thunk+0x5/0xfbef5 ? __virt_addr_valid+0x20d/0x410 ? snd_midi_event_free+0x53/0x60 kasan_report+0xe0/0x110 ? snd_midi_event_free+0x53/0x60 snd_midi_event_free+0x53/0x60 snd_seq_oss_midi_check_exit_port+0x1d8/0x370 receive_announce+0x1b8/0x370 ? __pfx_receive_announce+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __lock_acquire+0x466/0x2260 ? snd_seq_port_use_ptr+0x40/0x170 ? srso_alias_return_thunk+0x5/0xfbef5 ? find_held_lock+0x2b/0x80 ? snd_seq_port_use_ptr+0x10c/0x170 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_release+0xc8/0x280 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_receive_announce+0x10/0x10 __snd_seq_deliver_single_event+0x105/0x1a0 ? snd_seq_port_use_ptr+0x111/0x170 snd_seq_deliver_single_event+0x2fc/0x770 ? __pfx_snd_seq_deliver_single_event+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_down_read_nested+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? do_raw_read_unlock+0x49/0xe0 ? srso_alias_return_thunk+0x5/0xfbef5 ? _raw_read_unlock+0x23/0x40 snd_seq_deliver_event+0x351/0x760 ? __pfx_snd_seq_deliver_event+0x10/0x10 ? _raw_spin_unlock_irqrestore+0x44/0x60 ? trace_hardirqs_on+0x18/0x160 ? srso_alias_return_thunk+0x5/0xfbef5 ? _raw_spin_unlock_irqrestore+0x44/0x60 ? srso_alias_return_thunk+0x5/0xfbef5 snd_seq_kernel_client_dispatch+0x13f/0x170 snd_seq_system_broadcast+0x100/0x150 ? __pfx_snd_seq_system_broadcast+0x10/0x10 ? mark_held_locks+0x40/0x70 ? _raw_spin_unlock_irqrestore+0x44/0x60 ? srso_alias_return_thunk+0x5/0xfbef5 ? lockdep_hardirqs_on_prepare+0xea/0x1a0 ? srso_alias_return_thunk+0x5/0xfbef5 snd_seq_ioctl_delete_port+0x179/0x4b0 call_seq_client_ctl+0x90/0x110 snd_seq_kernel_client_ctl+0x8a/0x100 pmbd_case_delete_port+0xa6/0xf0 ? __pfx_pmbd_case_delete_port+0x10/0x10 ? __might_fault+0xdd/0x190 ? srso_alias_return_thunk+0x5/0xfbef5 ? __might_fault+0x14e/0x190 ? srso_alias_return_thunk+0x5/0xfbef5 ? strim+0x19c/0x200 pmbd_case_control_write+0x2c5/0x470 ? __pfx_pmbd_case_control_write+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __debugfs_file_get+0x1bd/0x7f0 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_acquire+0x17b/0x2f0 ? ksys_write+0x111/0x200 full_proxy_write+0x11f/0x180 vfs_write+0x25a/0x1010 ? __pfx_full_proxy_write+0x10/0x10 ? __pfx___mutex_lock+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? lock_acquire+0x17b/0x2f0 ? __pfx_vfs_write+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? srso_alias_return_thunk+0x5/0xfbef5 ? __fget_files+0x1e1/0x370 ksys_write+0x111/0x200 ? __pfx_ksys_write+0x10/0x10 ? rseq_register.isra.0+0x1f3/0x2e0 ? srso_alias_return_thunk+0x5/0xfbef5 ? exit_to_user_mode_loop+0x3a5/0x570 ? srso_alias_return_thunk+0x5/0xfbef5 do_syscall_64+0x115/0x6a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f3532e4e9ee Code: 08 0f 85 f5 4b ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 <c3> 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 80 00 00 00 00 48 83 ec 08 RSP: 002b:00007f3532dafe08 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 00007f3532db06c0 RCX: 00007f3532e4e9ee RDX: 000000000000000a RSI: 000055efbd747156 RDI: 0000000000000003 RBP: 000055efbd747156 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000000a R13: 0000000000000000 R14: 00007ffe7894e7f0 R15: 00007f35325b0000 </TASK> Allocated by task 490: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 __kmalloc_cache_noprof+0x251/0x610 snd_midi_event_new+0x74/0x210 snd_seq_oss_midi_check_new_port+0x329/0x610 receive_announce+0x277/0x370 __snd_seq_deliver_single_event+0x105/0x1a0 snd_seq_deliver_single_event+0x2fc/0x770 snd_seq_deliver_event+0x351/0x760 snd_seq_kernel_client_dispatch+0x13f/0x170 snd_seq_system_broadcast+0x100/0x150 snd_seq_ioctl_create_port+0x39a/0x9d0 call_seq_client_ctl+0x90/0x110 snd_seq_kernel_client_ctl+0x8a/0x100 pmbd_case_create_port+0xcc/0x160 pmbd_case_control_write+0x21d/0x470 full_proxy_write+0x11f/0x180 vfs_write+0x25a/0x1010 ksys_write+0x111/0x200 do_syscall_64+0x115/0x6a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task 493: 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_midi_event_free+0x48/0x60 snd_seq_oss_midi_check_exit_port+0x1d8/0x370 receive_announce+0x1b8/0x370 __snd_seq_deliver_single_event+0x105/0x1a0 snd_seq_deliver_single_event+0x2fc/0x770 snd_seq_deliver_event+0x351/0x760 snd_seq_kernel_client_dispatch+0x13f/0x170 snd_seq_system_broadcast+0x100/0x150 snd_seq_ioctl_delete_port+0x179/0x4b0 call_seq_client_ctl+0x90/0x110 snd_seq_kernel_client_ctl+0x8a/0x100 pmbd_case_delete_port+0xa6/0xf0 pmbd_case_control_write+0x398/0x470 full_proxy_write+0x11f/0x180 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 ffff888107074500 which belongs to the cache kmalloc-96 of size 96 The buggy address is located 24 bytes inside of freed 96-byte region [ffff888107074500, ffff888107074560) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x107074 flags: 0x200000000000000(node=0|zone=2) page_type: f5(slab) raw: 0200000000000000 ffff888100042280 dead000000000122 0000000000000000 raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff888107074400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff888107074480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc >ffff888107074500: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc ^ ffff888107074580: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc ffff888107074600: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc ================================================================== Assisted-by: LLM Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Link: https://patch.msgid.link/pm-pmb-7c5128efe2110a87b872-v2-c718183fd693e73d8e95@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
14 daysALSA: seq: Wait for one RCU grace period when deleting all portsAli Ahmet Memiş
Since the port list was converted to RCU, snd_seq_delete_all_ports() calls synchronize_rcu() once per port under register_mutex. Closing a client with 254 ports now takes about 1.6s and every other client open or close waits for it. Unlink all ports first, wait for a single grace period and then free them. Fixes: 4c252fbc06d6 ("ALSA: seq: Use RCU for the client port list") Signed-off-by: Ali Ahmet Memiş <aliamemis@disroot.org> Link: https://patch.msgid.link/20261010222543.1470723-1-aliamemis@disroot.org Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-10-08ALSA: seq: Don't lose partial read failureTakashi Iwai
snd_seq_read() returns an error even if one or more events have been successfully read before the error (except for -EAGAIN case), but this rather doesn't follow the POSIX standard that wants the processed bytes. Change the behavior to return the processed bytes when it's positive, instead. Reported-by: Sashiko <sashiko-bot@kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20261007172533.14667-8-tiwai@suse.de
2026-10-08ALSA: seq: Fix missing direction and ump_group handling in 32bit compat ioctlTakashi Iwai
I forgot to cover the two new fields, direction and ump_group, in struct snd_seq_port_info for the 32bit compat ioctls of SNDRV_SEQ_IOCTL_GET_PORT_INFO & co, which ended up with the garbage copies in those fields. Add the handling of those two fields in the compat layer. Also, avoid over-copying the 64bit snd_seq_port_info but only the first part (before the field kernel); this avoids the copy of kernel-space garbage value in the reserved field. Fixes: ff166a9d19fa ("ALSA: seq: Add port direction to snd_seq_port_info") Reported-by: Sashiko <sashiko-bot@kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20261007172533.14667-2-tiwai@suse.de
2026-10-08ALSA: seq: Drop the bogus RCU guard from clientptr()Takashi Iwai
In the recent refactoring with RCU, clientptr() takes guard(rcu)() around the client table lookup, but the RCU read-side section ends as soon as the function returns, so the returned pointer isn't protected at all. This gives a false impression as if that the callers were safe, and confuse reviewers including Sashiko. Actually, the callers (snd_seq_delete_kernel_client(), snd_seq_kernel_client_ctl() and snd_seq_kernel_client_write_poll()) never relied on any lock; the caller is the owner of the client (a kernel client passing its own id, or a user client via its opened file), hence the client can't be released concurrently by others. So just drop the confusing and useless RCU guard, read the table via rcu_dereference_protected(), and document the lifetime rule. Along with it, fold __clientptr() into its only user client_use_ptr(); the id range is already checked there, and it's never called with clients_lock held, so a plain rcu_dereference() suffices. Fixes: 7a287e4615d6 ("ALSA: seq: Use RCU for the client table") Reported-by: Sashiko <sashiko-bot@kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20261007172051.13240-2-tiwai@suse.de
2026-09-28Merge branch 'for-linus' into for-nextTakashi Iwai
Pull 7.3 devel branch for applying the further HD-audio quirks more cleanly. Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-09-28ALSA: seq: Mark OSS sequencer emulation as deprecatedTakashi Iwai
OSS sequencer API emulation has been implemented as a client of ALSA sequencer, decades ago, at the time where OSS was still use. But the API itself became very niche, and almost noone using it for a real purpose any longer -- only exceptions are AI and fuzzers, who have been causing significant maintenance burden for issues they hit & found. Meanwhile, the most features of OSS sequencer API emulation can be achieved in user-space, either by ALSA-OSS layer (aoss) or oss-seq-emu program: https://github.com/alsa-project/alsa-oss https://github.com/tiwai/oss-seq-emu where the former is LD_PRELOAD wrapper and the latter is a CUSE-based daemon. So we can drop the stuff from the kernel sooner or later. Now, let's mark the OSS sequencer emulation as deprecated and give a warning when loaded, so that we can drop it later actually. Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260912124951.416761-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-09-17ALSA: seq: Serialize compat port-info ioctlsKyle Zeng
The native sequencer ioctl path serializes handler calls with client->ioctl_mutex, but the translated port-info compat path invokes the same handlers through snd_seq_kernel_client_ctl() without taking that mutex. This lets concurrent compat CREATE_PORT requests pass the port-count check before any request reaches the serialized insertion. The computed integer port index can then exceed the address field range and wrap to an existing index. Subsequent subscriber teardown can resolve the duplicate address to the wrong port and access a freed subscriber. Take ioctl_mutex while dispatching converted port-info requests, matching the native ioctl path. All translated port-info commands share this helper, so their accesses to the client port state are serialized as well. Fixes: b3defb791b26 ("ALSA: seq: Make ioctls race-free") Cc: stable@vger.kernel.org Assisted-by: Codex:gpt-5.6-sol gpt-6-astra Signed-off-by: Kyle Zeng <kylebot@openai.com> Signed-off-by: Bruno Produit <bruno.produit@trailofbits.com> Link: https://patch.msgid.link/20260917105643.90102-1-bruno.produit@trailofbits.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-09-15ALSA: core: seq: oss: fix typos in commentsHemanth Selam
Correct spelling mistakes in comments. No functional change. Signed-off-by: Hemanth Selam <hemanth.selam@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260915084424.1007757-2-hemanth.selam@gmail.com
2026-09-04treewide: refresh kmalloc_obj() conversionsKees Cook
This is another run of the Coccinelle script for converting kmalloc() family of allocations to kmalloc_obj() via the existing rules in scripts/coccinelle/api/kmalloc_objs.cocci This catches both the set of kmalloc() uses added since the first kmalloc_obj() conversions in v7.0 and adds a large group missed in the first pass due to Coccinelle not interacting well with the cleanup.h scoped_...() family of macros[1]. I worked around this with spatch's "--macro-file" argument to a file with all the scoped_...() macros mapped to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control flow indicator I could find. Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc, riscv, and s390 with no new warnings. Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1] Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2] Signed-off-by: Kees Cook <kees+treewide@kernel.org>
2026-08-13ALSA: seq: midi: Serialize input teardown with event_inputJohn Keeping
snd_midi_input_event() must not be running while a rawmidi substream is closing, since this can lead to the trigger state becoming out-of-step through this sequence in snd_rawmidi_input_trigger(): snd_rawmidi_input_trigger(up=0) snd_midi_input_event() -> snd_rawmidi_kernel_read() -> snd_rawmidi_input_trigger(up=1) -> cancel_work_sync() which ends with the underlying device being active unexpectedly. When this is called from close_substream(), further input can re-trigger the input event leaving it running after rawmidi_release_priv() has set rfile->rmidi to NULL which leads to: Unable to handle kernel NULL pointer dereference at virtual address 00000000000000b0 Call trace: snd_midi_input_event+0x3c/0x134 [snd_seq_midi] (P) snd_rawmidi_input_event_work+0x1c/0x2c process_one_work+0x150/0x3a4 worker_thread+0x190/0x318 Apply a similar approach to commit ef7607ab1c8ad ("ALSA: seq: midi: Serialize output teardown with event_input") which fixed the same issue in the output direction, but updated to use RCU following Takashi Iwai's proposed follow-on patch [1]. With this change in place, midisynth_unsubscribe() clears the input file so snd_midi_input_event() will not re-trigger the stream and will be quiesced by the cancel_work_sync() in snd_rawmidi_input_trigger(). [1] https://lore.kernel.org/linux-sound/20260813144224.753399-1-tiwai@suse.de/ Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: John Keeping <jkeeping@inmusicbrands.com> Link: https://patch.msgid.link/20260813150810.795393-1-jkeeping@inmusicbrands.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-08-13ALSA: seq: midi: Optimize event_input locking with RCUTakashi Iwai
The recent fix for serializing the output teardown introduced a spinlock invocation at every MIDI output event via event_process_midi. Since this is a hot path, let's do performance optimization with RCU. The new output_substream __rcu pointer is published via rcu_assign_pointer() in midisynth_use() after output_rfile is set, and cleared in midisynth_unuse() before the resource teardown. event_process_midi() reads it under rcu_read_lock() and bumps output_use_lock inside that section, which is necessary to close the window between the pointer dereference and the refcount increment. midisynth_unuse() calls synchronize_rcu() before snd_use_lock_sync(): this guarantees that any reader who obtained a non-NULL pointer has already called atomic_inc (output_use_lock), so the subsequent snd_use_lock_sync() sees the correct in-flight count. Fixes: ef7607ab1c8a ("ALSA: seq: midi: Serialize output teardown with event_input") Link: https://patch.msgid.link/20260813144224.753399-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-08-12ALSA: seq: Drop the dead struct snd_seq_event_bounceHyeongJun An
The struct describes a bounce payload of an error code followed by the original event and its external data. No kernel has ever sent that. Before commit efc86691e4d8 ("ALSA: seq: Fix kernel heap address leak in bounce_error_event()") the kernel emitted no SNDRV_SEQ_EVENT_BOUNCE at all, and since then it sends the event record alone. Nothing has ever read it either. Its only accessor, snd_seq_event_bounce_ext_data(), has had no caller for the whole git history, and it did not even compile until commit c7e0b5bf9fff ("[ALSA] Remove xxx_t typedefs: Sequencer") incidentally repaired the type name it referred to, three years after the git import. Drop the accessor along with the struct. This removes a definition from a UAPI header. Since no kernel ever produced the layout, nothing can have parsed it, but a program that merely names the type will need to stop. Suggested-by: Takashi Iwai <tiwai@suse.de> Assisted-by: Claude:claude-opus-5 Signed-off-by: HyeongJun An <sammiee5311@gmail.com> Link: https://patch.msgid.link/20260812141506.4016387-1-sammiee5311@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-08-11ALSA: seq: Don't leak the extension cell pointer in the bounce payloadHyeongJun An
The bounce_error_event() embeds the failed event in the bounce payload by pointing data.ext.ptr at it. When that event is a queued variable-length event, its own data.ext.ptr holds the address of its first extension cell, put there by snd_seq_event_dup(). The payload goes out verbatim through snd_seq_expand_var_event(), so the address reaches userspace. That is the same address commit 705dd6dcbc0e ("ALSA: seq: Clear variable event pointer on read") removed from the event header. The read path still clears it there, just above the call that expands the payload. Embed a sanitised copy instead, treated exactly as snd_seq_read() treats the header. A stack copy is enough because delivery is synchronous and snd_seq_event_dup() copies before returning. An unprivileged client reaches this by setting SNDRV_SEQ_FILTER_BOUNCE, queueing a variable-length event to a port that does not exist and reading the bounce back. Eight bytes on 64-bit, from its own pool. Fixes: efc86691e4d8 ("ALSA: seq: Fix kernel heap address leak in bounce_error_event()") Assisted-by: Claude:claude-opus-5 Signed-off-by: HyeongJun An <sammiee5311@gmail.com> Link: https://patch.msgid.link/20260811131835.3837024-1-sammiee5311@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-08-10ALSA: seq: Use RCU for the UMP client output substreamTakashi Iwai
The UMP sequencer client protects its output rawmidi file (out_rfile) with an rwlock (output_lock). seq_ump_process_event(), the port's event_input callback, reads out_rfile.output under read_lock on every delivered UMP event, while the open/close paths (serialized by ump->open_mutex) publish and clear out_rfile under write_lock. Output is opened/closed only on the subscribe/use lifecycle while delivery happens per event, so this is another read-mostly hot path. Convert it to RCU and drop the rwlock. out_rfile is an embedded struct rather than a pointer, so instead of restructuring it, add an RCU-protected shadow of the substream (out_substream) for the reader; out_rfile itself becomes writer-only state accessed solely under open_mutex. The reader now runs lock-free under rcu_read_lock() via rcu_dereference(), and open publishes the substream with rcu_assign_pointer(). On close the substream is cleared with rcu_assign_pointer(NULL) and the rawmidi is released only after synchronize_rcu(), so no reader in the delivery path can still be writing to the substream when snd_rawmidi_kernel_release() runs. Dropping write_lock_irqsave() from the writers is safe: they run in process context under open_mutex, and the sole atomic reader now uses RCU, which is IRQ-safe. Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260810133711.42483-6-tiwai@suse.de
2026-08-10ALSA: seq: Use RCU for the virmidi file listTakashi Iwai
Each virmidi device keeps a list of its opened input files (filelist) protected by both an rwlock (filelist_lock) and a rw_semaphore (filelist_sem). snd_virmidi_dev_receive_event() walks the list on the sequencer event input path -- read_lock() when the event is delivered in atomic context, down_read() otherwise -- decoding each incoming event into the file's rawmidi buffer. The writers (input open/close) take both locks to add/remove entries. This is another typical dual-lock read-mostly pattern as the port subscriber list: files are opened/closed rarely while the receive callback runs per event. Let's convert the traversal to RCU and drop the rwlock; the existing filelist_sem keeps serializing the writers. The atomic input path now runs lock-free under rcu_read_lock(), and both readers share a single list_for_each_entry_rcu() (valid under the rwsem via lockdep_is_held()). The writers switch to list_add_tail_rcu() / list_del_rcu(). snd_virmidi_input_close() freed the entry (parser and struct) immediately after list_del. A concurrent lockless reader in the atomic path may still be dereferencing it, so the close path now waits for an RCU grace period after list_del_rcu() before freeing; synchronize_rcu() is used rather than kfree_rcu() because the parser must also be released after the grace period, not just the struct. Non-atomic readers are already excluded by the down_write, so only the atomic RCU readers need the grace period. Dropping write_lock_irq() from the writers is safe: no writer runs in atomic/IRQ context, and the sole atomic reader now uses RCU, which is IRQ-safe. Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260810133711.42483-5-tiwai@suse.de
2026-08-10ALSA: seq: Use RCU for the client tableTakashi Iwai
The sequencer keeps a global table of clients (clienttab[]) indexed by client id, protected by the global clients_lock spinlock. The lookup snd_seq_client_use_ptr() reads a slot and takes a use_lock reference on the client, and this runs on the event delivery hot path: every dispatched event resolves its destination (and often source) client through it. The spinlock's only job on the read side is to make the "pointer is non-NULL" test and the reference increment indivisible with respect to the writer that nulls the slot and then drains the refcount. Clients come and go rarely but delivery happens constantly, so this is yet another read-mostly case as the port and subscriber lists. Convert the table to RCU: the read side now runs lock-free under rcu_read_lock() and takes the use_lock reference via rcu_dereference(), removing contention on the single global spinlock from the delivery path. The writers keep clients_lock (still needed to serialize slot allocation) and publish / unpublish via rcu_assign_pointer(); creation and destruction remain serialized at a higher level by register_mutex. As with the ports, the client is not freed via kfree_rcu(): its lifetime is governed by the use_lock refcount drained in seq_free_client1(). list_del under the old spinlock excluded a concurrent lookup from taking a new reference once the slot was nulled; rcu_assign_pointer(NULL) offers no such exclusion, so a reader still holding the old pointer can grab a reference after the unpublish. seq_free_client1() therefore calls synchronize_rcu() after nulling the slot and before snd_use_lock_sync(): once the grace period elapses no new reference can appear, and the existing drain then frees the client safely. clienttablock[] keeps its slot-reservation role (create/free are serialized by register_mutex); its read on the lookup path only gates module autoload, so a lockless read is harmless. Dropping the spinlock from the read path is safe: clients_lock is now taken only by the process-context writers, and the sole atomic reader uses RCU, which is IRQ-safe. Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260810133711.42483-4-tiwai@suse.de
2026-08-10ALSA: seq: Use RCU for the client port listTakashi Iwai
Each sequencer client keeps a list of its ports (ports_list_head) protected by both an rwlock (ports_lock) and a mutex (ports_mutex). The rwlock is taken read-side on the event delivery hot path: snd_seq_port_use_ptr() walks the list to resolve a port on every dispatched event, while the mutex serializes port creation/deletion. Ports change rarely but delivery happens constantly, so this is the another read-mostly case as the port subscriber list. Convert the port list traversal to RCU and drop the rwlock entirely; the existing ports_mutex keeps serializing the writers. The atomic delivery path (snd_seq_port_use_ptr(), snd_seq_port_query_nearest()) now runs lock-free under rcu_read_lock() instead of contending on the shared rwlock. The writers switch to list_add_tail_rcu()/list_del_rcu(). snd_seq_insert_port() now stores the port number and name before publishing the node so RCU readers only ever observe a fully initialized port. One drawback is that snd_seq_delete_all_ports() drops the O(1) splice trick and unlinks each port individually, though: the splice repointed the last port's ->next away from the list head, which would send a concurrent lockless reader off the end of the list. Unlike the subscriber objects, ports are not freed via kfree_rcu(): port_delete() must drain outstanding use_lock references (and run private_free()) synchronously. The rwlock previously guaranteed that no reader could take a new use_lock reference once the port was unlinked -- list_del under write_lock excluded snd_use_lock_use() under read_lock. list_del_rcu() offers no such exclusion, so a reader still traversing the list can grab a reference after the unlink. port_delete() therefore calls synchronize_rcu() after the port has been unlinked and before snd_use_lock_sync(): once the grace period elapses no new reference can appear, and the existing drain then frees the port safely. Dropping write_lock_irq() from the writers is safe: no writer runs in atomic/IRQ context, and the sole atomic reader now uses RCU, which is IRQ-safe. Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260810133711.42483-3-tiwai@suse.de
2026-08-10ALSA: seq: Use RCU for the port subscriber listTakashi Iwai
Each sequencer port keeps two subscriber groups (c_src and c_dest), each protected by both an rwlock (list_lock) and a rw_semaphore (list_mutex). The rwlock is taken read-side in the event delivery hot path (__deliver_to_subscribers()) for delivering every event to subscribers, while the mutex serializes subscribe/unsubscribe and covers the sleepable delivery and query walks. Subscriptions change rarely but delivery happens constantly, so this is a textbook read-mostly case. Convert the subscriber list traversal to RCU and drop the rwlock entirely while keeping the existing list_mutex for serializing the writers. The atomic delivery path now runs lock-free under rcu_read_lock() instead of contending on the shared rwlock. Along with the conversion to RCU, the subscriber lists are switched from list_head to hlist so that removal can use hlist_del_init_rcu(): it keeps the ->next pointer intact for concurrent readers while clearing ->pprev, which lets the double-deletion guard (added in commit 13d5e5d4725c) keep detecting an already-removed entry via hlist_unhashed(). Dropping write_lock_irq() from the writers is safe: no writer runs in atomic/IRQ context, and the sole atomic reader now uses RCU, which is IRQ-safe. Port lifetime handling (use_lock/closing drain in port_delete()) is orthogonal and unchanged. Note that the conversion to RCU has another merit: it automatically "fixes" the (rather false) lockdep warnings for the doubly read-locks of the same subscriber list, too. Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260810133711.42483-2-tiwai@suse.de
2026-07-30Merge branch 'for-linus' into for-nextTakashi Iwai
Pull 7.2 devel branch for applying further patches cleanly. Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-07-25ALSA: seq: Fix division by zero in initialize_timer()Norbert Szetei
A userspace-driven ALSA timer (SND_UTIMER) lets an unprivileged user set the backing snd_timer's hardware resolution to an arbitrary 64-bit value via SNDRV_TIMER_IOCTL_CREATE. snd_utimer_create() only rejects zero. When such a timer is bound to a sequencer queue, initialize_timer() computes the tick period as tmr->ticks = 1000000000 / (r * freq); where r is that user-controlled resolution and freq is the sequencer update rate in Hz, clamped to MIN_FREQUENCY..MAX_FREQUENCY (10..6250). A resolution of 2^63 makes the 64-bit product r * freq wrap to zero for any even freq, including DEFAULT_FREQUENCY (1000), so the division faults with a divide-by-zero. The division runs under tmr->lock with interrupts disabled, so the oops leaves the spinlock held and hangs the CPU. It is reachable by an unprivileged user with access to /dev/snd/timer and /dev/snd/seq. Oops: divide error: 0000 [#1] SMP KASAN PTI CPU: 7 UID: 1000 PID: 456 Comm: alsa_seq_utimer Not tainted 7.2.0-rc4+ RIP: 0010:initialize_timer.constprop.0+0x20a/0x2d0 snd_seq_timer_start+0x15e/0x2b0 snd_seq_control_queue+0x56f/0xba0 snd_seq_write+0x3e0/0x730 Reject an overflowing product with check_mul_overflow() and fall back to a single tick, which also avoids feeding a wrapped-but-nonzero divisor (e.g. 2^63 * 1000 mod 2^64 == 0, or other resolutions wrapping to a small value) into the period computation. Fixes: 37745918e0e7 ("ALSA: timer: Introduce virtual userspace-driven timers") Cc: <stable@vger.kernel.org> Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Norbert Szetei <norbert@doyensec.com> Link: https://patch.msgid.link/DF8A3844-AD5E-4B8A-9CFC-BD83C212BA38@doyensec.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-07-14ALSA: seq: close a re-opened queue timer in the destructorNorbert Szetei
queue_delete() closes the queue timer, then frees it. snd_seq_timer_close() clears q->timer->timeri. snd_use_lock_sync() then drains borrowers, and snd_seq_timer_delete() frees q->timer. A borrower can re-open the timer inside that window. A SET_QUEUE_CLIENT that took a queueptr() use_lock reference before the queue was unlinked runs snd_seq_timer_open() after the close. Open refuses re-open only while timeri is set, and the close just cleared it, so it re-opens timeri. snd_seq_timer_delete() does not close that instance. Its snd_seq_timer_stop() is a no-op, because running was cleared first. So it frees q->timer with the instance still live. The queue is freed next. The instance stays on the global timer with callback_data pointing at the freed queue. A non-owner START on the unlocked queue arms it. The next tick derefs the freed queue in snd_seq_timer_interrupt(). Reachable by an unprivileged user with access to /dev/snd/seq. No CAP and no queue ownership required. Close any lingering instance in the destructor. There, ->timeri can no longer change: the queue is unlinked and all use_lock borrowers have drained, so no snd_seq_queue_use() can re-open it. Close it before clearing q->timer. snd_timer_close() waits for any in-flight snd_seq_timer_interrupt() to finish, and that callback still reads q->timer (via snd_seq_check_queue()), so q->timer must stay valid until it drains. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Norbert Szetei <norbert@doyensec.com> Link: https://patch.msgid.link/422FDB81-2A68-47C7-A22D-2D3301E2E86D@doyensec.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-07-13ALSA: core: Clean up file_operations definitionsbui duc phuc
Align file_operations initializers with tabs to match the standard kernel coding style and improve readability. Signed-off-by: bui duc phuc <phucduc.bui@gmail.com> Link: https://patch.msgid.link/20260708140624.562403-1-phucduc.bui@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-07-03ALSA: seq: Drop redundant stream_open() return checkbui duc phuc
The previous conversion from nonseekable_open() to stream_open() retained the existing error check. Since stream_open() always returns 0, remove the dead error handling path. Signed-off-by: bui duc phuc <phucduc.bui@gmail.com> Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260702084445.519669-7-phucduc.bui@gmail.com
2026-06-24ALSA: seq: Fix uninitialised heap leak in snd_seq_event_dup()HyeongJun An
snd_seq_event_dup() copies an incoming event into a pool cell and, in the UMP-enabled build, clears the trailing cell->ump.raw.extra word that the memcpy() did not cover. The guard deciding whether to clear it compares the copied size against sizeof(cell->event): memcpy(&cell->ump, event, size); if (size < sizeof(cell->event)) cell->ump.raw.extra = 0; For a legacy (non-UMP) event, size == sizeof(struct snd_seq_event) == sizeof(cell->event), so the condition is false and the extra word keeps stale data. The cell pool is allocated with kvmalloc() (not zeroed) and cells are reused via a free list, so that word holds uninitialised heap or leftover event data. When such a cell is delivered to a UMP client (client->midi_version > 0) that set SNDRV_SEQ_FILTER_NO_CONVERT -- so the legacy event reaches it unconverted -- snd_seq_read() reads it out as the larger struct snd_seq_ump_event and copies the stale word to user space, a 4-byte kernel heap infoleak to an unprivileged /dev/snd/seq client. Compare against sizeof(cell->ump) instead, so the trailing word is zeroed for every event shorter than the UMP cell. Fixes: 46397622a3fa ("ALSA: seq: Add UMP support") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-8 Signed-off-by: HyeongJun An <sammiee5311@gmail.com> Link: https://patch.msgid.link/20260623233841.853326-1-sammiee5311@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-06-14ALSA: seq: avoid stale FIFO cells during resizeCen Zhang
snd_seq_fifo_resize() still needs to publish the replacement pool before it waits for FIFO users. A blocking snd_seq_read() holds f->use_lock while it sleeps, so concurrent senders must be able to queue to the new pool and wake that reader instead of failing against a closing old pool. However, snd_seq_fifo_event_in() duplicates an event before it takes f->lock, and snd_seq_read() can dequeue a cell and later call snd_seq_fifo_cell_putback() if copy_to_user() or snd_seq_expand_var_event() fails. If resize swaps f->pool and detaches oldhead in between, either path can relink an old-pool cell after the snapshot. That stale cell sits outside the drained oldhead list, keeps oldpool->counter elevated, and can leave snd_seq_pool_delete() waiting for the retired pool to drain. Keep the existing swap-before-wait ordering in snd_seq_fifo_resize(), but reject stale cells before any FIFO relink. Revalidate event-in cells under f->lock and retry them against the published replacement pool, and free stale putback cells instead of linking them back into the FIFO. The buggy scenario involves two paths, with each column showing the order within that path: resize path: relink path: 1. Allocate newpool. 1. Take f->use_lock. 2. Swap f->pool to newpool and 2. Duplicate or dequeue an old-pool detach oldhead. cell before oldpool closes. 3. Mark oldpool closing and 3. Reach a later relink point after wait for FIFO users. resize published newpool. 4. Free oldhead and delete 4. Relink the old-pool cell after oldpool. resize detached oldhead. 5. Drop f->use_lock. The reproducer reports a resize ioctl blocked in the expected pool teardown path: signal: resize iteration=98 target_pool=4 exceeded 250ms (elapsed=251ms) diagnostic: resize_tid=651 wchan=snd_seq_pool_done diagnostic: resize_tid=651 stack= snd_seq_pool_done+0x5b/0x140 snd_seq_pool_delete+0x7a/0x90 snd_seq_fifo_resize+0x193/0x1e0 snd_seq_ioctl_set_client_pool+0x214/0x260 snd_seq_ioctl+0x119/0x540 __x64_sys_ioctl+0xd1/0x120 do_syscall_64+0xbb/0x2f0 entry_SYSCALL_64_after_hwframe+0x77/0x7f A second run with larger pools hit the same target path: signal: resize iteration=32 target_pool=64 exceeded 250ms (elapsed=251ms) diagnostic: resize_tid=663 wchan=snd_seq_pool_done diagnostic: resize_tid=663 stack= snd_seq_pool_done+0x5b/0x140 snd_seq_pool_delete+0x7a/0x90 snd_seq_fifo_resize+0x193/0x1e0 snd_seq_ioctl_set_client_pool+0x214/0x260 snd_seq_ioctl+0x119/0x540 __x64_sys_ioctl+0xd1/0x120 do_syscall_64+0xbb/0x2f0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Fixes: 2d7d54002e39 ("ALSA: seq: Fix race during FIFO resize") Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Link: https://patch.msgid.link/20260614004801.3507773-2-zzzccc427@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-06-14ALSA: seq: oss: Serialize readq reset state with q->lockCen Zhang
snd_seq_oss_readq_clear() resets qlen, head, and tail without q->lock even though the normal reader and producer paths serialize the same ring state under that spinlock. A reset can therefore race snd_seq_oss_readq_free() or snd_seq_oss_readq_put_event() and leave stale records in the queue, drop freshly queued ones, or report the wrong readiness after wakeup. KCSAN reports a data race between snd_seq_oss_readq_clear() and snd_seq_oss_readq_free(). Take q->lock while clearing the ring and resetting input_time. Factor the enqueue logic into a caller-locked helper so snd_seq_oss_readq_put_timestamp() updates its suppression state under the same lock instead of racing the reset path. The buggy scenario involves two paths, with each column showing the order within that path: reset path: locked readq updater: 1. snd_seq_oss_reset() or 1. A reader or callback producer release reaches takes q->lock on the same queue. snd_seq_oss_readq_clear(). 2. snd_seq_oss_readq_clear() 2. The updater tests or modifies resets qlen, head, tail, qlen, head, and tail. and input_time. 3. snd_seq_oss_readq_clear() 3. The updater completes its wakes sleepers on read-modify-write sequence. q->midi_sleep. 4. Without q->lock, the reset 4. The resulting ring state drives can overlap the locked later reads and readiness. update. KCSAN reports: BUG: KCSAN: data-race in snd_seq_oss_readq_clear / snd_seq_oss_readq_free write to 0xffff8881069fe608 of 4 bytes by task 120516 on cpu 0: snd_seq_oss_readq_free+0x6c/0x80 snd_seq_oss_read+0xcb/0x250 odev_read+0x38/0x60 vfs_read+0xff/0x600 ksys_read+0xb4/0x140 __x64_sys_read+0x46/0x60 do_syscall_64+0xbb/0x2f0 entry_SYSCALL_64_after_hwframe+0x77/0x7f read to 0xffff8881069fe608 of 4 bytes by task 120517 on cpu 1: snd_seq_oss_readq_clear+0x1f/0x90 snd_seq_oss_reset+0xa7/0xf0 snd_seq_oss_ioctl+0x6f6/0x7e0 odev_ioctl+0x56/0xc0 __x64_sys_ioctl+0xd1/0x120 do_syscall_64+0xbb/0x2f0 entry_SYSCALL_64_after_hwframe+0x77/0x7f value changed: 0x00000001 -> 0x00000000 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Link: https://patch.msgid.link/20260614004801.3507773-1-zzzccc427@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-06-12ALSA: seq: Don't re-bounce the error eventTakashi Iwai
The error bouncing may fail again, and we have no check for re-bouncing. For avoiding the loop, add the event type check at bouncing, and stop re-bouncing if it's already a bounce error. Link: https://patch.msgid.link/20260612113350.407465-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-06-12ALSA: seq: Fix kernel heap address leak in bounce_error_event()HanQuan
The comment above bounce_error_event() documents that user clients should receive SNDRV_SEQ_EVENT_BOUNCE with the original event embedded as variable-length data, while kernel clients should receive SNDRV_SEQ_EVENT_KERNEL_ERROR with a quoted kernel pointer. However, the implementation unconditionally uses SNDRV_SEQ_EVENT_KERNEL_ERROR with data.quote.event set to the raw struct snd_seq_event pointer for all clients. When a bounce error event is delivered to a USER_CLIENT via snd_seq_read(), the kernel heap address in data.quote.event is exposed to userspace through copy_to_user() in the fixed-length branch. This is a distinct leak path from the one addressed by commit 705dd6dcbc0e ("ALSA: seq: Clear variable event pointer on read"), which sanitizes data.ext.ptr in the variable-length branch of snd_seq_read(). The bounce_error_event() leak uses fixed-length events that take the else branch where no sanitization occurs. Differentiate the bounce event by client type. For USER_CLIENT, send SNDRV_SEQ_EVENT_BOUNCE with SNDRV_SEQ_EVENT_LENGTH_VARIABLE and data.ext pointing to the original event. The variable-length path in snd_seq_event_dup() copies the event data into chained cells, and snd_seq_expand_var_event() copies only the content -- never the pointer -- to userspace. For KERNEL_CLIENT, keep the existing SNDRV_SEQ_EVENT_KERNEL_ERROR behavior with the quoted pointer. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: HanQuan <eilaimemedsnaimel@gmail.com> Link: https://patch.msgid.link/20260612103222.2528305-1-eilaimemedsnaimel@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-06-10ALSA: timer: Manage timer object with krefTakashi Iwai
So far we've tried to address UAFs in ALSA timer code by applying the locks at various places, but the fundamental problem is that the timer object may be released while the belonging timer instance objects are still present and accessing to it. This patch is a more proper fix to address that issue, namely, by refcounting and keeping the timer object. The basic implementation is to use kref for the refcount of the timer object, and take/release the reference at assigning/releasing the instance, as well as at referring from ioctls or ALSA sequencer code. The reference from ioctl or ALSA sequencer is abstracted with snd_timeri_timer auto-cleanup. Note that this change assumes that the code already took the fix commit da3039e91d1f ("ALSA: timer: Forcibly close timer instances at closing"); otherwise the refcount may be unbalanced when the timer is freed while slave instances are still present. Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260609115100.806869-2-tiwai@suse.de
2026-06-07Merge branch 'for-linus' into for-nextTakashi Iwai
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-06-07ALSA: seq: Clear variable event pointer on readKyle Zeng
snd_seq_read() copies a queued variable-length event header to userspace before expanding the payload. Queued variable-length events use SNDRV_SEQ_EXT_CHAINED internally, and data.ext.ptr points at the first extension cell. The read side strips SNDRV_SEQ_EXT_* bits from data.ext.len before the copy, but it leaves data.ext.ptr untouched. A userspace sequencer client can therefore write a direct variable event to itself and read back the extension-cell kernel address from the returned header. Clear the temporary header pointer before copy_to_user(). The original queued event remains unchanged and is still passed to snd_seq_expand_var_event(), so payload expansion keeps using the internal chain. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Kyle Zeng <kylebot@openai.com> Link: https://patch.msgid.link/20260607004129.61345-1-kylebot@openai.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-06-06ALSA: seq: Fix partial userptr event expansionHyeongJun An
snd_seq_expand_var_event_at() clamps the number of bytes to copy to the remaining variable-event length, but passes the original buffer size to expand_var_event(). For SNDRV_SEQ_EXT_USRPTR events, expand_var_event() copies exactly the size argument from userspace. On the final chunk, when the remaining event data is shorter than the caller's buffer, this can read past the declared event data and can spuriously fail with -EFAULT if the extra bytes cross an unmapped page. Pass the clamped length instead. The chained and kernel-backed paths already reclamp in dump_var_event(), but the user-pointer path handles the size directly. Fixes: ea46f79709b6 ("ALSA: seq: Add snd_seq_expand_var_event_at() helper") Signed-off-by: HyeongJun An <sammiee5311@gmail.com> Link: https://patch.msgid.link/20260606040913.230213-1-sammiee5311@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-06-05ALSA: seq: dummy: fix UMP event stack overreadKyle Zeng
The dummy sequencer port forwards events by copying an incoming struct snd_seq_event into a stack temporary, rewriting source and destination, and dispatching the temporary to subscribers. That legacy event storage is smaller than struct snd_seq_ump_event. When a UMP event reaches the dummy client, the copy leaves the UMP flag set but only provides legacy-sized stack storage. The subscriber delivery path then uses snd_seq_event_packet_size() and copies a UMP-sized packet from that stack object, reading past the end of the temporary. Use the existing union __snd_seq_event storage and copy the packet size reported for the incoming event before rewriting the common routing fields. This preserves the full UMP packet for UMP events while keeping legacy event handling unchanged. Fixes: 32cb23a0f911 ("ALSA: seq: dummy: Allow UMP conversion") Signed-off-by: Kyle Zeng <kylebot@openai.com> Link: https://patch.msgid.link/20260605080204.32045-1-kylebot@openai.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-06-04ALSA: seq: oss: Use scoped cleanup for temporary MIDI use lockCássio Gabriel
The OSS sequencer write and out-of-band paths may receive a temporary snd_use_lock_t reference from snd_seq_oss_process_event(). This was added to keep MIDI device data alive until events with embedded SysEx data are dispatched. Use a scoped cleanup helper for that temporary reference. This keeps the lifetime rule local to the variable declaration and avoids future missing snd_use_lock_free() paths if these event handling paths gain more exits. No functional change is intended. Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260604-alsa-scoped-cleanups-v1-3-10c43152a728@gmail.com
2026-06-02ALSA: seq: oss: Reject reads that cannot fit the next eventCássio Gabriel
snd_seq_oss_read() checks whether the next queued OSS sequencer event fits in the remaining userspace buffer before removing it from the read queue. The check is inverted. It currently stops when the event is smaller than the remaining buffer, so a normal 4-byte event is not copied for an 8-byte read buffer. Conversely, an 8-byte event can be copied for a smaller read count. Break only when the remaining userspace buffer is smaller than the next event, and report -EINVAL if no complete event has been copied. This prevents an undersized read from looking like end-of-file while leaving the event queued for a later read with a large enough buffer. Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com> Link: https://patch.msgid.link/20260602-alsa-seq-oss-read-size-check-v1-1-10e59b1742e0@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-06-02ALSA: seq: Restore created port information after insertionCássio Gabriel
Commit 2ee646353cd5 ("ALSA: seq: Register kernel port with full information") split sequencer port creation from list insertion so a port can be filled before it becomes visible. However, snd_seq_ioctl_create_port() still copies port->addr back to the ioctl argument before snd_seq_insert_port() assigns the final port number. A successful SNDRV_SEQ_IOCTL_CREATE_PORT without SNDRV_SEQ_PORT_FLG_GIVEN_PORT can therefore report port -1 to userspace. Move the ioctl address copy after successful insertion, and keep the default "port-%d" name assignment from overwriting a caller-provided port name. This restores the observable behavior from before the split while keeping the port populated before publication. Fixes: 2ee646353cd5 ("ALSA: seq: Register kernel port with full information") Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com> Link: https://patch.msgid.link/20260602-alsa-seq-create-port-info-fix-v1-1-eec0280131e9@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-27ALSA: seq: midi: Serialize output teardown with event_inputZhang Cen
event_process_midi() borrows msynth->output_rfile.output and then passes the substream to dump_midi() and snd_rawmidi_kernel_write() without synchronizing with the output open/close transition. midisynth_use() also publishes output_rfile before snd_rawmidi_output_params() has finished. The last midisynth_unuse() can therefore release the same rawmidi file and free substream->runtime before snd_rawmidi_kernel_write1() takes its runtime buffer reference. That leaves the event_input path using a stale substream or runtime and can end in a NULL-deref or use-after-free. Fix this with two pieces of synchronization. Keep a short IRQ-safe spinlock only for publishing or clearing output_rfile and for pairing the output snapshot with an snd_use_lock_t reference. Once event_process_midi() has taken that in-flight reference, it drops the spinlock before calling snd_seq_dump_var_event(), dump_midi(), or snd_rawmidi_kernel_write(). midisynth_unuse() now detaches the visible rawmidi file under the same spinlock, waits for the in-flight writers to drain, and only then drains and releases the saved file. midisynth_use() likewise opens into a local snd_rawmidi_file and publishes it only after snd_rawmidi_output_params() succeeds. The buggy scenario involves two paths, with each column showing the order within that path: event_input path: last unuse path: 1. event_process_midi() snapshots 1. midisynth_unuse() starts output_rfile.output. tearing down output_rfile. 2. dump_midi() reaches 2. snd_rawmidi_kernel_release() snd_rawmidi_kernel_write() closes the output file. before runtime is pinned. 3. close_substream() frees 3. The callback keeps using substream->runtime. the borrowed substream. Validation reproduced this kernel report: KASAN null-ptr-deref in snd_rawmidi_kernel_write1+0x56/0x360 RIP: 0033:0x7fde7dd0837f RIP: 0010:snd_rawmidi_kernel_write1+0x56/0x360 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Assisted-by: Codex:gpt-5.5 Signed-off-by: Zhang Cen <rollkingzzc@gmail.com> Link: https://patch.msgid.link/20260527062948.3614025-1-rollkingzzc@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-27ALSA: seq: oss: Fix UAF at handling events with embedded SysEx dataTakashi Iwai
The OSS sequencer processes the input MIDI bytes into a sequencer event to be dispatched later (in snd_seq_oss_midi_putc() called from snd_seq_oss_process_event()). When it's a SysEx data, the event record contains data.ext.ptr pointer to the original SysEx bytes, and the referred data is copied into the pool afterwards at dispatching. The problem is that, if the sequencer port gets closed concurrently before the dispatch, the OSS sequencer core also releases the resources (in snd_seq_oss_midi_check_exit_port()), while the pending event may hold a stale pointer, eventually leading to a UAF at a later dispatch. Fortunately, there is already a refcounting mechanism (snd_use_lock_t) for the OSS MIDI device access, and for addressing the issue above, we just need to extend the refcount until the event gets dispatched. This patch extends snd_seq_oss_process_event() to give back the refcount object, which is in turn released after calling the sequencer dispatcher with the given event in the caller side. According to the original report, KASAN report as below: KASAN slab-use-after-free in snd_seq_event_dup+0x40c/0x470 RIP: 0033:0x7f2cb66a6340 Read of size 6 Call trace: dump_stack_lvl+0x73/0xb0 (?:?) print_report+0xd1/0x650 (?:?) srso_alias_return_thunk+0x5/0xfbef5 (?:?) __virt_addr_valid+0x1a7/0x340 (?:?) kasan_complete_mode_report_info+0x64/0x200 (?:?) kasan_report+0xf7/0x130 (?:?) snd_seq_event_dup+0x40c/0x470 (?:?) kasan_check_range+0x10c/0x1c0 (?:?) __asan_memcpy+0x27/0x70 (?:?) snd_seq_event_dup+0x9/0x470 (?:?) snd_seq_client_enqueue_event+0x139/0x240 (?:?) _raw_spin_unlock_irqrestore+0x4b/0x60 (?:?) snd_seq_kernel_client_enqueue+0x102/0x120 (?:?) snd_seq_oss_write+0x416/0x4e0 (?:?) apparmor_file_permission+0x20/0x30 (?:?) odev_write+0x3b/0x60 (?:?) vfs_write+0x1ce/0x850 (?:?) lock_release+0xc8/0x2a0 (?:?) __kasan_check_write+0x18/0x20 (?:?) __mutex_unlock_slowpath+0x129/0x510 (?:?) ksys_write+0xe1/0x180 (?:?) mutex_unlock+0x16/0x20 (?:?) odev_ioctl+0x65/0xc0 (?:?) __x64_sys_write+0x46/0x60 (?:?) x64_sys_call+0x7d/0x20d0 (?:?) do_syscall_64+0xc1/0x360 (arch/x86/entry/syscall_64.c:87) entry_SYSCALL_64_after_hwframe+0x77/0x7f (?:?) Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-and-tested-by: Zhang Cen <rollkingzzc@gmail.com> Closes: https://lore.kernel.org/20260521233900.478153-1-rollkingzzc@gmail.com Link: https://patch.msgid.link/20260526152843.617503-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-26ALSA: seq: Remove arbitrary prioq insertion limitCássio Gabriel
The sequencer priority queue insertion path uses a hardcoded traversal limit of 10000 entries. The value is intended to catch a corrupted list, but it also becomes a real limit for valid queues. The event pool limit is per client, while a sequencer queue can be shared by multiple clients. A queue can therefore legitimately contain more than 10000 events. In that case, inserting an event that has to be placed past the arbitrary limit fails with -EINVAL. Use the queue's own cell count as the traversal bound instead. This keeps the protection against inconsistent list accounting or cyclic lists without rejecting valid large queues. Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com> Link: https://patch.msgid.link/20260525-alsa-seq-prioq-limit-v1-1-16c348df5ff7@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-25ALSA: core: Mark some variables as __ro_after_initLen Bao
Some variables in the 'ALSA/core' are initialized only during the init phase in the '__init' functions and never changed. So, mark them as __ro_after_init to reduce the attack surface. Signed-off-by: Len Bao <len.bao@gmx.us> Link: https://patch.msgid.link/20260524162914.47764-1-len.bao@gmx.us Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-25Merge branch 'for-linus' into for-nextTakashi Iwai
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-20ALSA: seq: Serialize UMP output teardown with event_inputZhang Cen
seq_ump_process_event() borrows client->out_rfile.output without synchronizing with the first-open and last-close transition in seq_ump_client_open() and seq_ump_client_close(). The last output unuse can therefore drop opened[STR_OUT] to zero and release the rawmidi file while an in-flight event_input callback is still inside snd_rawmidi_kernel_write(). That leaves the rawmidi substream runtime exposed to teardown before the write path has taken its own buffer reference. Add a per-client rwlock for the event_input-visible output file. Publish a newly opened output file under the write side, and hold the read side from the output lookup through snd_rawmidi_kernel_write(). The last output close copies and clears the visible output file under the write side, then drops the lock and releases the saved rawmidi file. Use IRQ-safe rwlock guards because event_input can also be reached from atomic sequencer delivery. The buggy scenario involves two paths, with each column showing the order within that path: path A label: event_input path path B label: last unuse path 1. seq_ump_process_event() reads 1. seq_ump_client_close() client->out_rfile.output. drops opened[STR_OUT] to zero. 2. snd_rawmidi_kernel_write1() 2. snd_rawmidi_kernel_release() has not yet pinned runtime. closes the output file. 3. The writer continues using 3. close_substream() frees the borrowed substream. substream->runtime. This keeps the output substream and runtime alive for the full event_input write while keeping rawmidi release outside the rwlock. KASAN reproduced this as a slab-use-after-free in snd_rawmidi_kernel_write1(), with allocation through seq_ump_use()/snd_seq_port_connect() and free through seq_ump_unuse()/snd_seq_port_disconnect(). Suggested-by: Takashi Iwai <tiwai@suse.de> Validation reproduced this kernel report: KASAN slab-use-after-free in snd_rawmidi_kernel_write1+0x9d/0x400 RIP: 0033:0x7f5528af837f Read of size 8 Call trace: dump_stack_lvl+0x73/0xb0 (?:?) print_report+0xd1/0x650 (?:?) srso_alias_return_thunk+0x5/0xfbef5 (?:?) __virt_addr_valid+0x1a7/0x340 (?:?) kasan_complete_mode_report_info+0x64/0x200 (?:?) kasan_report+0xf7/0x130 (?:?) snd_rawmidi_kernel_write1+0x9d/0x400 (?:?) __asan_load8+0x82/0xb0 (?:?) update_stack_state+0x1ef/0x2d0 (?:?) snd_rawmidi_kernel_write+0x1a/0x20 (?:?) seq_ump_process_event+0xd4/0x120 (sound/core/seq/seq_ump_client.c:82) __snd_seq_deliver_single_event+0x8a/0xe0 (?:?) snd_seq_deliver_from_ump+0x2b2/0xd60 (?:?) lock_acquire+0x14e/0x2e0 (?:?) find_held_lock+0x31/0x90 (?:?) snd_seq_port_use_ptr+0xa6/0xe0 (?:?) __kasan_check_write+0x18/0x20 (?:?) do_raw_read_unlock+0x32/0xa0 (?:?) _raw_read_unlock+0x26/0x50 (?:?) snd_seq_deliver_single_event+0x45c/0x4b0 (?:?) snd_seq_deliver_event+0x10d/0x1b0 (?:?) snd_seq_client_enqueue_event+0x192/0x240 (?:?) snd_seq_write+0x2cd/0x450 (?:?) apparmor_file_permission+0x20/0x30 (?:?) security_file_permission+0x51/0x60 (?:?) vfs_write+0x1ce/0x850 (?:?) __fget_files+0x12b/0x220 (?:?) lock_release+0xc8/0x2a0 (?:?) __rcu_read_unlock+0x74/0x2d0 (?:?) __fget_files+0x135/0x220 (?:?) ksys_write+0x15a/0x180 (?:?) rcu_is_watching+0x24/0x60 (?:?) __x64_sys_write+0x46/0x60 (?:?) x64_sys_call+0x7d/0x20d0 (?:?) do_syscall_64+0xc1/0x360 (arch/x86/entry/syscall_64.c:87) entry_SYSCALL_64_after_hwframe+0x77/0x7f (?:?) Fixes: 81fd444aa371 ("ALSA: seq: Bind UMP device") Signed-off-by: Zhang Cen <rollkingzzc@gmail.com> Link: https://patch.msgid.link/20260520103249.3048345-1-rollkingzzc@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-20ALSA: seq: Register kernel port with full informationTakashi Iwai
The current ALSA sequencer core tries to register the new kernel sequencer port on the list at first, then fill up the port information. This means that user-space may sneak the wrong information before the actual data is filled, which isn't ideal. Although the user-space should try to query the port info after the port registration notification is sent out, it'd be still better to have a port available with the full info from the beginning. This patch changes the sequencer port creation and registration procedure; now split to two steps, for creation and insertion, and the port is registered after the information is filled. Link: https://sashiko.dev/#/patchset/20260518194023.1667857-1-maoyixie.tju%40gmail.com Link: https://patch.msgid.link/20260519094254.465041-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-19Merge branch 'for-linus' into for-nextTakashi Iwai
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-19ALSA: seq: avoid past-the-end iterator in snd_seq_create_port()Maoyi Xie
snd_seq_create_port() walks client->ports_list_head looking for the ordered insertion point and on loop fall-through passes &p->list to list_add_tail(): list_for_each_entry(p, &client->ports_list_head, list) { if (p->addr.port == port) { kfree(new_port); return -EBUSY; } if (p->addr.port > num) break; ... } list_add_tail(&new_port->list, &p->list); When the loop walks all entries without break (e.g., the new port sorts last), p is past-the-end. &p->list aliases &client->ports_list_head (the list head) via container_of offset cancellation, so the insert lands at the list tail. That is the intended behaviour, but the access is undefined per C11 even though it works in practice. Track an explicit insert_before pointer initialised to the list head and overwritten to &p->list only when the loop breaks early. The observable behaviour is unchanged. Fixes: 9244b2c3079f ("[ALSA] alsa core: convert to list_for_each_entry*") Signed-off-by: Maoyi Xie <maoyixie.tju@gmail.com> Link: https://patch.msgid.link/20260518194023.1667857-3-maoyixie.tju@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-15Merge branch 'for-linus' into for-nextTakashi Iwai
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2026-05-15ALSA: seq: Use flexible array for MIDI channelsRosen Penev
Store MIDI channel entries in the MIDI channel set allocation instead of allocating them separately. This ties the channel array lifetime directly to the channel set, removes a separate allocation failure path, and lets __counted_by() describe the array bounds. Move the embedded emux channel set to the end of its containing structure so it can carry the flexible array. Assisted-by: Codex:GPT-5.5 Signed-off-by: Rosen Penev <rosenp@gmail.com> Link: https://patch.msgid.link/20260511075447.445350-1-rosenp@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>