mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-07 14:28:50 +00:00
95 lines
4.0 KiB
Diff
95 lines
4.0 KiB
Diff
|
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) {
|