aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2015-02-08 09:38:56 (GMT)
committerJouni Malinen <j@w1.fi>2015-02-08 11:35:14 (GMT)
commitb0e669beebbb0d764c354f6ef7736c58f82681ec (patch)
treec0b3c4c56ba93bb0215cef073623d24e4dab4209 /wpa_supplicant
parent874057da4e11cf7a5e54e3360187d9342ea891a4 (diff)
downloadhostap-b0e669beebbb0d764c354f6ef7736c58f82681ec.zip
hostap-b0e669beebbb0d764c354f6ef7736c58f82681ec.tar.gz
hostap-b0e669beebbb0d764c354f6ef7736c58f82681ec.tar.bz2
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>
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/events.c29
-rw-r--r--wpa_supplicant/p2p_supplicant.c19
2 files changed, 35 insertions, 13 deletions
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index ad55241..c4bc02d 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -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);
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 9e1d665..e93c0a8 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -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;
}