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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2014-10-18 16:20:51 +03:00
parent 19d3a6e364
commit f2b3acc9d7

View file

@ -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, static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
enum p2p_group_removal_reason removal_reason) 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; global = wpa_s->global;
ifname = os_strdup(wpa_s->ifname); ifname = os_strdup(wpa_s->ifname);
type = wpas_p2p_if_type(wpa_s->p2p_group_interface); 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_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
wpa_s = global->ifaces; wpa_s = global->ifaces;
if (wpa_s && ifname) 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) int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
{ {
struct wpa_global *global = wpa_s->global; struct wpa_global *global = wpa_s->global;
struct wpa_supplicant *calling_wpa_s = wpa_s;
if (os_strcmp(ifname, "*") == 0) { if (os_strcmp(ifname, "*") == 0) {
struct wpa_supplicant *prev; 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 || NOT_P2P_GROUP_INTERFACE ||
(prev->current_ssid && (prev->current_ssid &&
prev->current_ssid->p2p_group)) prev->current_ssid->p2p_group))
wpas_p2p_disconnect(prev); wpas_p2p_disconnect_safely(prev, calling_wpa_s);
} }
return 0; return 0;
} }
@ -5044,7 +5077,7 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
break; break;
} }
return wpas_p2p_disconnect(wpa_s); return wpas_p2p_disconnect_safely(wpa_s, calling_wpa_s);
} }