[PATCH] nl80211: Fix use-after-free during wiphy event handling

Gwen Weinholt gwen at weinholt.net
Fri Apr 18 04:55:00 PDT 2025


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 <gwen at weinholt.net>
---
 src/drivers/driver_nl80211.c       | 2 ++
 src/drivers/driver_nl80211.h       | 1 +
 src/drivers/driver_nl80211_event.c | 8 +++++---
 3 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 2cff5bba0..2ed20b915 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;
 			}
 		}
-- 
2.47.2




More information about the Hostap mailing list