Linux IEEE 802.15.4 and 6LoWPAN development
 help / color / mirror / Atom feed
From: Ibrahim Hashimov <security@auditcode.ai>
To: alex.aring@gmail.com, miquel.raynal@bootlin.com,
	stefan@datenfreihafen.org
Cc: linux-wpan@vger.kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, stable@vger.kernel.org
Subject: [PATCH v2] mac802154: hold an interface reference across the scan worker
Date: Fri, 17 Jul 2026 12:58:09 +0200	[thread overview]
Message-ID: <20260717105810.26226-1-security@auditcode.ai> (raw)
In-Reply-To: <20260710140927.13228-1-security@auditcode.ai>

mac802154_scan_worker() captures the scanning sub-interface once under
RCU:

	sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(scan_req->wpan_dev);

and then, after rcu_read_unlock() and outside the rtnl, keeps
dereferencing sdata->dev: in the channel-change and restart failure
traces, in mac802154_transmit_beacon_req() (skb->dev = sdata->dev) for
active scans, in the final dev_dbg(), and in the end_scan
mac802154_scan_cleanup_locked() path. Nothing keeps that netdev alive
for the duration of the worker iteration.

A concurrent teardown of the scanning interface -- userspace issuing
NL802154_CMD_DEL_INTERFACE (ieee802154_if_remove() ->
unregister_netdevice()), or a full PHY removal via
ieee802154_unregister_hw() -> ieee802154_remove_interfaces() -- can run
as soon as the worker drops the rtnl between its two short
drv_set_channel()/drv_start() sections. The netdev is not freed
synchronously by unregister_netdevice(): it is queued to net_todo_list
and freed later from netdev_run_todo(), which drops the rtnl mutex
(__rtnl_unlock()) *before* netdev_wait_allrefs_any()/free_netdev(). The
freeing therefore runs with the rtnl not held, on whichever task next
drains net_todo_list. Holding the rtnl in the worker does not prevent
it, and the per-PHY IEEE802154_IS_SCANNING flag does not identify the
specific interface: a subsequent NEW_INTERFACE + TRIGGER_SCAN re-arms
the flag, so a stale worker iteration sails past an is-scanning recheck
and dereferences the already-freed netdev.

Triggering the race requires CAP_NET_ADMIN: both
NL802154_CMD_TRIGGER_SCAN and NL802154_CMD_DEL_INTERFACE are
GENL_ADMIN_PERM, reachable only from the initial user namespace, so
the attacker is a locally privileged (CAP_NET_ADMIN) user, not an
unprivileged local user or a remote peer.

KASAN slab-use-after-free, kworker reading the freed
net_device/ieee802154_sub_if_data (kmalloc-cg-4k) allocated and freed by
the racing NEW_INTERFACE/DEL_INTERFACE task:

  BUG: KASAN: slab-use-after-free in mac802154_scan_worker+0x... [mac802154]
  Read of size 8 ... by task kworker/u8:N
  Workqueue: phy0-mac-cmds mac802154_scan_worker [mac802154]
   mac802154_scan_worker
   process_one_work

Fix it by taking a reference on the interface while the RCU read lock is
still held -- so the netdev cannot be freed before the refcount is
raised -- and releasing it at every exit of the worker past that point.
This keeps sdata->dev valid for the whole iteration. The reference does
not defer the free indefinitely: a teardown started while it is held
simply blocks in netdev_run_todo() until the current iteration returns,
and it cannot self-deadlock the single-threaded mac_wq because the
unregistering task claims the net_todo_list entry under the rtnl, so the
blocking netdev_wait_allrefs_any() always runs on that task, not on the
worker.

Verified on a v6.19 KASAN build: racing DEL_INTERFACE against an
in-flight TRIGGER_SCAN reliably tripped a slab-use-after-free KASAN
report inside mac802154_scan_worker() before this patch, and the
same reproducer no longer triggers it with the fix applied.

Fixes: 57588c71177f ("mac802154: Handle passive scanning")
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
---
v2: trim the in-worker comment down to the essentials, as requested by
    Miquel Raynal. No functional change.

 net/mac802154/scan.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index 300d4584533e..5b4ea2a895cc 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -209,6 +209,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.
+	 */
+	dev_hold(sdata->dev);
+
 	wpan_phy = scan_req->wpan_phy;
 	scan_req_type = scan_req->type;
 	scan_req_duration = scan_req->duration;
@@ -262,12 +270,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);
+	dev_put(sdata->dev);
 	return;
 
 end_scan:
 	rtnl_lock();
 	mac802154_scan_cleanup_locked(local, sdata, false);
 	rtnl_unlock();
+	dev_put(sdata->dev);
 }
 
 int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
-- 
2.50.1 (Apple Git-155)

  parent reply	other threads:[~2026-07-17 10:58 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-10 14:09 [PATCH net] mac802154: hold an interface reference across the scan worker Ibrahim Hashimov
2026-07-17  8:57 ` Miquel Raynal
2026-07-17 10:58 ` Ibrahim Hashimov [this message]
2026-07-17 11:37   ` [PATCH v2] " Miquel Raynal

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=20260717105810.26226-1-security@auditcode.ai \
    --to=security@auditcode.ai \
    --cc=alex.aring@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-wpan@vger.kernel.org \
    --cc=miquel.raynal@bootlin.com \
    --cc=netdev@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=stefan@datenfreihafen.org \
    /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