P2P: Fix P2P_CONNECT-auto fallback to GO Neg with group interface

If a separate P2P group interface was used, P2P_CONNECT-auto fallback to
GO Negotiation could result in use of freed memory and segmentation
fault. This happened in cases where the peer GO was found in some old
scans, but not in the first scan triggered by the P2P_CONNECT-auto
command ("P2P: Peer was found running GO in older scan -> try to join
the group" shows up in the debug log). In addition, the GO would still
need to reply to PD Request to allow this code path to be triggered.

When five scans for the GO were completed in this sequence, the P2P
group interface was removed as part of falling back to GO Negotiation.
However, that ended up dereferencing the freed wpa_s instance at the end
of scan event processing. Fix this by reordering code a bit and breaking
out from EVENT_SCAN_RESULTS processing if the interface could have been
removed.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2015-02-08 11:38:56 +02:00
parent 874057da4e
commit b0e669beeb
2 changed files with 35 additions and 13 deletions

View File

@ -1448,7 +1448,12 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
int timeout_sec = wpa_s->scan_interval;
int timeout_usec = 0;
#ifdef CONFIG_P2P
if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
int res;
res = wpas_p2p_scan_no_go_seen(wpa_s);
if (res == 2)
return 2;
if (res == 1)
return 0;
if (wpa_s->p2p_in_provisioning ||
@ -1498,12 +1503,21 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
}
static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
static int wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
struct wpa_supplicant *ifs;
int res;
if (_wpa_supplicant_event_scan_results(wpa_s, data, 1) != 0) {
res = _wpa_supplicant_event_scan_results(wpa_s, data, 1);
if (res == 2) {
/*
* Interface may have been removed, so must not dereference
* wpa_s after this.
*/
return 1;
}
if (res != 0) {
/*
* If no scan results could be fetched, then no need to
* notify those interfaces that did not actually request
@ -1511,7 +1525,7 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
* interface, do not notify other interfaces to avoid concurrent
* operations during a connection attempt.
*/
return;
return 0;
}
/*
@ -1526,6 +1540,8 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
_wpa_supplicant_event_scan_results(ifs, data, 0);
}
}
return 0;
}
#endif /* CONFIG_NO_SCAN_PROCESSING */
@ -3088,7 +3104,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds",
diff.sec, diff.usec);
}
wpa_supplicant_event_scan_results(wpa_s, data);
if (wpa_supplicant_event_scan_results(wpa_s, data))
break; /* interface may have been removed */
wpa_s->own_scan_running = 0;
wpa_s->radio->external_scan_running = 0;
radio_work_check_next(wpa_s);

View File

@ -117,8 +117,8 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
void *timeout_ctx);
static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
int group_added);
static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
int group_added);
static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
static void wpas_stop_listen(void *ctx);
static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
@ -8184,16 +8184,18 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
}
static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
int group_added)
static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
int group_added)
{
struct wpa_supplicant *group = wpa_s;
int ret = 0;
if (wpa_s->global->p2p_group_formation)
group = wpa_s->global->p2p_group_formation;
wpa_s = wpa_s->parent;
offchannel_send_action_done(wpa_s);
if (group_added)
wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
ret = wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
@ -8202,11 +8204,14 @@ static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
wpa_s->p2p_pd_before_go_neg,
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht);
return ret;
}
int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
{
int res;
if (!wpa_s->p2p_fallback_to_go_neg ||
wpa_s->p2p_in_provisioning <= 5)
return 0;
@ -8216,9 +8221,9 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
"fallback to GO Negotiation");
wpas_p2p_fallback_to_go_neg(wpa_s, 1);
res = wpas_p2p_fallback_to_go_neg(wpa_s, 1);
return 1;
return res == 1 ? 2 : 1;
}