From: Ilan Peer ilan.peer@intel.com
[ Upstream commit ea928544f3215fdeac24d66bef85e10bb638b8c1 ]
The element data length check did not account for the extra octet used for the extension ID. Fix it.
Signed-off-by: Ilan Peer ilan.peer@intel.com Signed-off-by: Miri Korenblit miriam.rachel.korenblit@intel.com Link: https://patch.msgid.link/20250907115109.8da0012e2286.I8c0c69a0011f7153c13b36... Signed-off-by: Johannes Berg johannes.berg@intel.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES
- What the patch changes - Tightens the HE capabilities IE length check in `ieee80211_max_rx_chains()` to account for the one-byte Extension ID: - Before: `if (!he_cap_elem || he_cap_elem->datalen < sizeof(*he_cap)) return chains;` - After: `if (!he_cap_elem || he_cap_elem->datalen < sizeof(*he_cap) + 1) return chains;` - Location: `net/mac80211/mlme.c` in `ieee80211_max_rx_chains()` around the HE path (`cfg80211_find_ext_elem(...)`), see current tree at `net/mac80211/mlme.c:5741` and the nearby “skip one byte ext_tag_id” comment at `net/mac80211/mlme.c:5744`.
- Why this is correct - For extended IEs, `cfg80211_find_ext_elem()` matches the extended EID at offset 0 of the element data (so `data[0]` is the Extension ID), see `include/net/cfg80211.h:7282`. The returned `struct element` layout is `id`, `datalen`, `data[]` (see `include/linux/ieee80211.h:5220`), and for an extended IE the first byte of `data[]` is the ext ID. - The code immediately “skips” this byte (`he_cap = (void *)(he_cap_elem->data + 1)`), so the initial length check must require at least `1 + sizeof(struct ieee80211_he_cap_elem)` to ensure the entire HE capability fixed fields are present. The original check only required `sizeof(*he_cap)`, which is off by one and inconsistent with the subsequent “invalid HE IE” check that already uses `1 + mcs_nss_size + sizeof(*he_cap)` at `net/mac80211/mlme.c:5749`. - Consistency with other callers: in `net/wireless/nl80211.c`, the HE capability parsing uses the correct “+1” rule (`cap->datalen >= sizeof(*params->he_cap) + 1`) before skipping the ext ID (`net/wireless/nl80211.c:6402-6408`). This patch aligns mac80211 with that established pattern.
- Bug impact and risk - Impact: Without the “+1”, the parser may treat a truncated HE capability (exactly `sizeof(*he_cap)` bytes total, including the extension ID) as if it had the full fixed portion after skipping the ext ID. This can lead to mis-parse or at minimum unnecessary processing of invalid data before bailing at the later check. It risks reading fields relative to the HE cap beyond the element’s logical bounds, even if still within the overall IE buffer. - User-visible effect: `ieee80211_max_rx_chains()` is used to derive `link->needed_rx_chains` during association/connection (`net/mac80211/mlme.c:6103`). Correctly rejecting invalid/truncated HE IEs avoids computing chain counts from malformed data, preventing subtle misconfiguration and ensuring safe fallback to HT/VHT-derived limits. - Scope and risk: One-line guard fix in mac80211 parsing path. No API/ABI changes, no architectural refactoring. Behavior for valid IEs is unchanged; malformed IEs are handled more robustly.
- Stable backport suitability - Fixes a real parsing bug with potential robustness/safety implications. - Minimal, well-scoped change with very low regression risk. - Aligns mac80211 with correct extended IE handling used elsewhere in the tree, improving consistency. - Touches a contained part of mac80211 and does not introduce new features or architectural changes.
Given these points, this is a textbook stable backport candidate.
net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0f2d2fec05426..d0af917a40b34 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5733,7 +5733,7 @@ static u8 ieee80211_max_rx_chains(struct ieee80211_link_data *link, he_cap_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ies->data, ies->len);
- if (!he_cap_elem || he_cap_elem->datalen < sizeof(*he_cap)) + if (!he_cap_elem || he_cap_elem->datalen < sizeof(*he_cap) + 1) return chains;
/* skip one byte ext_tag_id */