[PATCH RFC] wifi: mac80211: prevent destroying non-TDLS stations in TDLS operations

20 views
Skip to first unread message

syzbot

unread,
Aug 2, 2026, 5:52:12 PM (4 days ago) Aug 2
to syzkaller-upst...@googlegroups.com, syz...@lists.linux.dev
When userspace sends a NL80211_CMD_TDLS_OPER command with the
NL80211_TDLS_DISABLE_LINK operation, the request is handled by
ieee80211_tdls_oper(). The code for this operation directly calls
sta_info_destroy_addr() to destroy the station entry associated with the
provided MAC address. Unlike the NL80211_TDLS_ENABLE_LINK case, which
correctly verifies that the target station exists and is actually a TDLS
peer, the disable link path blindly destroys whatever station matches the
MAC address.

If the provided MAC address is the AP's MAC address, this causes the AP's
station entry to be destroyed while the interface is still associated.
Later, when the driver attempts to send a probe request to the AP, it looks
up the AP's station entry, which returns NULL, triggering a warning in
ieee80211_mgd_probe_ap_send():

WARNING: net/mac80211/mlme.c:4898 at
ieee80211_mgd_probe_ap_send+0x497/0x560 net/mac80211/mlme.c:4898
RIP: 0010:ieee80211_mgd_probe_ap_send+0x497/0x560 net/mac80211/mlme.c:4898
Call Trace:
<TASK>
cfg80211_wiphy_work+0x29e/0x420 net/wireless/core.c:538
process_one_work kernel/workqueue.c:3322 [inline]
process_scheduled_works+0xa8e/0x14e0 kernel/workqueue.c:3405
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3486
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>

A similar issue exists in ieee80211_tdls_peer_del_work() which is queued by
ieee80211_tdls_mgmt_setup(). If a TDLS setup request is sent with the AP's
MAC address, the AP's station entry will be destroyed when the setup
timeout expires.

Fix this by explicitly verifying that the station exists and is a TDLS peer
(sta->sta.tdls == true) before destroying it in both ieee80211_tdls_oper()
and ieee80211_tdls_peer_del_work().

Fixes: dfe018bf9953 ("mac80211: handle TDLS high-level commands and frames")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: syzbot+a59b52...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=a59b5291776979816910
Link: https://syzkaller.appspot.com/ai_job?id=52e47481-fb24-46ec-8402-1f14cf87081f
To: "Johannes Berg" <joha...@sipsolutions.net>
To: <linux-w...@vger.kernel.org>
To: "Arik Nemtsov" <ar...@wizery.com>
Cc: <linux-...@vger.kernel.org>

---
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index ffd575a8d..24297552f 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -33,8 +33,12 @@ void ieee80211_tdls_peer_del_work(struct wiphy *wiphy, struct wiphy_work *wk)
lockdep_assert_wiphy(local->hw.wiphy);

if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer)) {
+ struct sta_info *sta;
+
tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->u.mgd.tdls_peer);
- sta_info_destroy_addr(sdata, sdata->u.mgd.tdls_peer);
+ sta = sta_info_get(sdata, sdata->u.mgd.tdls_peer);
+ if (sta && sta->sta.tdls)
+ __sta_info_destroy(sta);
eth_zero_addr(sdata->u.mgd.tdls_peer);
}
}
@@ -1462,6 +1466,10 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
!ether_addr_equal(sdata->u.mgd.tdls_peer, peer));
break;
case NL80211_TDLS_DISABLE_LINK:
+ sta = sta_info_get(sdata, peer);
+ if (!sta || !sta->sta.tdls)
+ return -ENOLINK;
+
/*
* The teardown message in ieee80211_tdls_mgmt_teardown() was
* created while the queues were stopped, so it might still be
@@ -1476,7 +1484,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
/* flush a potentially queued teardown packet */
ieee80211_flush_queues(local, sdata, false);

- ret = sta_info_destroy_addr(sdata, peer);
+ ret = __sta_info_destroy(sta);

