diff options
author | Eyal Shapira <eyal@wizery.com> | 2012-08-02 11:30:24 +0300 |
---|---|---|
committer | Arik Nemtsov <arik@wizery.com> | 2012-08-02 12:57:44 +0300 |
commit | 6e72d7b7977bfd6310c38aa5d87de0982ddcbb4d (patch) | |
tree | 5347f4ef51ec4f0e2626334867a9e1beeac0a7ed /wpa_supplicant | |
parent | 2e35a027db58930422b191fe361d3220a2530d71 (diff) | |
download | external_wpa_supplicant_8_ti-6e72d7b7977bfd6310c38aa5d87de0982ddcbb4d.zip external_wpa_supplicant_8_ti-6e72d7b7977bfd6310c38aa5d87de0982ddcbb4d.tar.gz external_wpa_supplicant_8_ti-6e72d7b7977bfd6310c38aa5d87de0982ddcbb4d.tar.bz2 |
Fix use-after-free bug when removing a connected network
When removing a network to which wpa_s is currently connected
the network wpa_ssid struct is freed however wpa_s->current_ssid
keeps pointing to it.
current_ssid is being used later on when handling the disassoc
event. This has been seen to lead to wpa_s crash as well as
using corrupted data from wpa_s->current_ssid.
Fix this by refactoring the removal code into a new function and
do the disconnection which uses wpa_s->current_ssid before the
actual removal. The refactoring is required as preparation for
fixes in additional places where this bug exists like dbus.
Changed wpa_supplicant_disassociate to wpa_supplicant_deauthenticate
as there's a mix of these in different handlers of remove network
which doesn't seem right.
Signed-off-by: Eyal Shapira <eyal@wizery.com>
Diffstat (limited to 'wpa_supplicant')
-rw-r--r-- | wpa_supplicant/ctrl_iface.c | 60 | ||||
-rw-r--r-- | wpa_supplicant/wpa_supplicant.c | 57 | ||||
-rw-r--r-- | wpa_supplicant/wpa_supplicant_i.h | 3 |
3 files changed, 70 insertions, 50 deletions
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index ae19860..46c6845 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1809,62 +1809,24 @@ static int wpa_supplicant_ctrl_iface_remove_network( /* cmd: "<network id>" or "all" */ if (os_strcmp(cmd, "all") == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all"); - ssid = wpa_s->conf->ssid; - while (ssid) { - struct wpa_ssid *remove_ssid = ssid; - id = ssid->id; - ssid = ssid->next; - wpas_notify_network_removed(wpa_s, remove_ssid); - wpa_config_remove_network(wpa_s->conf, id); - } - 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); - wpa_supplicant_disassociate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); - } - return 0; - } - - id = atoi(cmd); - wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id); - - ssid = wpa_config_get_network(wpa_s->conf, id); - if (ssid) - wpas_notify_network_removed(wpa_s, ssid); - if (ssid == NULL || - wpa_config_remove_network(wpa_s->conf, id) < 0) { - wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " - "id=%d", id); - return -1; - } + ssid = NULL; + } else { + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id); - if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) { -#ifdef CONFIG_SME - wpa_s->sme.prev_bssid_set = 0; -#endif /* CONFIG_SME */ - /* - * Invalidate the EAP session cache if the current or - * previously used network is removed. - */ - eapol_sm_invalidate_cached_session(wpa_s->eapol); + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " + "network id=%d", id); + return -1; + } } - if (ssid == wpa_s->current_ssid) { - wpa_sm_set_config(wpa_s->wpa, NULL); - eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); - - wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); - } + wpa_supplicant_remove_network(wpa_s, ssid); return 0; } - static int wpa_supplicant_ctrl_iface_set_network( struct wpa_supplicant *wpa_s, char *cmd) { diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index d3ebb24..50e212a 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1610,6 +1610,63 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, wpa_supplicant_clear_connection(wpa_s, addr); } +/** + * wpa_supplicant_remove_network - Removes a configured network and disconnect + * if it's the currently connected network. + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network or %NULL + * + * Removes the specified network or all networks if no network specified. + */ +void wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct wpa_ssid *other_ssid; + + if (ssid == NULL) { + for (other_ssid = wpa_s->conf->ssid; other_ssid; + other_ssid = other_ssid->next) { + wpas_notify_network_removed(wpa_s, ssid); + if (other_ssid == 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); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + } + wpa_config_remove_network(wpa_s->conf, ssid->id); + } + + eapol_sm_invalidate_cached_session(wpa_s->eapol); + } else { + wpas_notify_network_removed(wpa_s, ssid); + + if (ssid == wpa_s->current_ssid || + wpa_s->current_ssid == NULL) { +#ifdef CONFIG_SME + wpa_s->sme.prev_bssid_set = 0; +#endif /* CONFIG_SME */ + /* + * Invalidate the EAP session cache if the current or + * previously used network is removed. + */ + eapol_sm_invalidate_cached_session(wpa_s->eapol); + } + + if (ssid == wpa_s->current_ssid) { + wpa_sm_set_config(wpa_s->wpa, NULL); + eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); + + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + } + + wpa_config_remove_network(wpa_s->conf, ssid->id); + } +} /** * wpa_supplicant_enable_network - Mark a configured network as enabled diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index b608f29..8323547 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -611,7 +611,8 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, int reason_code); void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s, int reason_code); - +void wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s, |