]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS ER: Fix deinit timeout handling with delayed/failing unsubscribe
authorJouni Malinen <jouni@qca.qualcomm.com>
Fri, 29 Nov 2013 15:45:30 +0000 (17:45 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 26 Dec 2013 18:50:28 +0000 (20:50 +0200)
The five second timeout to call wps_er_deinit_finish() could potentially
be left behind when removing the ER data based on some other event. This
could result in double-freeing of wps_er context killing the process,
e.g., if the WPS ER functionality is stopped while in the process of
unsubscribing from an AP and then restarted.

In addition, AP entries could still be present in the
er->ap_unsubscribing list when the deinit timeout hits. These entries
would still maintain HTTP context pointing to the ER which would be
freed here and as such, the following HTTP client callback could refer
to freed memory and kill the process. Fix this by freeing AP entries
from ap_unsubscribing list when ER is deinitialized from timeout even if
such AP entries have not completed unsubscription from UPnP events.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

src/wps/wps_er.c

index 56949970b424a17121788d3889ba4ff3b9f73056..e729617ce63fa27dd5fae770a8c0a6c0c1f33218 100644 (file)
@@ -185,10 +185,8 @@ static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap)
        dl_list_del(&ap->list);
        wps_er_ap_free(ap);
 
-       if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) {
-               eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
+       if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing))
                wps_er_deinit_finish(er, NULL);
-       }
 }
 
 
@@ -1347,9 +1345,19 @@ static void wps_er_deinit_finish(void *eloop_data, void *user_ctx)
        struct wps_er *er = eloop_data;
        void (*deinit_done_cb)(void *ctx);
        void *deinit_done_ctx;
+       struct wps_er_ap *ap, *tmp;
 
        wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit");
 
+       dl_list_for_each_safe(ap, tmp, &er->ap_unsubscribing, struct wps_er_ap,
+                             list) {
+               wpa_printf(MSG_DEBUG, "WPS ER: AP entry for %s (%s) still in ap_unsubscribing list - free it",
+                          inet_ntoa(ap->addr), ap->location);
+               dl_list_del(&ap->list);
+               wps_er_ap_free(ap);
+       }
+
+       eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
        deinit_done_cb = er->deinit_done_cb;
        deinit_done_ctx = er->deinit_done_ctx;
        os_free(er->ip_addr_text);