Skip to content

Commit e2c8a3c

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: stable@vger.kernel.org Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@kuleuven.be> Link: https://patch.msgid.link/20250616004635.224344-1-Mathy.Vanhoef@kuleuven.be Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent cc145e0 commit e2c8a3c

1 file changed

Lines changed: 50 additions & 2 deletions

File tree

net/wireless/util.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,52 @@ bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr)
813813
}
814814
EXPORT_SYMBOL(ieee80211_is_valid_amsdu);
815815

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

864912
offset += sizeof(struct ethhdr);

0 commit comments

Comments
 (0)