]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Fix use-after-free during wiphy event handling
authorGwen Weinholt <gwen@weinholt.net>
Fri, 18 Apr 2025 11:55:00 +0000 (13:55 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 2 May 2025 20:49:31 +0000 (23:49 +0300)
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@weinholt.net>
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_event.c

index 2055fb2f2fbe0e2982b114b785e80416aef219a9..ea33b1e453e337ded4139efb55e2fb09487206cd 100644 (file)
@@ -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
index a6f92ff1e5920da9d35f5b9b3df27d22e7ce79c8..bea87afeb7edc376ce5974769dfcd36e013eb4e8 100644 (file)
@@ -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;
index 8928b6e04f7b480fe75af706cb519ab8bb15220d..e7b67371a576b6a1ccbbae970c73e77850a48926 100644 (file)
@@ -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;
                        }
                }