]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mac80211: prevent mixed key and fragment cache attacks
authorMathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
Tue, 11 May 2021 18:02:43 +0000 (20:02 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 Jun 2021 06:38:03 +0000 (08:38 +0200)
commit 94034c40ab4a3fcf581fbc7f8fdf4e29943c4a24 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/mac80211/ieee80211_i.h
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/rx.c

index fc715bba59146f2ddfe84987d5582f781a205b16..db113013416c2e5bc162d1756027beebfb3aeaa8 100644 (file)
@@ -100,6 +100,7 @@ struct ieee80211_fragment_entry {
        u8 rx_queue;
        bool check_sequential_pn; /* needed for CCMP/GCMP */
        u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
+       unsigned int key_color;
 };
 
 
index f20bb39f492da989675ea2a4137cca056ac81689..6775d6cb7d3d4d0f31de0f78a92549d1d86dd3ce 100644 (file)
@@ -653,6 +653,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
                       struct ieee80211_sub_if_data *sdata,
                       struct sta_info *sta)
 {
+       static atomic_t key_color = ATOMIC_INIT(0);
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_key *old_key;
        int idx = key->conf.keyidx;
@@ -688,6 +689,12 @@ int ieee80211_key_link(struct ieee80211_key *key,
        key->sdata = sdata;
        key->sta = sta;
 
+       /*
+        * Assign a unique ID to every key so we can easily prevent mixed
+        * key and fragment cache attacks.
+        */
+       key->color = atomic_inc_return(&key_color);
+
        increment_tailroom_need_count(sdata);
 
        ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
index ebdb80b85dc3aa3b12da1f8925df3552a51674b3..d8e187bcb7510349766789627bb0439e8e113be5 100644 (file)
@@ -127,6 +127,8 @@ struct ieee80211_key {
        } debugfs;
 #endif
 
+       unsigned int color;
+
        /*
         * key config, must be last because it contains key
         * material as variable length member
index bf100fe67439b07365d4b3372a6f4a99330ccc16..83d8b27167f16349d68c0f6e5291e8e3dde75831 100644 (file)
@@ -2139,6 +2139,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                         * next fragment has a sequential PN value.
                         */
                        entry->check_sequential_pn = true;
+                       entry->key_color = rx->key->color;
                        memcpy(entry->last_pn,
                               rx->key->u.ccmp.rx_pn[queue],
                               IEEE80211_CCMP_PN_LEN);
@@ -2176,6 +2177,11 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 
                if (!requires_sequential_pn(rx, fc))
                        return RX_DROP_UNUSABLE;
+
+               /* Prevent mixed key and fragment cache attacks */
+               if (entry->key_color != rx->key->color)
+                       return RX_DROP_UNUSABLE;
+
                memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN);
                for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {
                        pn[i]++;