mac80211: prevent mixed key and fragment cache attacks
authorMathy Vanhoef <Mathy.Vanhoef@kuleuven.be>
Mon, 31 May 2021 20:30:13 +0000 (22:30 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 Jun 2021 06:23:28 +0000 (08:23 +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 9c20c53f6729e15dc5fe69693117b235a400c1dd..5bca7994b58cf413155609a5e858137dba2fd595 100644 (file)
@@ -97,6 +97,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 6e02f8dfce2b2bf04aaa9b3023de24fb26bfc048..4e23f240f599e34d752be5f64ed63e943c43bcc0 100644 (file)
@@ -647,6 +647,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
                       struct sta_info *sta)
 {
        struct ieee80211_local *local = sdata->local;
+       static atomic_t key_color = ATOMIC_INIT(0);
        struct ieee80211_key *old_key;
        int idx = key->conf.keyidx;
        bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
@@ -658,6 +659,12 @@ int ieee80211_key_link(struct ieee80211_key *key,
        bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
        int ret;
 
+       /*
+        * 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);
+
        mutex_lock(&sdata->local->key_mtx);
 
        if (sta && pairwise)
index 4aa20cef08595955702cd0aa5746d2dde1e56647..2749a7d05e7636c7dfe82b214d70406719346d12 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 e5760492c27d2a6fa31d993835703d926546f65f..d3aee2859f0aa83aa290ff30ef552f030465c7b5 100644 (file)
@@ -2004,6 +2004,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);
@@ -2041,6 +2042,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]++;