mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: 徐晗翔 <xuhx@hust.edu.cn>
To: perex@perex.cz, tiwai@suse.com
Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: ALSA: ctxfi: free atimer only after the timer IRQ is quiesced
Date: Fri, 13 Nov 2026 19:58:51 +0800 (GMT+08:00)	[thread overview]
Message-ID: <57529fbf.262c8.1a1d4c65987.Coremail.xuhx@hust.edu.cn> (raw)
In-Reply-To: <2026102727-data-sequel-ce41@gregkh>

`ct_timer_free()` frees `struct ct_timer` while the ctxfi timer IRQ handler can
still be executing, or can start after `snd_card_disconnect()` has already done
its single `synchronize_irq()`.  A handler that has passed the non-atomic
`hw->irq_callback` check then calls `ct_timer_interrupt()` with the freed
`atimer`; `free_irq()` only runs later, inside `ct_atc_destroy()` ->
`destroy_hw_obj()`.  This is a use-after-free on the timer object and can crash
or wedge the device during PCI removal/unbind.

The detailed description:

* Test environment / affected version

  Linux 7.3.0 source tree under review.  This report is source-level only: no
  ctxfi hardware was available and QEMU has no ctxfi device model, so no
  driver-specific reproducer was run.  The source paths/line numbers below are
  from 7.3.

* Mechanism

  `ct_timer_new()` (`sound/pci/ctxfi/cttimer.c:388-411`) installs the native
  timer callback by default when `!use_system_timer && hw->set_timer_irq`:

    hw->irq_callback_data = atimer;
    hw->irq_callback      = ct_timer_interrupt;

  The PCI IRQ handlers `ct_20k1_interrupt()` (`cthw20k1.c:1878-1891`) and
  `ct_20k2_interrupt()` (`cthw20k2.c:2045-2059`) do:

    if (hw->irq_callback)
        hw->irq_callback(hw->irq_callback_data, status);

  `ct_timer_interrupt()` (`cttimer.c:379-386`) then reads
  `timer->ops->interrupt` and calls it with `timer`.  Neither the check nor
  the two loads is atomic.

  `ct_timer_free()` (`cttimer.c:414-421`) does:

    struct hw *hw = atimer->atc->hw;
    hw->irq_callback = NULL;
    if (atimer->ops->free_global)
        atimer->ops->free_global(atimer);
    kfree(atimer);

  `ct_xfitimer_free_global()` only calls `ct_xfitimer_irq_stop()`; that helper
  stops the hardware only if `atimer->running` is set (`cttimer.c:137-145`).
  It does not wait for an in-flight IRQ handler.

  `ct_atc_destroy()` (`ctatc.c:1250-1286`) then calls `ct_timer_free()` at
  1257-1260, calls `destroy_hw_obj(atc->hw)` at 1274-1275, and only after that
  `kfree(atc)` at 1283.  `destroy_hw_obj()` -> `hw_card_shutdown()` ->
  `free_irq()` at `cthw20k1.c:1969` / `cthw20k2.c:2140`.  So `atc` itself is
  not the freed object in this window; `atimer` is freed before `free_irq()`.

* Why the existing synchronization does not close the window

  ctxfi does set `card->sync_irq` at `cthw20k1.c:1937` / `cthw20k2.c:2104`,
  and `snd_card_disconnect()` (`sound/core/init.c:495-562`) calls
  `synchronize_irq(card->sync_irq)` once at 540-541.  But that call happens
  before `ct_timer_free()`, only waits handlers that are running at that
  instant, and does not disable the IRQ line.  A new handler can enter after
  the one-time sync and before `free_irq()`.

  The `hw->irq_callback = NULL` store does not close the race either: a
  handler that loaded the callback pointer before the store can still call it.