iee80211_tdls_recalc_ht_protection(sdata, NULL);



base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
--
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at syzk...@googlegroups.com.

Krystian Kaniewski

unread,
Aug 3, 2026, 9:32:55 AM (4 days ago) Aug 3
to syzbot, syzkaller-upst...@googlegroups.com, syz...@lists.linux.dev
Preserve the TDLS-peer validation in both touched paths. The verified bug is
that NL80211_TDLS_DISABLE_LINK accepts the associated AP's address and
blindly
destroys its non-TDLS station entry; later AP probing cannot find that
station
and triggers the reported !sta warning. The delayed setup cleanup has
the same
destructive risk because setup currently records any existing station
address,
not necessarily a TDLS peer.

Correct the delayed-work hunk so it does not ignore the return value of
__sta_info_destroy(), which is declared __must_check and causes an
-Wunused-result compiler warning. The smallest correction is to retain the
new sta_info_get() plus sta->sta.tdls validation, but call the existing
sta_info_destroy_addr(sdata, sdata->u.mgd.tdls_peer) wrapper after that
check.
Alternatively, explicitly consume and handle the internal helper's result.

Keep the early missing/non-TDLS rejection in NL80211_TDLS_DISABLE_LINK, the
queue flushing and recalculation order for valid TDLS peers, and the
existing
commit message and tags. Do not add unrelated cleanup or broaden the change.

syzbot

unread,
Aug 3, 2026, 11:36:42 AM (4 days ago) Aug 3
to syzkaller-upst...@googlegroups.com, krystianm...@gmail.com, syz...@lists.linux.dev
Link: https://syzkaller.appspot.com/ai_job?id=986e342d-a720-47ab-84bf-e8be0e8b70e5
To: "Johannes Berg" <joha...@sipsolutions.net>
To: <linux-w...@vger.kernel.org>
To: "Arik Nemtsov" <ar...@wizery.com>
Cc: <linux-...@vger.kernel.org>

---
v2:
- In ieee80211_tdls_peer_del_work(), use sta_info_destroy_addr() instead of __sta_info_destroy() to destroy the station.

v1:
https://lore.kernel.org/all/7f0c8fa8-559d-4fdf...@mail.kernel.org/T/
---
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index ffd575a8d..eef1dde1c 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -33,8 +33,12 @@ void ieee80211_tdls_peer_del_work(struct wiphy *wiphy, struct wiphy_work *wk)
lockdep_assert_wiphy(local->hw.wiphy);

if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer)) {
+ struct sta_info *sta;
+
tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->u.mgd.tdls_peer);
- sta_info_destroy_addr(sdata, sdata->u.mgd.tdls_peer);
+ sta = sta_info_get(sdata, sdata->u.mgd.tdls_peer);
+ if (sta && sta->sta.tdls)
+ sta_info_destroy_addr(sdata, sdata->u.mgd.tdls_peer);
eth_zero_addr(sdata->u.mgd.tdls_peer);
}
}
@@ -1462,6 +1466,10 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
!ether_addr_equal(sdata->u.mgd.tdls_peer, peer));
break;
case NL80211_TDLS_DISABLE_LINK:
+ sta = sta_info_get(sdata, peer);
+ if (!sta || !sta->sta.tdls)
+ return -ENOLINK;
+
/*
* The teardown message in ieee80211_tdls_mgmt_teardown() was
* created while the queues were stopped, so it might still be
@@ -1476,7 +1484,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
/* flush a potentially queued teardown packet */
ieee80211_flush_queues(local, sdata, false);

- ret = sta_info_destroy_addr(sdata, peer);
+ ret = __sta_info_destroy(sta);

iee80211_tdls_recalc_ht_protection(sdata, NULL);



base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff

Krystian Kaniewski

unread,
3:44 AM (20 hours ago) 3:44 AM
to syzbot, syzkaller-upst...@googlegroups.com, syz...@lists.linux.dev
#syz upstream
Reply all
Reply to author
Forward
0 new messages