From: Hyunjung Ko wcd_mbhc_deinit() drains two of the three works embedded in struct wcd_mbhc before freeing it - correct_plug_swch (via wcd_cancel_hs_detect_plug()) and mbhc_plug_detect_work - but not the button long-press delayed work mbhc_btn_dwork: mutex_lock(&mbhc->lock); wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); cancel_work_sync(&mbhc->mbhc_plug_detect_work); mutex_unlock(&mbhc->lock); kfree(mbhc); mbhc_btn_dwork is armed from the button-press interrupt handler wcd_mbhc_btn_press_handler() with a 400 ms delay: schedule_delayed_work(&mbhc->mbhc_btn_dwork, msecs_to_jiffies(400)); and its handler wcd_btn_long_press_fn() dereferences @mbhc (container_of(), mbhc->current_plug, mbhc->jack). wcd_mbhc_deinit() frees the MBHC interrupts first, which stops new work from being queued, but free_irq() does not cancel a delayed work that was already scheduled. If a button was pressed within ~400 ms of component removal, mbhc_btn_dwork is still pending when kfree(mbhc) runs, so wcd_btn_long_press_fn() later executes against freed memory (use-after-free). The freeing of mbhc was introduced by commit a5475829adcc ("ASoC: codecs: wcd-mbhc-v2: fix resource leaks on component remove"), which switched mbhc to kzalloc() and added the kfree(mbhc) above; the deinit path cancels correct_plug_swch (added with the multi-button support in 0e5c9e7ff899) and, later, mbhc_plug_detect_work (added in 0c105997eefd), but mbhc_btn_dwork has never been cancelled there. Use the existing wcd_mbhc_cancel_pending_work() helper, which cancels mbhc_btn_dwork (via wcd_cancel_btn_work()) and then correct_plug_swch, matching the other cancellation sites in this file and ensuring mbhc_btn_dwork is cancelled before wcd_cancel_hs_detect_plug() briefly drops mbhc->lock. Found by code review; not runtime-reproduced (requires WCD codec hardware and a button-press event racing component removal). Fixes: a5475829adcc ("ASoC: codecs: wcd-mbhc-v2: fix resource leaks on component remove") Cc: stable@vger.kernel.org Signed-off-by: Hyunjung Ko --- v2: - Use the existing wcd_mbhc_cancel_pending_work() helper instead of an open-coded cancel_delayed_work_sync(), per review - it cancels mbhc_btn_dwork before wcd_cancel_hs_detect_plug() drops the lock and matches the other cancellation sites. - Add Fixes: tag and correct the commit history in the changelog (the v1 reference to CVE-2023-53842 was inaccurate), per review. sound/soc/codecs/wcd-mbhc-v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -1623,7 +1623,7 @@ void wcd_mbhc_deinit(struct wcd_mbhc *mbhc) free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc); mutex_lock(&mbhc->lock); - wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); + wcd_mbhc_cancel_pending_work(mbhc); cancel_work_sync(&mbhc->mbhc_plug_detect_work); mutex_unlock(&mbhc->lock);