* Trigger model

  Open a ctxfi device (native timer path, the default), then remove/unbind the
  PCI device while an interrupt is pending or arrives during teardown.  The
  window is between `ct_timer_free()` and `free_irq()`.  Consequence: UAF read
  of `atimer->ops` and timer fields in IRQ context; crash, stall, or potential
  control-flow corruption.

* Suggested direction

  After clearing `hw->irq_callback` and calling `free_global()`, but before
  `kfree(atimer)`, do:

    if (hw->irq >= 0)
        synchronize_irq(hw->irq);

  Alternatively, move `free_irq()` earlier so it precedes the timer free.
  Keep the existing `hw->irq == -1` initialization contract.


Please keep me in Cc; I am not subscribed to the lists.


Regards,
Hanxiang Xu
xuhx@hust.edu.cn

  parent reply	other threads:[~2026-11-13 11:59 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-27 12:35 usb: devio: usbdev_release() has no barrier against an in-flight async_completed() callback (use-after-free window on struct usb_dev_state)gregkh@linuxfoundation.org 徐晗翔
2026-10-27 14:12 ` Greg KH
2026-11-03 11:21   ` mm/slub: has_pcs_used() reads remote per-CPU sheaf state from flush_all_cpus_locked() without synchronization (data race; KCSAN blind spot: slub.o is uninstrumented) 徐晗翔
2026-11-04  9:41     ` Qing Wang
2026-11-04 10:07       ` Qing Wang
2026-11-03 11:30   ` futex/hrtimer: hrtimer_sleeper::task is read unsynchronized in 16 places on v7.3 -- the accessor series that fixes this is not in 7.3; please make sure it reaches the affected trees (backport nudge + stock-kernel KCSAN evidence) 徐晗翔
2026-11-03 11:48   ` cgroup: fork vs cgroup.procs write race in favordynmods mode -- v7.3 is affected; please make sure bf6fbf46b5ff reaches the stable trees (repro incl. uninstrumented natural hit) 徐晗翔
2026-11-03 14:51     ` Sasha Levin
2026-11-03 11:57   ` net: rtnetlink: rtnl_link_unregister() vs in-flight RTM_GETLINK dump readers -- v7.3 lacks the synchronize_rcu() fix (Fixes: 6b57ff21a310 family); A/B reproduction on stock 7.3 徐晗翔
2026-11-03 15:49     ` Eric Dumazet
2026-11-04 15:03     ` Sasha Levin
2026-11-03 12:07   ` wifi: wilc1000: SDIO/SPI remove destroys the srcu_struct before wiphy_unregister() -- late cfg80211 callbacks write through dangling srcu state (unfixed upstream; controlled + natural Oops) 徐晗翔
2026-11-03 12:10   ` gpio: gpiolib: final put of the gpio_device happens inside the SRCU read critical section on the setup-failure path -- deterministic use-after-free read at guard release (unfixed upstream) 徐晗翔
2026-11-05  8:52     ` Linus Walleij
2026-11-04 12:54   ` soc: qcom: pmic_glink_altmode: fix use-after-free on unbind (no cancel_work_sync for port work and enable_work) 徐晗翔
2026-11-04 13:04     ` Greg KH
2026-11-04 12:57   ` usb: typec: anx7411: unregister partner/altmodes before stopping the IRQ work -- use-after-free, double unregister, orphan partner on remove 徐晗翔
2026-11-04 13:28     ` Greg KH
2026-11-04 12:58   ` usb: typec: ucsi: deadlock on cros_ec unbind -- connector lock held across cancel_delayed_work_sync vs the mode-selection work's unbounded trylock polling 徐晗翔
2026-11-04 13:00   ` usb: typec: stusb160x/rt1719/hd3ss3220: IRQ thread vs remove -- double unregister / use-after-free on the partner and port 徐晗翔
2026-11-04 13:01   ` usb: typec: ucsi: displayport: data race on dp->header/ vdo_data/vdo_size -- work reads them unlocked while writers hold con->lock (VDM mismatch) 徐晗翔
2026-11-04 13:02   ` usb: typec: class: three lifetime/locking gaps around the mux/switch handles and mode_selection (drvdata UAF after provider unbind; no concurrent protocol for set/put; unlocked state_update vs delete) 徐晗翔
2026-11-10 12:56   ` driver core: uevent: netns teardown frees uevent_sock while a tagged uevent is still being broadcast (UAF) 徐晗翔
2026-11-10 13:00   ` 徐晗翔
2026-11-10 18:48     ` Greg KH
2026-11-10 13:05   ` ACPI: CPPC: per-CPU cpc_desc is freed on processor unbind without clearing the published pointer, causing UAF in cpufreq accessors 徐晗翔
2026-11-10 13:07   ` ACPI: CPPC: shared PCC subspace data can be freed while another CPU probes, reads, or tears it down 徐晗翔
2026-11-10 14:47     ` Christian Loehle
2026-11-10 13:11   ` ACPI: ACPICA: Reset can delete an event semaphore while another thread is blocked in Wait 徐晗翔
2026-11-10 13:14   ` power: supply: bq25890: pump-express work can call power_supply_changed after the psy is unregistered 徐晗翔
2026-11-10 13:17   ` power: supply: core: get/set property callbacks can run after unregister and read freed driver data 徐晗翔
2026-11-10 13:18   ` power: supply: core: system-battery enumeration can return an unregistered battery 徐晗翔
2026-11-10 13:21   ` power: supply: core: changed work can run after unregister and use freed LED triggers 徐晗翔
2026-11-10 13:23   ` power: supply: bq24190: IRQ handler can call power_supply_changed after the psy is unregistered 徐晗翔
2026-11-10 13:34   ` 徐晗翔
2026-11-11  7:17   ` genirq: NMI dispatch reads struct irqaction with no quiescence -- use-after-free across free_nmi()'s kfree (x86 verification on the arch-independent core path) 徐晗翔
2026-11-11  7:26   ` genirq: NMI API lacks the request_mutex / dev_id matching / idempotency semantics that free_irq() has -- double free_nmi releases chip PM and module references twice (verified) 徐晗翔
2026-11-11  7:30   ` kernfs: kernfs_drain()'s fast-path decision reads the active count without acquire ordering -- on weakly-ordered architectures the forced ->release()/unmap can be skipped 徐晗翔
2026-11-11 13:41     ` Greg KH
2026-11-13 11:58   ` 徐晗翔 [this message]
2026-11-13 12:03   ` ALSA: ctxfi: do not free a running system timer when timer_delete_sync_try() returns -1 (UAF) 徐晗翔
2026-11-13 12:04   ` ALSA: asihpi: free IRQ before snd_card_free()/HPI delete on HPI6205 removal (UAF) 徐晗翔
2026-11-13 12:06   ` ALSA: asihpi: quiesce PCM timer and IRQ before freeing dpcm on close (UAF) 徐晗翔
2026-11-13 12:15   ` ALSA: pcm: link-group walk in timer callback can use a closed substream's freed runtime (UAF) 徐晗翔
2026-11-13 12:28   ` ALSA: usb-audio: us144mkii: PCM close frees runtime while playback/feedback URB completion and capture work still use it (UAF) 徐晗翔
2026-11-13 12:29   ` ALSA: usb-audio: us144mkii: queued stop_pcm_work calls snd_pcm_stop() after PCM close and dereferences NULL runtime 徐晗翔
2026-11-13 12:33   ` sched/topology: old domain chains are queued for RCU freeing before the per-CPU pointers are updated, so a late reader can still dereference a freed sched_domain and sched_domain_shared (UAF) 徐晗翔

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=57529fbf.262c8.1a1d4c65987.Coremail.xuhx@hust.edu.cn \
    --to=xuhx@hust.edu.cn \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=perex@perex.cz \
    --cc=tiwai@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®