Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: prevent mixed key and fragment cache attacks

Simultaneously prevent mixed key attacks (CVE-2020-24587) and fragment
cache attacks (CVE-2020-24586). This is accomplished by assigning a
unique color to every key (per interface) and using this to track which
key was used to decrypt a fragment. When reassembling frames, it is
now checked whether all fragments were decrypted using the same key.

To assure that fragment cache attacks are also prevented, the ID that is
assigned to keys is unique even over (re)associations and (re)connects.
This means fragments separated by a (re)association or (re)connect will
not be reassembled. Because mac80211 now also prevents the reassembly of
mixed encrypted and plaintext fragments, all cache attacks are prevented.

Cc: stable@vger.kernel.org
Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
Link: https://lore.kernel.org/r/20210511200110.3f8290e59823.I622a67769ed39257327a362cfc09c812320eb979@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Mathy Vanhoef and committed by
Johannes Berg
94034c40 965a7d72

+16
+1
net/mac80211/ieee80211_i.h
··· 97 97 u8 rx_queue; 98 98 bool check_sequential_pn; /* needed for CCMP/GCMP */ 99 99 u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ 100 + unsigned int key_color; 100 101 }; 101 102 102 103
+7
net/mac80211/key.c
··· 799 799 struct ieee80211_sub_if_data *sdata, 800 800 struct sta_info *sta) 801 801 { 802 + static atomic_t key_color = ATOMIC_INIT(0); 802 803 struct ieee80211_key *old_key; 803 804 int idx = key->conf.keyidx; 804 805 bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; ··· 850 849 key->local = sdata->local; 851 850 key->sdata = sdata; 852 851 key->sta = sta; 852 + 853 + /* 854 + * Assign a unique ID to every key so we can easily prevent mixed 855 + * key and fragment cache attacks. 856 + */ 857 + key->color = atomic_inc_return(&key_color); 853 858 854 859 increment_tailroom_need_count(sdata); 855 860
+2
net/mac80211/key.h
··· 128 128 } debugfs; 129 129 #endif 130 130 131 + unsigned int color; 132 + 131 133 /* 132 134 * key config, must be last because it contains key 133 135 * material as variable length member
+6
net/mac80211/rx.c
··· 2255 2255 * next fragment has a sequential PN value. 2256 2256 */ 2257 2257 entry->check_sequential_pn = true; 2258 + entry->key_color = rx->key->color; 2258 2259 memcpy(entry->last_pn, 2259 2260 rx->key->u.ccmp.rx_pn[queue], 2260 2261 IEEE80211_CCMP_PN_LEN); ··· 2293 2292 2294 2293 if (!requires_sequential_pn(rx, fc)) 2295 2294 return RX_DROP_UNUSABLE; 2295 + 2296 + /* Prevent mixed key and fragment cache attacks */ 2297 + if (entry->key_color != rx->key->color) 2298 + return RX_DROP_UNUSABLE; 2299 + 2296 2300 memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN); 2297 2301 for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) { 2298 2302 pn[i]++;