12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- From: Johannes Berg <[email protected]>
- 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: [email protected]
- Co-developed-by: Jouni Malinen <[email protected]>
- Signed-off-by: Jouni Malinen <[email protected]>
- Signed-off-by: Johannes Berg <[email protected]>
- ---
- --- 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) {
|