mac80211: backport upstream fixes for FragAttacks
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / subsys / 388-mac80211-do-not-accept-forward-invalid-EAPOL-frames.patch
diff --git a/package/kernel/mac80211/patches/subsys/388-mac80211-do-not-accept-forward-invalid-EAPOL-frames.patch b/package/kernel/mac80211/patches/subsys/388-mac80211-do-not-accept-forward-invalid-EAPOL-frames.patch
new file mode 100644 (file)
index 0000000..9a0b78d
--- /dev/null
@@ -0,0 +1,94 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Tue, 11 May 2021 20:02:50 +0200
+Subject: [PATCH] mac80211: do not accept/forward invalid EAPOL frames
+
+EAPOL frames are used for authentication and key management between the
+AP and each individual STA associated in the BSS. Those frames are not
+supposed to be sent by one associated STA to another associated STA
+(either unicast for broadcast/multicast).
+
+Similarly, in 802.11 they're supposed to be sent to the authenticator
+(AP) address.
+
+Since it is possible for unexpected EAPOL frames to result in misbehavior
+in supplicant implementations, it is better for the AP to not allow such
+cases to be forwarded to other clients either directly, or indirectly if
+the AP interface is part of a bridge.
+
+Accept EAPOL (control port) frames only if they're transmitted to the
+own address, or, due to interoperability concerns, to the PAE group
+address.
+
+Disable forwarding of EAPOL (or well, the configured control port
+protocol) frames back to wireless medium in all cases. Previously, these
+frames were accepted from fully authenticated and authorized stations
+and also from unauthenticated stations for one of the cases.
+
+Additionally, to avoid forwarding by the bridge, rewrite the PAE group
+address case to the local MAC address.
+
+Cc: stable@vger.kernel.org
+Co-developed-by: Jouni Malinen <jouni@codeaurora.org>
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2541,13 +2541,13 @@ static bool ieee80211_frame_allowed(stru
+       struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
+       /*
+-       * Allow EAPOL frames to us/the PAE group address regardless
+-       * of whether the frame was encrypted or not.
++       * Allow EAPOL frames to us/the PAE group address regardless of
++       * whether the frame was encrypted or not, and always disallow
++       * all other destination addresses for them.
+        */
+-      if (ehdr->h_proto == rx->sdata->control_port_protocol &&
+-          (ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) ||
+-           ether_addr_equal(ehdr->h_dest, pae_group_addr)))
+-              return true;
++      if (unlikely(ehdr->h_proto == rx->sdata->control_port_protocol))
++              return ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) ||
++                     ether_addr_equal(ehdr->h_dest, pae_group_addr);
+       if (ieee80211_802_1x_port_control(rx) ||
+           ieee80211_drop_unencrypted(rx, fc))
+@@ -2572,8 +2572,28 @@ static void ieee80211_deliver_skb_to_loc
+               cfg80211_rx_control_port(dev, skb, noencrypt);
+               dev_kfree_skb(skb);
+       } else {
++              struct ethhdr *ehdr = (void *)skb_mac_header(skb);
++
+               memset(skb->cb, 0, sizeof(skb->cb));
++              /*
++               * 802.1X over 802.11 requires that the authenticator address
++               * be used for EAPOL frames. However, 802.1X allows the use of
++               * the PAE group address instead. If the interface is part of
++               * a bridge and we pass the frame with the PAE group address,
++               * then the bridge will forward it to the network (even if the
++               * client was not associated yet), which isn't supposed to
++               * happen.
++               * To avoid that, rewrite the destination address to our own
++               * address, so that the authenticator (e.g. hostapd) will see
++               * the frame, but bridge won't forward it anywhere else. Note
++               * that due to earlier filtering, the only other address can
++               * be the PAE group address.
++               */
++              if (unlikely(skb->protocol == sdata->control_port_protocol &&
++                           !ether_addr_equal(ehdr->h_dest, sdata->vif.addr)))
++                      ether_addr_copy(ehdr->h_dest, sdata->vif.addr);
++
+               /* deliver to local stack */
+               if (rx->list)
+ #if LINUX_VERSION_IS_GEQ(4,19,0)
+@@ -2617,6 +2637,7 @@ ieee80211_deliver_skb(struct ieee80211_r
+       if ((sdata->vif.type == NL80211_IFTYPE_AP ||
+            sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
+           !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
++          ehdr->h_proto != rx->sdata->control_port_protocol &&
+           (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
+               if (is_multicast_ether_addr(ehdr->h_dest) &&
+                   ieee80211_vif_get_num_mcast_if(sdata) != 0) {