diff options
author | Jouni Malinen <j@w1.fi> | 2010-07-26 18:52:03 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-07-27 14:59:58 -0400 |
commit | 32162a4dab0e6a4ca7f886a01173b5f9b80843be (patch) | |
tree | a8337e9b9788b787c13241ec9a9642527d5aad6a | |
parent | 1b2fb7dc71c1f8f97663c2da84fa1c8183588474 (diff) |
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 <j@w1.fi>
Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | net/mac80211/cfg.c | 6 | ||||
-rw-r--r-- | net/mac80211/key.c | 13 | ||||
-rw-r--r-- | net/mac80211/key.h | 3 | ||||
-rw-r--r-- | 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, | |||
158 | if (mac_addr) { | 158 | if (mac_addr) { |
159 | sta = sta_info_get_bss(sdata, mac_addr); | 159 | sta = sta_info_get_bss(sdata, mac_addr); |
160 | if (!sta) { | 160 | if (!sta) { |
161 | ieee80211_key_free(key); | 161 | ieee80211_key_free(sdata->local, key); |
162 | err = -ENOENT; | 162 | err = -ENOENT; |
163 | goto out_unlock; | 163 | goto out_unlock; |
164 | } | 164 | } |
@@ -192,7 +192,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
192 | goto out_unlock; | 192 | goto out_unlock; |
193 | 193 | ||
194 | if (sta->key) { | 194 | if (sta->key) { |
195 | ieee80211_key_free(sta->key); | 195 | ieee80211_key_free(sdata->local, sta->key); |
196 | WARN_ON(sta->key); | 196 | WARN_ON(sta->key); |
197 | ret = 0; | 197 | ret = 0; |
198 | } | 198 | } |
@@ -205,7 +205,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
205 | goto out_unlock; | 205 | goto out_unlock; |
206 | } | 206 | } |
207 | 207 | ||
208 | ieee80211_key_free(sdata->keys[key_idx]); | 208 | ieee80211_key_free(sdata->local, sdata->keys[key_idx]); |
209 | WARN_ON(sdata->keys[key_idx]); | 209 | WARN_ON(sdata->keys[key_idx]); |
210 | 210 | ||
211 | ret = 0; | 211 | 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) | |||
323 | if (!key) | 323 | if (!key) |
324 | return; | 324 | return; |
325 | 325 | ||
326 | ieee80211_key_disable_hw_accel(key); | 326 | if (key->local) |
327 | ieee80211_key_disable_hw_accel(key); | ||
327 | 328 | ||
328 | if (key->conf.alg == ALG_CCMP) | 329 | if (key->conf.alg == ALG_CCMP) |
329 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 330 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
330 | if (key->conf.alg == ALG_AES_CMAC) | 331 | if (key->conf.alg == ALG_AES_CMAC) |
331 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 332 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
332 | ieee80211_debugfs_key_remove(key); | 333 | if (key->local) |
334 | ieee80211_debugfs_key_remove(key); | ||
333 | 335 | ||
334 | kfree(key); | 336 | kfree(key); |
335 | } | 337 | } |
@@ -410,15 +412,12 @@ static void __ieee80211_key_free(struct ieee80211_key *key) | |||
410 | __ieee80211_key_destroy(key); | 412 | __ieee80211_key_destroy(key); |
411 | } | 413 | } |
412 | 414 | ||
413 | void ieee80211_key_free(struct ieee80211_key *key) | 415 | void ieee80211_key_free(struct ieee80211_local *local, |
416 | struct ieee80211_key *key) | ||
414 | { | 417 | { |
415 | struct ieee80211_local *local; | ||
416 | |||
417 | if (!key) | 418 | if (!key) |
418 | return; | 419 | return; |
419 | 420 | ||
420 | local = key->sdata->local; | ||
421 | |||
422 | mutex_lock(&local->key_mtx); | 421 | mutex_lock(&local->key_mtx); |
423 | __ieee80211_key_free(key); | 422 | __ieee80211_key_free(key); |
424 | mutex_unlock(&local->key_mtx); | 423 | 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, | |||
135 | void ieee80211_key_link(struct ieee80211_key *key, | 135 | void ieee80211_key_link(struct ieee80211_key *key, |
136 | struct ieee80211_sub_if_data *sdata, | 136 | struct ieee80211_sub_if_data *sdata, |
137 | struct sta_info *sta); | 137 | struct sta_info *sta); |
138 | void ieee80211_key_free(struct ieee80211_key *key); | 138 | void ieee80211_key_free(struct ieee80211_local *local, |
139 | struct ieee80211_key *key); | ||
139 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); | 140 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); |
140 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | 141 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, |
141 | int idx); | 142 | 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) | |||
647 | return ret; | 647 | return ret; |
648 | 648 | ||
649 | if (sta->key) { | 649 | if (sta->key) { |
650 | ieee80211_key_free(sta->key); | 650 | ieee80211_key_free(local, sta->key); |
651 | WARN_ON(sta->key); | 651 | WARN_ON(sta->key); |
652 | } | 652 | } |
653 | 653 | ||