CVE-2026-64586: wifi: brcmfmac: drain bus_reset work on device removal
In the Linux kernel, the following vulnerability has been resolved:
wifi: brcmfmac: drain busreset work on device removal
brcmffwcrashed() and the debugfs "reset" entry both schedule drvr->busreset, whose callback recovers drvr through containerof() and dereferences it. The removal path frees drvr (brcmffree -> wiphyfree) without draining the work, so a busreset callback pending or running during removal can outlive drvr.
Cancellation cannot live in brcmfdetach() or brcmffree(): the work callback reaches teardown through the bus .reset op (PCIe brcmfpciereset -> brcmfdetach; SDIO brcmfsdiobusreset -> brcmfsdiodremove -> brcmffree), so cancelling there would wait for the running work and deadlock.
Add a per-bus mutex (busresetlock) and route all arming through brcmfbusschedulereset(), which under the lock skips when the bus is marked removing. Each bus remove entry calls brcmfbuscancelresetwork(), which under the same lock sets removing and cancels the work. Holding the mutex across cancelworksync() makes the set-removing + drain step atomic. Every producer reaches the arming path from process context -- the PCIe firmware-halt notification runs in the threaded IRQ handler (brcmfpcieisrthread) and the SDIO hostmail path runs from the data workqueue -- so the mutex is taken only in sleepable contexts. Where applicable the remove entry first stops the firmware-crash producer: on PCIe mask the mailbox and synchronizeirq; on SDIO unregister the bus interrupt and cancel the data worker, which also reports firmware halts through brcmffwcrashed(). The mutex is initialized at bus allocation. The SDIO suspend power-off path frees drvr through the same brcmfsdiodremove() and takes the same lock; resume re-allows the work only on a successful re-probe.
Also guard brcmffwcrashed() against a NULL busif/drvr: it can fire before brcmfattach() wires up drvr, and it dereferences drvr (bphyerr/brcmfdevcoredump) before reaching the arming gate.
The busreset work is shared across buses, so the drain is applied to every remove path: PCIe (the .reset op introduced by the Fixes commit), SDIO (arms the same work through brcmffwcrashed()), and USB (via the debugfs "reset" entry). cancelworksync() drains a running or pending busreset work item before removal frees drvr, and patch 1/2 makes the scratch-buffer release safe when reset teardown has already released those DMA buffers.
This patch fixes the lifetime of the busreset work item itself. It does not attempt to address the separate, pre-existing lifetime of the asynchronous firmware completion started by the PCIe reset path. That callback needs its own lifetime/ownership protocol and is being tracked separately.
This issue was found by an in-house static analysis tool.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Implement a per-bus mutex named bus_reset_lock and require all arming of bus_reset to be routed through this lock to fix the lifetime/race of the bus_reset work item across buses.
Linux kernel brcmfmac (brcmf bus_reset work on device removal) bus_reset_lock mutex = Add per-bus mutex (bus_reset_lock) and route all arming through it - Configuration
In brcmf_fw_crashed(), add guards to handle a NULL bus_if and NULL drvr safely so firmware-crash callbacks cannot dereference NULL during teardown.
Linux kernel brcmfmac (brcmf_fw_crashed) brcmf_fw_crashed NULL handling = Guard brcmf_fw_crashed() against NULL bus_if/drvr - Configuration
Ensure cancellation of bus_reset work is not performed inside brcmf_detach() or brcmf_free(); move to a remove-path-controlled protocol that cancels/drains under the bus_reset_lock and manages drvr lifetime correctly.
Linux kernel brcmfmac (brcmf_detach/brcmf_free) Cancellation location for brcmf bus_reset work = Do not cancel in brcmf_detach() or brcmf_free() - Configuration
For every bus remove entry (PCIe reset op and SDIO remove), follow the order: under bus_reset_lock, set removing (set-removing + drain step atomic), stop/synchronize relevant producers (e.g., cancel work), then cancel the bus_reset work and dereference drvr only after the work item cannot run.
Linux kernel brcmfmac (remove path bus reset cancellation) Remove entry ordering = Stop then cancel/deref under lock per remove entry - Configuration
Under bus_reset_lock, in brcmf_bus_cancel_reset_work() mark the bus as removing; in brcmf_bus_schedule_reset() skip scheduling when the bus is marked removing or when brcmf_fw_crashed() indicates the firmware-crash state, preventing new work from being queued during teardown.
Linux kernel brcmfmac (bus_reset scheduling) brcmf_bus_cancel_reset_work / brcmf_bus_schedule_reset under lock = Cancel sets removing; schedule skips when bus is removing / crashed - Compensating control
During removal, ensure the bus-specific interrupt/work sources are stopped so producers cannot re-arm bus_reset: for PCIe mask the mailbox and synchronize_irq; for SDIO unregister the bus interrupt and cancel the data worker.
- Compensating control
Ensure debugfs 'reset' does not schedule bus_reset during teardown by routing its scheduling through the same bus_reset_lock and the removing/crashed checks so debugfs reset cannot race with remove/free.
Event History
Frequently Asked Questions
What is the severity of CVE-2026-64586?
CVE-2026-64586 has been assigned a risk score of 44, indicating a moderate severity level.
What are the impacts of CVE-2026-64586?
CVE-2026-64586 can lead to potential data corruption or system crashes due to incorrect handling of device removal in the Linux kernel.
How do I fix CVE-2026-64586?
To fix CVE-2026-64586, update the Linux kernel to the version that includes the patch addressing this vulnerability.
Which systems are affected by CVE-2026-64586?
CVE-2026-64586 affects systems running vulnerable versions of the Linux kernel that utilize the brcmfmac driver.
When was CVE-2026-64586 published?
CVE-2026-64586 was published on August 6, 2026.