On Thu, 21 Aug 2025 20:44:21 +0200 Arend van Spriel wrote: > > The brcmf_btcoex_detach() only shuts down the btcoex timer, if the > > flag timer_on is false. However, the brcmf_btcoex_timerfunc(), which > > runs as timer handler, sets timer_on to false. This creates a critical > > race condition: > > > > 1.If brcmf_btcoex_detach() is called while brcmf_btcoex_timerfunc() > > is executing, it may observe timer_on as false and skip the call to > > timer_shutdown_sync(). > > > > 2.The brcmf_btcoex_timerfunc() may then reschedule the brcmf_btcoex_info > > worker after the cancel_work_sync() has been executed. > > > > 3.Subsequently, the brcmf_btcoex_info structure is freed. > > > > 4.Finally, the rescheduled worker attempts to execute, leading to > > use-after-free bugs by accessing the freed brcmf_btcoex_info object. > > Thanks for the patch. Being a nit picker just wanted to day that the > use-after-free happens a bit earlier as the worker itself is contained > in struct brcmf_btcoex_info. Also the diagram below does not add much > more than the textual description above. Thank you very much for your guidance. The use-after-free bugs occur in two distinct scenarios, depending on the timing of when the brcmf_btcoex_info struct is freed relative to the execution of its worker thread. Scenario 1: Freed before the worker is scheduled The brcmf_btcoex_info is deallocated before the worker is scheduled. A race condition can occur when schedule_work(&bt_local->work) is called after the target memory has been freed. The sequence of events is detailed below: CPU0 | CPU1 brcmf_btcoex_detach | brcmf_btcoex_timerfunc | bt_local->timer_on = false; if (cfg->btcoex->timer_on) | ... | cancel_work_sync(); | ... | kfree(cfg->btcoex); // FREE | | schedule_work(&bt_local->work); // USE Scenario 2: Freed after the worker is scheduled The brcmf_btcoex_info is freed after the worker has been scheduled but before or during its execution. In this case, statements within the brcmf_btcoex_handler() worker — such as the container_of macro and subsequent dereferences of the brcmf_btcoex_info object will cause a use-after-free access. The following timeline illustrates this scenario: CPU0 | CPU1 brcmf_btcoex_detach | brcmf_btcoex_timerfunc | bt_local->timer_on = false; if (cfg->btcoex->timer_on) | ... | cancel_work_sync(); | ... | schedule_work(&bt_local->work); // Reschedule | kfree(cfg->btcoex); // FREE | brcmf_btcoex_handler() // Worker /* | btci = container_of(....); // USE The kfree() above could | ... also occur at any point | btci->vif; // USE during the worker's execution| */ | I would like to submit a v2 patch to make the description clearer. > > The following diagram illustrates this sequence of events: > > > > cpu0 cpu1 > > brcmf_btcoex_detach | brcmf_btcoex_timerfunc > > | bt_local->timer_on = false; > > if (cfg->btcoex->timer_on) | > > ... | > > cancel_work_sync(); | > > ... | schedule_work() //reschedule > > kfree(cfg->btcoex);//free | > > | brcmf_btcoex_handler() //worker > > | btci-> //use > > > > To resolve this race condition, drop the conditional check and call > > timer_shutdown_sync() directly. It can deactivate the timer reliably, > > regardless of its current state. Once stopped, the timer_on state is > > then set to false. > > However, no reason to stop this patch from going in so... > > Acked-by: Arend van Spriel <arend.vanspriel@xxxxxxxxxxxx> > > > Fixes: 61730d4dfffc ("brcmfmac: support critical protocol API for DHCP") > > Signed-off-by: Duoming Zhou <duoming@xxxxxxxxxx> > > --- > > drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c | 6 ++---- > > 1 file changed, 2 insertions(+), 4 deletions(-) Best regards, Duoming Zhou