Skip to content

Commit e01851f

Browse files
vanhoefmgregkh
authored andcommitted
wifi: prevent A-MSDU attacks in mesh networks
commit 737bb91 upstream. This patch is a mitigation to prevent the A-MSDU spoofing vulnerability for mesh networks. The initial update to the IEEE 802.11 standard, in response to the FragAttacks, missed this case (CVE-2025-27558). It can be considered a variant of CVE-2020-24588 but for mesh networks. This patch tries to detect if a standard MSDU was turned into an A-MSDU by an adversary. This is done by parsing a received A-MSDU as a standard MSDU, calculating the length of the Mesh Control header, and seeing if the 6 bytes after this header equal the start of an rfc1042 header. If equal, this is a strong indication of an ongoing attack attempt. This defense was tested with mac80211_hwsim against a mesh network that uses an empty Mesh Address Extension field, i.e., when four addresses are used, and when using a 12-byte Mesh Address Extension field, i.e., when six addresses are used. Functionality of normal MSDUs and A-MSDUs was also tested, and confirmed working, when using both an empty and 12-byte Mesh Address Extension field. It was also tested with mac80211_hwsim that A-MSDU attacks in non-mesh networks keep being detected and prevented. Note that the vulnerability being patched, and the defense being implemented, was also discussed in the following paper and in the following IEEE 802.11 presentation: https://papers.mathyvanhoef.com/wisec2025.pdf https://mentor.ieee.org/802.11/dcn/25/11-25-0949-00-000m-a-msdu-mesh-spoof-protection.docx Cc: [email protected] Signed-off-by: Mathy Vanhoef <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 373caee commit e01851f

File tree

1 file changed

+50
-2
lines changed

1 file changed

+50
-2
lines changed

net/wireless/util.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,52 @@ bool ieee80211_is_valid_amsdu(struct sk_buff *skb, u8 mesh_hdr)
820820
}
821821
EXPORT_SYMBOL(ieee80211_is_valid_amsdu);
822822

823+
824+
/*
825+
* Detects if an MSDU frame was maliciously converted into an A-MSDU
826+
* frame by an adversary. This is done by parsing the received frame
827+
* as if it were a regular MSDU, even though the A-MSDU flag is set.
828+
*
829+
* For non-mesh interfaces, detection involves checking whether the
830+
* payload, when interpreted as an MSDU, begins with a valid RFC1042
831+
* header. This is done by comparing the A-MSDU subheader's destination
832+
* address to the start of the RFC1042 header.
833+
*
834+
* For mesh interfaces, the MSDU includes a 6-byte Mesh Control field
835+
* and an optional variable-length Mesh Address Extension field before
836+
* the RFC1042 header. The position of the RFC1042 header must therefore
837+
* be calculated based on the mesh header length.
838+
*
839+
* Since this function intentionally parses an A-MSDU frame as an MSDU,
840+
* it only assumes that the A-MSDU subframe header is present, and
841+
* beyond this it performs its own bounds checks under the assumption
842+
* that the frame is instead parsed as a non-aggregated MSDU.
843+
*/
844+
static bool
845+
is_amsdu_aggregation_attack(struct ethhdr *eth, struct sk_buff *skb,
846+
enum nl80211_iftype iftype)
847+
{
848+
int offset;
849+
850+
/* Non-mesh case can be directly compared */
851+
if (iftype != NL80211_IFTYPE_MESH_POINT)
852+
return ether_addr_equal(eth->h_dest, rfc1042_header);
853+
854+
offset = __ieee80211_get_mesh_hdrlen(eth->h_dest[0]);
855+
if (offset == 6) {
856+
/* Mesh case with empty address extension field */
857+
return ether_addr_equal(eth->h_source, rfc1042_header);
858+
} else if (offset + ETH_ALEN <= skb->len) {
859+
/* Mesh case with non-empty address extension field */
860+
u8 temp[ETH_ALEN];
861+
862+
skb_copy_bits(skb, offset, temp, ETH_ALEN);
863+
return ether_addr_equal(temp, rfc1042_header);
864+
}
865+
866+
return false;
867+
}
868+
823869
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
824870
const u8 *addr, enum nl80211_iftype iftype,
825871
const unsigned int extra_headroom,
@@ -861,8 +907,10 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
861907
/* the last MSDU has no padding */
862908
if (subframe_len > remaining)
863909
goto purge;
864-
/* mitigate A-MSDU aggregation injection attacks */
865-
if (ether_addr_equal(hdr.eth.h_dest, rfc1042_header))
910+
/* mitigate A-MSDU aggregation injection attacks, to be
911+
* checked when processing first subframe (offset == 0).
912+
*/
913+
if (offset == 0 && is_amsdu_aggregation_attack(&hdr.eth, skb, iftype))
866914
goto purge;
867915

868916
offset += sizeof(struct ethhdr);

0 commit comments

Comments
 (0)