]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
GAS: Use more careful matching of pending queries
authorJouni Malinen <jouni.malinen@oss.qualcomm.com>
Wed, 27 Aug 2025 09:51:42 +0000 (12:51 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 27 Aug 2025 09:51:42 +0000 (12:51 +0300)
The earlier change to accept a response from an AP MLD MAC address ended
up opening an unlikely case where a single dialog token value might end
up mapping to more than a one pending query entry if one of those
entries was for a link address and another one for the MLD MAC address.
This could result in processing of a response freeing a pending query
that did not match the current radio work and with that, leaving behind
a radio work that points to freed memory. That could then result in
dereferencing that freed memory.

Avoid this corner case by picking the pending query that matches the
current radio work in a case where more than a single pending query
would match the received GAS response.

Fixes: bef417152190 ("GAS: Accept GAS response using AP MLD MAC address")
Signed-off-by: Jouni Malinen <jouni.malinen@oss.qualcomm.com>
wpa_supplicant/gas_query.c

index 88564d51890a69f3b0d5373815f16271f907baef..b3ebac1689946b59add4d6026fb8faca3d8eeac1 100644 (file)
@@ -199,19 +199,29 @@ void gas_query_deinit(struct gas_query *gas)
 static struct gas_query_pending *
 gas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token)
 {
-       struct gas_query_pending *q;
+       struct gas_query_pending *q, *alt = NULL;
        struct wpa_supplicant *wpa_s = gas->wpa_s;
+       void *ctx = gas->work ? gas->work->ctx : NULL;
 
+       /* Prefer a pending entry that matches with the current radio_work to
+        * avoid issues when freeing the pending entry in gas_query_free(). That
+        * case should not really happen, but due to the special case for
+        * AP MLD MAC address here, a same dialog token value might end up
+        * being pending and matching the same query. */
        dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
-               if (ether_addr_equal(q->addr, addr) &&
-                   q->dialog_token == dialog_token)
-                       return q;
-               if (wpa_s->valid_links &&
-                   ether_addr_equal(wpa_s->ap_mld_addr, addr) &&
-                   wpas_ap_link_address(wpa_s, q->addr))
-                       return q;
-       }
-       return NULL;
+               if ((ether_addr_equal(q->addr, addr) &&
+                    q->dialog_token == dialog_token) ||
+                   (wpa_s->valid_links &&
+                    ether_addr_equal(wpa_s->ap_mld_addr, addr) &&
+                    wpas_ap_link_address(wpa_s, q->addr))) {
+                       if (q == ctx)
+                               return q;
+                       if (!alt)
+                               alt = q;
+               }
+       }
+
+       return alt;
 }