[PATCH v2] mac80211: reject station addition if AP or MLO link is inactive
Slawomir Stepien <[email protected]> Mon, 27 Jul 2026 09:45:26 +0200
| Newsgroups | dev.linux.lists.syzbot,org.kernel.vger.linux-kernel,org.kernel.vger.linux-wireless |
|---|---|
| Message-ID | <[email protected]> |
Currently, userspace can issue a netlink command to add a station to an AP or P2P GO interface before the AP has fully started, or before a specific MLO link has begun beaconing. This will e.g. lead to a WARN_ON trigger: WARNING: net/mac80211/rate.c:51 at rate_control_rate_init+0x5a6/0x630 ... Call Trace: <TASK> rate_control_rate_init_all_links+0xf4/0x190 net/mac80211/rate.c:84 sta_apply_auth_flags+0x1bc/0x430 net/mac80211/cfg.c:2152 sta_apply_parameters+0x126d/0x1b10 net/mac80211/cfg.c:2618 ieee80211_add_station+0x3de/0x700 net/mac80211/cfg.c:2684 rdev_add_station+0xfc/0x290 net/wireless/rdev-ops.h:201 nl80211_new_station+0x1b4e/0x1fd0 net/wireless/nl80211.c:9505 Fix this by introducing a two-tiered active state check in ieee80211_add_station(): 1. Global AP State: Add an early return if the main wdev is an AP or P2P GO and `sdata->u.ap.active` is false. 2. MLO Link State: For Wi-Fi 7 MLO setups, links can start asynchronously. Even if the global AP is active, a specific link might still be down. If a specific link_id is requested, ensure the underlying physical link has an allocated beacon (`link->u.ap.beacon`) before proceeding with sta_info allocation. Assisted-by: Gemini:3.1-pro Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=9bdc0c5998ab45b05030 Signed-off-by: Slawomir Stepien <[email protected]> --- v2: * Move the logic inside ieee80211_add_station() * Check both the non-MLO AP/P2P state and MLO link state * Update subject line and commit message v1: * https://lore.kernel.org/linux-wireless/[email protected]/ --- net/mac80211/cfg.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 43f142624d33..c3a580ad97e9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2637,19 +2637,24 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct wireless_dev *wdev, { struct ieee80211_local *local = wiphy_priv(wiphy); struct sta_info *sta; - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); int err; lockdep_assert_wiphy(local->hw.wiphy); + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_P2P_GO) { + if (!sdata->u.ap.active) + return -ENETDOWN; + } + if (params->vlan) { sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && sdata->vif.type != NL80211_IFTYPE_AP) return -EINVAL; - } else - sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + } if (ether_addr_equal(mac, sdata->vif.addr)) return -EINVAL; @@ -2663,17 +2668,37 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct wireless_dev *wdev, return -EINVAL; /* - * If we have a link ID, it can be a non-MLO station on an AP MLD, - * but we need to have a link_mac in that case as well, so use the - * STA's MAC address in that case. + * If we have a link ID: + * (1) check if it is valid, up and beaconing + * (2) it can be a non-MLO station on an AP MLD, but we need to have a + * link_mac in that case as well, so use the STA's MAC address in that + * case. */ - if (params->link_sta_params.link_id >= 0) + if (params->link_sta_params.link_id >= 0) { + int link_id = params->link_sta_params.link_id; + struct ieee80211_link_data *link; + struct ieee80211_sub_if_data *wdev_sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + + if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) + return -EINVAL; + + link = sdata_dereference(wdev_sdata->link[link_id], wdev_sdata); + if (!link) + return -ENOLINK; + + if (wdev_sdata->vif.type == NL80211_IFTYPE_AP || + wdev_sdata->vif.type == NL80211_IFTYPE_P2P_GO) { + if (!rcu_access_pointer(link->u.ap.beacon)) + return -ENETDOWN; + } + sta = sta_info_alloc_with_link(sdata, mac, - params->link_sta_params.link_id, + link_id, params->link_sta_params.link_mac ?: mac, GFP_KERNEL); - else + } else { sta = sta_info_alloc(sdata, mac, GFP_KERNEL); + } if (!sta) return -ENOMEM; -- 2.55.0