mac80211: Beacon protection using the new BIGTK (STA)
authorJouni Malinen <jouni@codeaurora.org>
Sat, 22 Feb 2020 13:25:47 +0000 (15:25 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 24 Feb 2020 09:36:17 +0000 (10:36 +0100)
This adds support for mac80211 to verify that received Beacon frames
have a valid MME in station mode when a BIGTK is configured.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
Link: https://lore.kernel.org/r/20200222132548.20835-6-jouni@codeaurora.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/rx.c

index ec3a04a1db202984659b1fd67e8250d2dcab5eed..6bd24123456dacf51fe5067aa8436d2fc978559f 100644 (file)
@@ -983,7 +983,8 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
                return -1;
 
-       if (!ieee80211_is_robust_mgmt_frame(skb))
+       if (!ieee80211_is_robust_mgmt_frame(skb) &&
+           !ieee80211_is_beacon(hdr->frame_control))
                return -1; /* not a robust management frame */
 
        mmie = (struct ieee80211_mmie *)
@@ -1868,6 +1869,41 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 } /* ieee80211_rx_h_sta_process */
 
+static struct ieee80211_key *
+ieee80211_rx_get_bigtk(struct ieee80211_rx_data *rx, int idx)
+{
+       struct ieee80211_key *key = NULL;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       int idx2;
+
+       /* Make sure key gets set if either BIGTK key index is set so that
+        * ieee80211_drop_unencrypted_mgmt() can properly drop both unprotected
+        * Beacon frames and Beacon frames that claim to use another BIGTK key
+        * index (i.e., a key that we do not have).
+        */
+
+       if (idx < 0) {
+               idx = NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS;
+               idx2 = idx + 1;
+       } else {
+               if (idx == NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
+                       idx2 = idx + 1;
+               else
+                       idx2 = idx - 1;
+       }
+
+       if (rx->sta)
+               key = rcu_dereference(rx->sta->gtk[idx]);
+       if (!key)
+               key = rcu_dereference(sdata->keys[idx]);
+       if (!key && rx->sta)
+               key = rcu_dereference(rx->sta->gtk[idx2]);
+       if (!key)
+               key = rcu_dereference(sdata->keys[idx2]);
+
+       return key;
+}
+
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 {
@@ -1885,17 +1921,18 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        /*
         * Key selection 101
         *
-        * There are four types of keys:
+        * There are five types of keys:
         *  - GTK (group keys)
         *  - IGTK (group keys for management frames)
+        *  - BIGTK (group keys for Beacon frames)
         *  - PTK (pairwise keys)
         *  - STK (station-to-station pairwise keys)
         *
         * When selecting a key, we have to distinguish between multicast
         * (including broadcast) and unicast frames, the latter can only
-        * use PTKs and STKs while the former always use GTKs and IGTKs.
-        * Unless, of course, actual WEP keys ("pre-RSNA") are used, then
-        * unicast frames can also use key indices like GTKs. Hence, if we
+        * use PTKs and STKs while the former always use GTKs, IGTKs, and
+        * BIGTKs. Unless, of course, actual WEP keys ("pre-RSNA") are used,
+        * then unicast frames can also use key indices like GTKs. Hence, if we
         * don't have a PTK/STK we check the key index for a WEP key.
         *
         * Note that in a regular BSS, multicast frames are sent by the
@@ -1939,6 +1976,20 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                /* Skip decryption if the frame is not protected. */
                if (!ieee80211_has_protected(fc))
                        return RX_CONTINUE;
+       } else if (mmie_keyidx >= 0 && ieee80211_is_beacon(fc)) {
+               /* Broadcast/multicast robust management frame / BIP */
+               if ((status->flag & RX_FLAG_DECRYPTED) &&
+                   (status->flag & RX_FLAG_IV_STRIPPED))
+                       return RX_CONTINUE;
+
+               if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
+                   mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
+                   NUM_DEFAULT_BEACON_KEYS)
+                       return RX_DROP_MONITOR; /* unexpected BIP keyidx */
+
+               rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx);
+               if (!rx->key)
+                       return RX_CONTINUE; /* Beacon protection not in use */
        } else if (mmie_keyidx >= 0) {
                /* Broadcast/multicast robust management frame / BIP */
                if ((status->flag & RX_FLAG_DECRYPTED) &&
@@ -1968,11 +2019,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                struct ieee80211_sub_if_data *sdata = rx->sdata;
                int i;
 
-               if (ieee80211_is_mgmt(fc) &&
-                   is_multicast_ether_addr(hdr->addr1) &&
-                   (key = rcu_dereference(rx->sdata->default_mgmt_key)))
-                       rx->key = key;
-               else {
+               if (ieee80211_is_beacon(fc)) {
+                       key = ieee80211_rx_get_bigtk(rx, -1);
+               } else if (ieee80211_is_mgmt(fc) &&
+                          is_multicast_ether_addr(hdr->addr1)) {
+                       key = rcu_dereference(rx->sdata->default_mgmt_key);
+               } else {
                        if (rx->sta) {
                                for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
                                        key = rcu_dereference(rx->sta->gtk[i]);
@@ -1987,9 +2039,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                                                break;
                                }
                        }
-                       if (key)
-                               rx->key = key;
                }
+               if (key)
+                       rx->key = key;
                return RX_CONTINUE;
        } else {
                /*
@@ -2358,6 +2410,9 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
                                                             rx->skb->len);
                        return -EACCES;
                }
+               if (unlikely(ieee80211_is_beacon(fc) && rx->key &&
+                            ieee80211_get_mmie_keyidx(rx->skb) < 0))
+                       return -EACCES;
                /*
                 * When using MFP, Action frames are not allowed prior to
                 * having configured keys.