Skip to content

Commit ec63920

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 1d57f71 commit ec63920

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
@@ -826,6 +826,52 @@ bool ieee80211_is_valid_amsdu(struct sk_buff *skb, u8 mesh_hdr)
826826
}
827827
EXPORT_SYMBOL(ieee80211_is_valid_amsdu);
828828

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

874922
offset += sizeof(struct ethhdr);

0 commit comments

Comments
 (0)