From 745fe9ebb49bdf21487ab7d145e1d2aa3eaae72d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 27 Aug 2025 12:51:42 +0300 Subject: [PATCH] GAS: Use more careful matching of pending queries 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 --- wpa_supplicant/gas_query.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c index 88564d518..b3ebac168 100644 --- a/wpa_supplicant/gas_query.c +++ b/wpa_supplicant/gas_query.c @@ -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; } -- 2.47.3