]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P: Fix P2P_CONNECT-auto fallback to GO Neg with group interface
authorJouni Malinen <j@w1.fi>
Sun, 8 Feb 2015 09:38:56 +0000 (11:38 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 8 Feb 2015 11:35:14 +0000 (13:35 +0200)
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>
wpa_supplicant/events.c
wpa_supplicant/p2p_supplicant.c

index ad55241848983e00a991cdff457e0993a22c83f7..c4bc02d1c5754c17945a51391cd40a7f415a9eb6 100644 (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);
index 9e1d66568f2de006b91385cc4fb092a0462157c3..e93c0a8f431f2d78852418db11c43ad06ea9dcbc 100644 (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;
 }