WPS ER: Fix deinit timeout handling with delayed/failing unsubscribe

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>
This commit is contained in:
Jouni Malinen 2013-11-29 17:45:30 +02:00 committed by Jouni Malinen
parent 7b75c30109
commit c9629476f3

View 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);