From 32162a4dab0e6a4ca7f886a01173b5f9b80843be Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 26 Jul 2010 15:52:03 -0700 Subject: [PATCH] mac80211: Fix key freeing to handle unlinked keys Key locking simplification removed key->sdata != NULL verification from ieee80211_key_free(). While that is fine for most use cases, there is one path where this function can be called with an unlinked key (i.e., key->sdata == NULL && key->local == NULL). This results in a NULL pointer dereference with the current implementation. This is known to happen at least with FT protocol when wpa_supplicant tries to configure the key before association. Avoid the issue by passing in the local pointer to ieee80211_key_free(). In addition, do not clear the key from hw_accel or debugfs if it has not yet been added. At least the hw_accel one could trigger another NULL pointer dereference. Signed-off-by: Jouni Malinen Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 6 +++--- net/mac80211/key.c | 13 ++++++------- net/mac80211/key.h | 3 ++- net/mac80211/sta_info.c | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b769567949be..dab6b8efe5fa 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -158,7 +158,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, if (mac_addr) { sta = sta_info_get_bss(sdata, mac_addr); if (!sta) { - ieee80211_key_free(key); + ieee80211_key_free(sdata->local, key); err = -ENOENT; goto out_unlock; } @@ -192,7 +192,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, goto out_unlock; if (sta->key) { - ieee80211_key_free(sta->key); + ieee80211_key_free(sdata->local, sta->key); WARN_ON(sta->key); ret = 0; } @@ -205,7 +205,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, goto out_unlock; } - ieee80211_key_free(sdata->keys[key_idx]); + ieee80211_key_free(sdata->local, sdata->keys[key_idx]); WARN_ON(sdata->keys[key_idx]); ret = 0; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 50d1cff23d8e..1b9d87ed143a 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -323,13 +323,15 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) if (!key) return; - ieee80211_key_disable_hw_accel(key); + if (key->local) + ieee80211_key_disable_hw_accel(key); if (key->conf.alg == ALG_CCMP) ieee80211_aes_key_free(key->u.ccmp.tfm); if (key->conf.alg == ALG_AES_CMAC) ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); - ieee80211_debugfs_key_remove(key); + if (key->local) + ieee80211_debugfs_key_remove(key); kfree(key); } @@ -410,15 +412,12 @@ static void __ieee80211_key_free(struct ieee80211_key *key) __ieee80211_key_destroy(key); } -void ieee80211_key_free(struct ieee80211_key *key) +void ieee80211_key_free(struct ieee80211_local *local, + struct ieee80211_key *key) { - struct ieee80211_local *local; - if (!key) return; - local = key->sdata->local; - mutex_lock(&local->key_mtx); __ieee80211_key_free(key); mutex_unlock(&local->key_mtx); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index a3849fa3fce8..b665bbb7a471 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -135,7 +135,8 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, void ieee80211_key_link(struct ieee80211_key *key, struct ieee80211_sub_if_data *sdata, struct sta_info *sta); -void ieee80211_key_free(struct ieee80211_key *key); +void ieee80211_key_free(struct ieee80211_local *local, + struct ieee80211_key *key); void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 67656cbf2b15..6d86f0c1ad04 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -647,7 +647,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) return ret; if (sta->key) { - ieee80211_key_free(sta->key); + ieee80211_key_free(local, sta->key); WARN_ON(sta->key); }