summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZihan Xi <zihanx@nebusec.ai>2026-08-02 09:23:34 +0000
committerJakub Kicinski <kuba@kernel.org>2026-08-05 17:12:50 -0700
commit5f26a690e8efa54315e4922368daf54e0b8f5515 (patch)
tree219043ed0a1b4a2eaf790d72cd93f3bc57468d0d
parent8aecf0bbcc72605592134c917c222207d8f63ab0 (diff)
mac802154: fix netdev use-after-free in beacon worker
mac802154_beacon_worker() reads local->beacon_req under RCU and derives the sub-interface from the request, but then drops the RCU read lock and continues to use both sdata and the embedded wpan_dev. mac802154_stop_beacons_locked() cancels only pending beacon work, clears local->beacon_req and frees the request. A beacon worker that is already running can therefore continue after interface teardown and dereference the freed netdev private area. The scan worker already pins the netdev before leaving RCU. Apply the same lifetime rule to the beacon worker: take a netdev reference while the request is still protected by RCU, and release it on all paths that continue after the reference is acquired. Fixes: 3accf4762734 ("mac802154: Handle basic beaconing") Cc: stable@vger.kernel.org Reported-by: Vega <vega@nebusec.ai> Signed-off-by: Zihan Xi <zihanx@nebusec.ai> Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com> Link: https://patch.msgid.link/e9a3909c7a6281967961773ca841e860b8ecf40e.1785596603.git.zihanx@nebusec.ai Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--net/mac802154/scan.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index 65089826ff59..005338f89b75 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -415,6 +415,7 @@ void mac802154_beacon_worker(struct work_struct *work)
container_of(work, struct ieee802154_local, beacon_work.work);
struct cfg802154_beacon_request *beacon_req;
struct ieee802154_sub_if_data *sdata;
+ netdevice_tracker dev_tracker;
struct wpan_dev *wpan_dev;
u8 interval;
int ret;
@@ -427,12 +428,14 @@ void mac802154_beacon_worker(struct work_struct *work)
}
sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(beacon_req->wpan_dev);
+ netdev_hold(sdata->dev, &dev_tracker, GFP_ATOMIC);
/* Wait an arbitrary amount of time in case we cannot use the device */
if (local->suspended || !ieee802154_sdata_running(sdata)) {
rcu_read_unlock();
queue_delayed_work(local->mac_wq, &local->beacon_work,
msecs_to_jiffies(1000));
+ netdev_put(sdata->dev, &dev_tracker);
return;
}
@@ -450,6 +453,7 @@ void mac802154_beacon_worker(struct work_struct *work)
if (interval < IEEE802154_ACTIVE_SCAN_DURATION)
queue_delayed_work(local->mac_wq, &local->beacon_work,
local->beacon_interval);
+ netdev_put(sdata->dev, &dev_tracker);
}
int mac802154_stop_beacons_locked(struct ieee802154_local *local,