From: Dhanavandhana Kannan Date: Fri, 22 Aug 2025 11:01:39 +0000 (+0530) Subject: nl80211: Fix crash by setting the drv->ctx properly X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ca266cc24d8705eb1a2a0857ad326e48b1408b20;p=thirdparty%2Fhostap.git nl80211: Fix crash by setting the drv->ctx properly During nl80211_stop_ap(), the active_links bitmap is updated, and the flink is reassigned to the next available active link in an MLD. active_links becomes zero when nl80211_stop_ap() is called for the last remaining link. For example: Consider a 3-link MLD (2.4 GHz, 5 GHz, and 6 GHz), with flink initially pointing to 2.4 GHz: nl80211_stop_ap() is called for 2.4 GHz -> flink is updated to 5 GHz. Then for 5 GHz -> flink is updated to 6 GHz. Finally for 6 GHz -> all links are stopped, and active_links becomes zero. Following this, when driver_nl80211_link_remove() is called and links are removed in a specific order (say 2.4 GHz first, then 6 GHz), the flink (which was pointing to 6 GHz) gets removed. However, the driver context (drv->ctx) still points to bss->ctx, which was associated with the now-deleted flink. If an event arrives from the driver after this removal, it tries to access drv->ctx, which now points to freed memory. This results in a crash due to invalid memory access. Fix by ensuring that flink is updated only during nl80211_remove_link() and not during nl80211_stop_ap(). Also ensure that drv->ctx is properly updated with flink->ctx during link removal and ensure that eloop timers are properly cancelled before changing the drv->ctx. Fixes: 2fe31050c248 ("nl80211: Use active_links to notify start/stop state of links") Signed-off-by: Dhanavandhana Kannan --- diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 693d846fe..5fb4529e5 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -9705,9 +9705,6 @@ fail: void nl80211_update_active_links(struct i802_bss *bss, int link_id) { - struct i802_link *link = &bss->links[link_id]; - size_t i; - wpa_printf(MSG_DEBUG, "nl80211: Update link (ifindex=%d link_id=%u)", bss->ifindex, link_id); @@ -9720,14 +9717,6 @@ void nl80211_update_active_links(struct i802_bss *bss, int link_id) wpa_driver_nl80211_del_beacon(bss, link_id); bss->active_links &= ~BIT(link_id); - - /* Choose new deflink if we are removing that link */ - if (bss->flink == link) { - for_each_link(bss->active_links, i) { - bss->flink = &bss->links[i]; - break; - } - } } @@ -9738,6 +9727,7 @@ int nl80211_remove_link(struct i802_bss *bss, int link_id) struct nl_msg *msg; int ret; u8 link_addr[ETH_ALEN]; + size_t i; wpa_printf(MSG_DEBUG, "nl80211: Remove link (ifindex=%d link_id=%u)", bss->ifindex, link_id); @@ -9763,6 +9753,14 @@ int nl80211_remove_link(struct i802_bss *bss, int link_id) if (bss->scan_link == link) bss->scan_link = NULL; + /* Choose new deflink if we are removing that link */ + if (bss->flink == link) { + for_each_link(bss->valid_links, i) { + bss->flink = &bss->links[i]; + break; + } + } + /* If this was the last link, reset default link */ if (!bss->valid_links) { /* TODO: Does keeping freq/bandwidth make sense? */ @@ -11095,10 +11093,14 @@ static int driver_nl80211_link_remove(void *priv, enum wpa_driver_if_type type, nl80211_remove_link(bss, link_id); - bss->ctx = bss->flink->ctx; - - if (drv->first_bss == bss && bss->valid_links) + if (drv->ctx == bss->ctx) { + eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, + drv, drv->ctx); + bss->ctx = bss->flink->ctx; drv->ctx = bss->ctx; + } else { + bss->ctx = bss->flink->ctx; + } if (!bss->valid_links) { void *ctx = bss->ctx;