aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorEyal Shapira <eyal@wizery.com>2012-08-02 11:30:24 +0300
committerArik Nemtsov <arik@wizery.com>2012-08-02 12:57:44 +0300
commit6e72d7b7977bfd6310c38aa5d87de0982ddcbb4d (patch)
tree5347f4ef51ec4f0e2626334867a9e1beeac0a7ed /wpa_supplicant
parent2e35a027db58930422b191fe361d3220a2530d71 (diff)
downloadexternal_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.c60
-rw-r--r--wpa_supplicant/wpa_supplicant.c57
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h3
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,