diff options
| author | James Morris <james.l.morris@oracle.com> | 2017-11-29 12:47:41 +1100 | 
|---|---|---|
| committer | James Morris <james.l.morris@oracle.com> | 2017-11-29 12:47:41 +1100 | 
| commit | cf40a76e7d5874bb25f4404eecc58a2e033af885 (patch) | |
| tree | 8fd81cbea03c87b3d41d7ae5b1d11eadd35d6ef5 /net/mac80211/key.c | |
| parent | ab5348c9c23cd253f5902980d2d8fe067dc24c82 (diff) | |
| parent | 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff) | |
Merge tag 'v4.15-rc1' into next-seccomp
Linux 4.15-rc1
Diffstat (limited to 'net/mac80211/key.c')
| -rw-r--r-- | net/mac80211/key.c | 54 | 
1 files changed, 50 insertions, 4 deletions
| diff --git a/net/mac80211/key.c b/net/mac80211/key.c index a98fc2b5e0dc..938049395f90 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -4,7 +4,7 @@   * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>   * Copyright 2007-2008	Johannes Berg <johannes@sipsolutions.net>   * Copyright 2013-2014  Intel Mobile Communications GmbH - * Copyright 2015	Intel Deutschland GmbH + * Copyright 2015-2017	Intel Deutschland GmbH   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 as @@ -19,6 +19,7 @@  #include <linux/slab.h>  #include <linux/export.h>  #include <net/mac80211.h> +#include <crypto/algapi.h>  #include <asm/unaligned.h>  #include "ieee80211_i.h"  #include "driver-ops.h" @@ -609,6 +610,39 @@ void ieee80211_key_free_unused(struct ieee80211_key *key)  	ieee80211_key_free_common(key);  } +static bool ieee80211_key_identical(struct ieee80211_sub_if_data *sdata, +				    struct ieee80211_key *old, +				    struct ieee80211_key *new) +{ +	u8 tkip_old[WLAN_KEY_LEN_TKIP], tkip_new[WLAN_KEY_LEN_TKIP]; +	u8 *tk_old, *tk_new; + +	if (!old || new->conf.keylen != old->conf.keylen) +		return false; + +	tk_old = old->conf.key; +	tk_new = new->conf.key; + +	/* +	 * In station mode, don't compare the TX MIC key, as it's never used +	 * and offloaded rekeying may not care to send it to the host. This +	 * is the case in iwlwifi, for example. +	 */ +	if (sdata->vif.type == NL80211_IFTYPE_STATION && +	    new->conf.cipher == WLAN_CIPHER_SUITE_TKIP && +	    new->conf.keylen == WLAN_KEY_LEN_TKIP && +	    !(new->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) { +		memcpy(tkip_old, tk_old, WLAN_KEY_LEN_TKIP); +		memcpy(tkip_new, tk_new, WLAN_KEY_LEN_TKIP); +		memset(tkip_old + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8); +		memset(tkip_new + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8); +		tk_old = tkip_old; +		tk_new = tkip_new; +	} + +	return !crypto_memneq(tk_old, tk_new, new->conf.keylen); +} +  int ieee80211_key_link(struct ieee80211_key *key,  		       struct ieee80211_sub_if_data *sdata,  		       struct sta_info *sta) @@ -620,9 +654,6 @@ int ieee80211_key_link(struct ieee80211_key *key,  	pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;  	idx = key->conf.keyidx; -	key->local = sdata->local; -	key->sdata = sdata; -	key->sta = sta;  	mutex_lock(&sdata->local->key_mtx); @@ -633,6 +664,20 @@ int ieee80211_key_link(struct ieee80211_key *key,  	else  		old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); +	/* +	 * Silently accept key re-installation without really installing the +	 * new version of the key to avoid nonce reuse or replay issues. +	 */ +	if (ieee80211_key_identical(sdata, old_key, key)) { +		ieee80211_key_free_unused(key); +		ret = 0; +		goto out; +	} + +	key->local = sdata->local; +	key->sdata = sdata; +	key->sta = sta; +  	increment_tailroom_need_count(sdata);  	ieee80211_key_replace(sdata, sta, pairwise, old_key, key); @@ -648,6 +693,7 @@ int ieee80211_key_link(struct ieee80211_key *key,  		ret = 0;  	} + out:  	mutex_unlock(&sdata->local->key_mtx);  	return ret; | 
