From f2b3acc9d7b91fbaccfc9dd8d408252bda4f1be9 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 18 Oct 2014 16:20:51 +0300 Subject: [PATCH] P2P: Fix group interface removal through interface ctrl_iface It was possible to issue the P2P_GROUP_REMOVE command through the per-interface control interface. This resulted in freed memory getting accessed when trying to send the control interface response to the operation that ended up deleting the group interface. Fix this by postponing the removal operation until the caller has returned. Signed-off-by: Jouni Malinen --- wpa_supplicant/p2p_supplicant.c | 37 +++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 8dcceaea1..b4cef9e27 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -426,6 +426,37 @@ static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s, } +static void run_wpas_p2p_disconnect(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + wpa_printf(MSG_DEBUG, + "P2P: Complete previously requested removal of %s", + wpa_s->ifname); + wpas_p2p_disconnect(wpa_s); +} + + +static int wpas_p2p_disconnect_safely(struct wpa_supplicant *wpa_s, + struct wpa_supplicant *calling_wpa_s) +{ + if (calling_wpa_s == wpa_s && + wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) { + /* + * The calling wpa_s instance is going to be removed. Do that + * from an eloop callback to keep the instance available until + * the caller has returned. This my be needed, e.g., to provide + * control interface responses on the per-interface socket. + */ + if (eloop_register_timeout(0, 0, run_wpas_p2p_disconnect, + wpa_s, NULL) < 0) + return -1; + return 0; + } + + return wpas_p2p_disconnect(wpa_s); +} + + static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, enum p2p_group_removal_reason removal_reason) { @@ -545,6 +576,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, global = wpa_s->global; ifname = os_strdup(wpa_s->ifname); type = wpas_p2p_if_type(wpa_s->p2p_group_interface); + eloop_cancel_timeout(run_wpas_p2p_disconnect, wpa_s, NULL); wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0); wpa_s = global->ifaces; if (wpa_s && ifname) @@ -5023,6 +5055,7 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname) { struct wpa_global *global = wpa_s->global; + struct wpa_supplicant *calling_wpa_s = wpa_s; if (os_strcmp(ifname, "*") == 0) { struct wpa_supplicant *prev; @@ -5034,7 +5067,7 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname) NOT_P2P_GROUP_INTERFACE || (prev->current_ssid && prev->current_ssid->p2p_group)) - wpas_p2p_disconnect(prev); + wpas_p2p_disconnect_safely(prev, calling_wpa_s); } return 0; } @@ -5044,7 +5077,7 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname) break; } - return wpas_p2p_disconnect(wpa_s); + return wpas_p2p_disconnect_safely(wpa_s, calling_wpa_s); }