[BUG REPORT] sound/usb: Fix Use-After-Free in snd-usb-audio error_timer during device disconnect
张建 <[email protected]>
| Newsgroups | gmane.linux.alsa.devel,gmane.linux.usb.general |
|---|---|
| Message-ID | <CAEoG+NRpPip1Eymi1ZSgG7FdYH2UkRneat2GJRWXL_M38xfD9w@mail.gmail.com> |
Hi Takashi and Linux USB/ALSA maintainers, We identified a reproducible Use-After-Free (UAF) kernel panic in sound/usb/midi.c during USB MIDI device hot-unplug under active URB transfers. The issue was reproduced on Qualcomm platforms (Snapdragon 8 Gen 3 Linux 6.1.145 / Android 14, Snapdragon 8 Elite Linux 6.6.77 / Android16 etc.). The crash consistently hits __run_timers (timer softirq) dereferencing poison pointer. Crash Trace [ 169.493907] I[ 1: surfaceflinger: 1794] Internal error: Oops - CFI: 00000000f2008234 [#1] PREEMPT SMP [ 169.493941] I[ 1: surfaceflinger: 1794] sec,qc-rst_exinfo soc:samsung,qcom-rst_exinfo: fault handler : unknown [ 169.495442] I[ 1: surfaceflinger: 1794] CPU: 1 PID: 1794 Comm: surfaceflinger Tainted: G S WC O 6.1.145-android14-11-3254743-abS9280ZCS6DZF2 #1 [ 169.495447] I[ 1: surfaceflinger: 1794] Hardware name: Samsung E3Q PROJECT (board-id,09) (DT) [ 169.495455] I[ 1: surfaceflinger: 1794] pstate: 02400005 (nzcv daif +PAN -UAO +TCO -DIT -SSBS BTYPE=--) [ 169.495464] I[ 1: surfaceflinger: 1794] pc : call_timer_fn+0x44/0x26c [ 169.495471] I[ 1: surfaceflinger: 1794] lr : __run_timers+0x1b8/0x30c [ 169.495475] I[ 1: surfaceflinger: 1794] sp : ffffffc00800be40 [ 169.495480] I[ 1: surfaceflinger: 1794] x29: ffffffc00800be40 x28: dead000000000122 x27: 0000000000000000 [ 169.495490] I[ 1: surfaceflinger: 1794] x26: ffffffc00800be90 x25: 0000000000000001 x24: ffffff8a713312b0 [ 169.495501] I[ 1: surfaceflinger: 1794] x23: ffffffc00a427000 x22: ffffff8868a70000 x21: ffffff804c485c40 [ 169.495511] I[ 1: surfaceflinger: 1794] x20: ffffff804c485c58 x19: 0000000000000100 x18: 0000000000000000 [ 169.495522] I[ 1: surfaceflinger: 1794] x17: 0000000091b4a83a x16: 0000000000000000 x15: 0000000000000000 [ 169.495532] I[ 1: surfaceflinger: 1794] x14: ffffff804c485c40 x13: 000000000000000d x12: 0000000000000028 [ 169.495542] I[ 1: surfaceflinger: 1794] x11: ffffffc00800be98 x10: ffffff8a71331240 x9 : 0000000100000100 [ 169.495553] I[ 1: surfaceflinger: 1794] x8 : 0000000100000100 x7 : 0000002776497736 x6 : 0000002776497736 [ 169.495563] I[ 1: surfaceflinger: 1794] x5 : 0000002776497736 x4 : 0000000000000001 x3 : 00000000000009c4 [ 169.495573] I[ 1: surfaceflinger: 1794] x2 : 00000000ffff808d x1 : ffffff804c485c58 x0 : ffffff804c485c40 [ 169.495584] I[ 1: surfaceflinger: 1794] Call trace: [ 169.495591] I[ 1: surfaceflinger: 1794] call_timer_fn+0x44/0x26c [ 169.495598] I[ 1: surfaceflinger: 1794] __run_timers+0x1b8/0x30c [ 169.495605] I[ 1: surfaceflinger: 1794] run_timer_softirq+0x24/0x4c [ 169.495614] I[ 1: surfaceflinger: 1794] handle_softirqs+0x120/0x3e0 [ 169.495621] I[ 1: surfaceflinger: 1794] __do_softirq+0x14/0x20 [ 169.495628] I[ 1: surfaceflinger: 1794] ____do_softirq+0x10/0x20 [ 169.495635] I[ 1: surfaceflinger: 1794] call_on_irq_stack+0x3c/0x74 [ 169.495641] I[ 1: surfaceflinger: 1794] do_softirq_own_stack+0x1c/0x2c [ 169.495648] I[ 1: surfaceflinger: 1794] __irq_exit_rcu+0x54/0xb4 [ 169.495655] I[ 1: surfaceflinger: 1794] irq_exit_rcu+0x10/0x1c [ 169.495665] I[ 1: surfaceflinger: 1794] el0_interrupt+0x54/0x174 [ 169.495671] I[ 1: surfaceflinger: 1794] __el0_irq_handler_common+0x18/0x28 [ 169.495677] I[ 1: surfaceflinger: 1794] el0t_64_irq_handler+0x10/0x1c [ 169.495683] I[ 1: surfaceflinger: 1794] el0t_64_irq+0x1a4/0x1a8 [ 169.495690] I[ 1: surfaceflinger: 1794] Code: 72950751 72b23691 6b11021f 54000040 (d4304680) [ 169.495696] I[ 1: surfaceflinger: 1794] ---[ end trace 0000000000000000 ]--- Root Cause & Race Condition There is a sequence defect in snd_usbmidi_disconnect() combined with the URB completion handler: 1. In snd_usbmidi_disconnect(), del_timer_sync(&umidi->error_timer) is invoked BEFORE killing in-flight IN URBs via usb_kill_urb(). 2. Prior to usb_kill_urb() finishing, an in-flight IN URB completes with an unconventional error status (e.g., -EPIPE) when USB disconnect. 3. snd_usbmidi_in_urb_complete() calls snd_usbmidi_urb_error(urb). When receiving non-disconnect error codes (This error code is outside the scope of the error codes handled by snd_usbmidi_urb_error.), it invokes mod_timer(&ep->umidi->error_timer, ...) without checking umidi->disconnected. 4. This re-arms error_timer AFTER del_timer_sync() has already executed. 5. snd_usbmidi_disconnect() completes and frees struct snd_usb_midi in snd_usbmidi_free. 6. Later when error_timer fires on deallocated memory, leading to a UAF panic in __run_timers. Please let us know your thoughts on this issue. Thanks!