mac802154: hold an interface reference across the scan worker
Subsystems (4)
PATCH v3 1/1 mac802154: hold an interface reference across the scan worker
mac802154_scan_worker() captures the scanning sub-interface under RCU and then keeps dereferencing sdata->dev after rcu_read_unlock() and outside the rtnl -- in the failure traces, in mac802154_transmit_beacon_req() (skb->dev = sdata->dev), and in the end_scan cleanup. Nothing keeps that netdev alive across the worker iteration.
A concurrent DEL_INTERFACE or PHY removal can unregister the interface once the worker drops the rtnl between its two drv_set_channel() sections. unregister_netdevice() frees the netdev asynchronously from netdev_run_todo() with the rtnl already dropped, so neither holding the rtnl nor the per-PHY IEEE802154_IS_SCANNING flag prevents a stale worker iteration from dereferencing the freed netdev -- a KASAN slab-use-after-free, reachable by racing TRIGGER_SCAN against DEL_INTERFACE (both CAP_NET_ADMIN).
Pin the netdev with netdev_hold() while the RCU read lock is still held, and release it at every worker exit.
---
v3: use netdev_hold()/netdev_put() with a stack tracker instead of
dev_hold()/dev_put(), per Jakub Kicinski. Posted standalone.
v2: trim the in-worker comment, per Miquel Raynal.
net/mac802154/scan.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
net/mac802154/scan.c +11 -0
@@ -180,6 +180,7 @@ void mac802154_scan_worker(struct work_struct *work)struct ieee802154_sub_if_data *sdata;unsigned int scan_duration =0 ;struct wpan_phy *wpan_phy; +netdevice_tracker dev_tracker;u8 scan_req_duration;u8 page, channel;int ret;
@@ -209,6 +210,14 @@ void mac802154_scan_worker(struct work_struct *work)return ; } +/* +* sdata->dev is dereferenced below after rcu_read_unlock() and outside +* the rtnl, and a concurrent DEL_INTERFACE / PHY teardown can free it +* asynchronously from netdev_run_todo(). Pin it with a reference taken +* while the RCU read lock is still held, and drop it at every exit. +*/ +netdev_hold (sdata->dev, &dev_tracker,GFP_ATOMIC ); + wpan_phy = scan_req->wpan_phy; scan_req_type = scan_req->type; scan_req_duration = scan_req->duration;
@@ -262,12 +271,14 @@ void mac802154_scan_worker(struct work_struct *work)"Scan page %u channel %u for %ums\n" , page, channel, jiffies_to_msecs(scan_duration));queue_delayed_work (local->mac_wq, &local->scan_work, scan_duration); +netdev_put (sdata->dev, &dev_tracker);return ; end_scan:rtnl_lock ();mac802154_scan_cleanup_locked (local, sdata, false);rtnl_unlock (); +netdev_put (sdata->dev, &dev_tracker); } int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
Signature · 1 line
2.50.1 (Apple Git-155)
This patch was applied to netdev/net.git (main) by Jakub Kicinski <[email protected]>:
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <[email protected]>:
Quoted 8 lines · On Tue, 21 Jul 2026 23:12:28 +0200 you wrote:
mac802154_scan_worker()captures the scanning sub-interface under RCU and then keeps dereferencingsdata->devafterrcu_read_unlock()and outside the rtnl -- in the failure traces, inmac802154_transmit_beacon_req()(skb->dev=sdata->dev), and in theend_scancleanup. Nothing keeps that netdev alive across the worker iteration.[...]
Here is the summary with links:
- [net,v3] mac802154: hold an interface reference across the scan worker
https://git.kernel.org/netdev/net/c/234e5e898b71
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html