From: Gwen Weinholt Date: Fri, 18 Apr 2025 11:55:00 +0000 (+0200) Subject: nl80211: Fix use-after-free during wiphy event handling X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=207c17ec51d89dc890e4e499d80480c6811a2947;p=thirdparty%2Fhostap.git nl80211: Fix use-after-free during wiphy event handling When processing a NL80211_CMD_RADAR_DETECT event, the current driver interface instance may be deinitialized during the event handler. The event loop still holds a pointer to the old driver interface, but using it after deinit can cause a crash. A previous attempt to fix this relied on checking whether the interface pointer still appeared in the list of interfaces. However, that approach is incomplete: if malloc() returns the same pointer for a newly added interface (as observed occasionally on glibc 2.31), the check incorrectly assumes the original instance still exists. To fix this reliably, this commit introduces a unique instance ID in the wpa_driver_nl80211_data struct and uses that ID to check whether the original driver instance is still present in the list. Fixes: f13683720239 ("nl80211: Pass wiphy events to all affected interfaces") Signed-off-by: Gwen Weinholt --- diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 2055fb2f2..ea33b1e45 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2302,6 +2302,7 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, const char *driver_params, enum wpa_p2p_mode p2p_mode) { + static unsigned int next_unique_drv_id = 0; struct wpa_driver_nl80211_data *drv; struct i802_bss *bss; char path[128], buf[200], *pos; @@ -2334,6 +2335,7 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, drv->ctx = ctx; drv->hostapd = !!hostapd; drv->eapol_sock = -1; + drv->unique_drv_id = next_unique_drv_id++; /* * There is no driver capability flag for this, so assume it is diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index a6f92ff1e..bea87afeb 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -129,6 +129,7 @@ struct wpa_driver_nl80211_data { u16 mld_capa_and_ops; } iface_capa[NL80211_IFTYPE_MAX]; unsigned int num_iface_capa; + unsigned int unique_drv_id; int has_capability; int has_driver_key_mgmt; diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 8928b6e04..e7b67371a 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -4256,13 +4256,13 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, static bool nl80211_drv_in_list(struct nl80211_global *global, - struct wpa_driver_nl80211_data *drv) + unsigned int unique_drv_id) { struct wpa_driver_nl80211_data *tmp; dl_list_for_each(tmp, &global->interfaces, struct wpa_driver_nl80211_data, list) { - if (drv == tmp) + if (tmp->unique_drv_id == unique_drv_id) return true; } @@ -4322,6 +4322,8 @@ int process_global_event(struct nl_msg *msg, void *arg) dl_list_for_each_safe(drv, tmp, &global->interfaces, struct wpa_driver_nl80211_data, list) { + unsigned int unique_drv_id = drv->unique_drv_id; + for (bss = drv->first_bss; bss; bss = bss->next) { if (wiphy_idx_set) wiphy_idx = nl80211_get_wiphy_index(bss); @@ -4347,7 +4349,7 @@ int process_global_event(struct nl_msg *msg, void *arg) * e.g., due to NL80211_CMD_RADAR_DETECT event, * so need to stop the loop if that has * happened. */ - if (!nl80211_drv_in_list(global, drv)) + if (!nl80211_drv_in_list(global, unique_drv_id)) break; } }