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

mac80211: assure all fragments are encrypted

Do not mix plaintext and encrypted fragments in protected Wi-Fi
networks. This fixes CVE-2020-26147.

Previously, an attacker was able to first forward a legitimate encrypted
fragment towards a victim, followed by a plaintext fragment. The
encrypted and plaintext fragment would then be reassembled. For further
details see Section 6.3 and Appendix D in the paper "Fragment and Forge:
Breaking Wi-Fi Through Frame Aggregation and Fragmentation".

Because of this change there are now two equivalent conditions in the
code to determine if a received fragment requires sequential PNs, so we
also move this test to a separate function to make the code easier to
maintain.

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

authored by

Mathy Vanhoef and committed by
Johannes Berg
965a7d72 297c4de6

+12 -11
+12 -11
net/mac80211/rx.c
··· 2194 2194 return NULL; 2195 2195 } 2196 2196 2197 + static bool requires_sequential_pn(struct ieee80211_rx_data *rx, __le16 fc) 2198 + { 2199 + return rx->key && 2200 + (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP || 2201 + rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 || 2202 + rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP || 2203 + rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) && 2204 + ieee80211_has_protected(fc); 2205 + } 2206 + 2197 2207 static ieee80211_rx_result debug_noinline 2198 2208 ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) 2199 2209 { ··· 2248 2238 /* This is the first fragment of a new frame. */ 2249 2239 entry = ieee80211_reassemble_add(rx->sdata, frag, seq, 2250 2240 rx->seqno_idx, &(rx->skb)); 2251 - if (rx->key && 2252 - (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP || 2253 - rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 || 2254 - rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP || 2255 - rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) && 2256 - ieee80211_has_protected(fc)) { 2241 + if (requires_sequential_pn(rx, fc)) { 2257 2242 int queue = rx->security_idx; 2258 2243 2259 2244 /* Store CCMP/GCMP PN so that we can verify that the ··· 2290 2285 u8 pn[IEEE80211_CCMP_PN_LEN], *rpn; 2291 2286 int queue; 2292 2287 2293 - if (!rx->key || 2294 - (rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP && 2295 - rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256 && 2296 - rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP && 2297 - rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256)) 2288 + if (!requires_sequential_pn(rx, fc)) 2298 2289 return RX_DROP_UNUSABLE; 2299 2290 memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN); 2300 2291 for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {