From 4b96fafcd8688f4222cf065038ab406f7083d86d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 19 Aug 2020 19:09:35 -0700 Subject: [PATCH] D-Bus: Share 'remove all networks' with CLI The D-Bus implementation of RemoveAllNetworks differs wildly from the CLI implementation. Let's share the implementations. This resolves use-after-free bugs I noticed, where we continue to use the 'wpa_s->current_ssid' wpa_ssid object after freeing it, because we didn't bother to disconnect from (and set to NULL) current_ssid before freeing it. Signed-off-by: Brian Norris --- wpa_supplicant/ctrl_iface.c | 28 +-------------- wpa_supplicant/dbus/dbus_new_handlers.c | 24 +------------ wpa_supplicant/wpa_supplicant.c | 46 +++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant_i.h | 1 + 4 files changed, 49 insertions(+), 50 deletions(-) diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 1bb18bdd1..76a3ed618 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -3480,38 +3480,12 @@ static int wpa_supplicant_ctrl_iface_remove_network( struct wpa_supplicant *wpa_s, char *cmd) { int id; - struct wpa_ssid *ssid; int result; /* cmd: "" or "all" */ if (os_strcmp(cmd, "all") == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all"); - if (wpa_s->sched_scanning) - wpa_supplicant_cancel_sched_scan(wpa_s); - - eapol_sm_invalidate_cached_session(wpa_s->eapol); - if (wpa_s->current_ssid) { -#ifdef CONFIG_SME - wpa_s->sme.prev_bssid_set = 0; -#endif /* CONFIG_SME */ - wpa_sm_set_config(wpa_s->wpa, NULL); - eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); - if (wpa_s->wpa_state >= WPA_AUTHENTICATING) - wpa_s->own_disconnect_req = 1; - wpa_supplicant_deauthenticate( - wpa_s, WLAN_REASON_DEAUTH_LEAVING); - } - ssid = wpa_s->conf->ssid; - while (ssid) { - struct wpa_ssid *remove_ssid = ssid; - id = ssid->id; - ssid = ssid->next; - if (wpa_s->last_ssid == remove_ssid) - wpa_s->last_ssid = NULL; - wpas_notify_network_removed(wpa_s, remove_ssid); - wpa_config_remove_network(wpa_s->conf, id); - } - return 0; + return wpa_supplicant_remove_all_networks(wpa_s); } id = atoi(cmd); diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 489d89a8d..86f85605a 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -1817,25 +1817,6 @@ out: } -static void remove_network(void *arg, struct wpa_ssid *ssid) -{ - struct wpa_supplicant *wpa_s = arg; - - wpas_notify_network_removed(wpa_s, ssid); - - if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) { - wpa_printf(MSG_ERROR, - "%s[dbus]: error occurred when removing network %d", - __func__, ssid->id); - return; - } - - if (ssid == wpa_s->current_ssid) - wpa_supplicant_deauthenticate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); -} - - /** * wpas_dbus_handler_remove_all_networks - Remove all configured networks * @message: Pointer to incoming dbus message @@ -1847,11 +1828,8 @@ static void remove_network(void *arg, struct wpa_ssid *ssid) DBusMessage * wpas_dbus_handler_remove_all_networks( DBusMessage *message, struct wpa_supplicant *wpa_s) { - if (wpa_s->sched_scanning) - wpa_supplicant_cancel_sched_scan(wpa_s); - /* NB: could check for failure and return an error */ - wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s); + wpa_supplicant_remove_all_networks(wpa_s); return NULL; } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 3404f7d01..01ba032f4 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -4122,6 +4122,52 @@ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id) } +/** + * wpa_supplicant_remove_all_networks - Remove all configured networks + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: 0 on success (errors are currently ignored) + * + * This function performs the following operations: + * 1. Remove all networks. + * 2. Send network removal notifications. + * 3. Update internal state machines. + * 4. Stop any running sched scans. + */ +int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid; + + if (wpa_s->sched_scanning) + wpa_supplicant_cancel_sched_scan(wpa_s); + + eapol_sm_invalidate_cached_session(wpa_s->eapol); + if (wpa_s->current_ssid) { +#ifdef CONFIG_SME + wpa_s->sme.prev_bssid_set = 0; +#endif /* CONFIG_SME */ + wpa_sm_set_config(wpa_s->wpa, NULL); + eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); + if (wpa_s->wpa_state >= WPA_AUTHENTICATING) + wpa_s->own_disconnect_req = 1; + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_DEAUTH_LEAVING); + } + ssid = wpa_s->conf->ssid; + while (ssid) { + struct wpa_ssid *remove_ssid = ssid; + int id; + + id = ssid->id; + ssid = ssid->next; + if (wpa_s->last_ssid == remove_ssid) + wpa_s->last_ssid = NULL; + wpas_notify_network_removed(wpa_s, remove_ssid); + wpa_config_remove_network(wpa_s->conf, id); + } + return 0; +} + + /** * wpa_supplicant_enable_network - Mark a configured network as enabled * @wpa_s: wpa_supplicant structure for a network interface diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 2df45c62c..ffaacf948 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1381,6 +1381,7 @@ void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s); struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s); int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id); +int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s); void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,