[PATCH] wifi: cfg80211: preserve mesh A-MSDU lengths when adding mesh headers

From: Zhao Li

Date: Wed Oct 28 2026 - 10:27:17 EST


A malformed mesh A-MSDU subframe with a declared payload length near
65535 bytes can pass validation against a much shorter aggregate.

ieee80211_amsdu_subframe_length() adds the mesh control length to the
declared length in a u16, and ieee80211_is_valid_amsdu() stores the
result in a u16 local. The sum therefore wraps before either walker
compares it with the remaining aggregate length. The decomposer then
splits and delivers the malformed aggregate instead of rejecting it.

Keep the computed length in unsigned int in both the helper and the
validator so oversized subframes cannot wrap.

LLM assistance was used to find the bug and review.

Fixes: 6e4c0d0460bd ("wifi: mac80211: add a workaround for receiving non-standard mesh A-MSDU")
Fixes: fe4a6d2db3ba ("wifi: mac80211: implement support for yet another mesh A-MSDU format")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Zhao Li <enderaoelyther@xxxxxxxxx>
---
Validation: A W=1 module build with MODPOST passed. A QEMU
guest using the real validator and decomposer accepted both malformed
mesh formats and emitted two frames before the change; both formats were
rejected and no frames were emitted after it. No KASAN report is expected
or claimed.
A reproducer is available on request.
Sparse C=2 passed. Targeted Smatch introduced no new diagnostics.

net/wireless/util.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/wireless/util.c b/net/wireless/util.c
index f2464d2ce0d5..c510fc62d819 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -822,12 +822,12 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
return frame;
}

-static u16
+static unsigned int
ieee80211_amsdu_subframe_length(void *field, u8 mesh_flags, u8 hdr_type)
{
__le16 *field_le = field;
__be16 *field_be = field;
- u16 len;
+ unsigned int len;

if (hdr_type >= 2)
len = le16_to_cpu(*field_le);
@@ -849,7 +849,7 @@ bool ieee80211_is_valid_amsdu(struct sk_buff *skb, u8 mesh_hdr)
__be16 len;
u8 mesh_flags;
} hdr;
- u16 len;
+ unsigned int len;

if (sizeof(hdr) > remaining)
return false;

base-commit: 25e73f1d6868c759c8eb56cad4e411692c5341b4
--
2.56.0