From: Doruk Tan Ozturk <doruk@0sec.ai>
To: briannorris@chromium.org
Cc: francesco@dolcini.it, kees@kernel.org,
linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org, Doruk Tan Ozturk <doruk@0sec.ai>
Subject: [PATCH v4] wifi: mwifiex: validate HT/VHT capability and operation IE lengths
Date: Fri, 14 Aug 2026 15:47:07 +0200 [thread overview]
Message-ID: <20260814134707.85925-1-doruk@0sec.ai> (raw)
mwifiex_update_bss_desc_with_ie() stores pointers to the HT and VHT
capability and operation elements, and to the operating-mode
notification, taken from a beacon/probe response without checking that
each element is long enough for the fixed-size structure the driver
later dereferences it as. The beacon buffer is a tight kmemdup() of the
on-air IEs, so a truncated element leaves the stored pointer short of
the structure and triggers a slab out-of-bounds read when the BSS
descriptor is consumed at association time -- e.g.
mwifiex_cmd_append_11n_tlv() memcpy()s sizeof(struct ieee80211_ht_cap)
from bcn_ht_cap. A nearby AP (rogue / evil-twin; an open SSID needs no
credentials) can trigger this on the victim's association attempt.
mwifiex_set_sta_ht_cap() has the same missing-length pattern in uAP
mode: it reads ieee80211_ht_cap.cap_info from a
cfg80211_find_ie(WLAN_EID_HT_CAPABILITY) result without checking the
element length.
Reject the frame with -EINVAL when any of these elements is shorter than
the structure the driver later reads, matching the length validation the
FH/DS/CF/IBSS parameter-set cases in the same parser already perform. The
operating-mode notification pointer includes the element header, so it is
checked against total_ie_len; the HT/VHT pointers skip the header and are
checked against element_len. mwifiex_set_sta_ht_cap() returns void, so
there the too-short element is skipped instead.
No dynamic reproducer: mwifiex is a fullmac driver for Marvell hardware
with no mac80211_hwsim equivalent, so this was confirmed by source and
structure-offset analysis, and compile-tested only.
Found by 0sec automated security-research tooling (https://0sec.ai).
Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver")
Cc: stable@vger.kernel.org
Assisted-by: 0sec:multi-model
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
---
Changes in v4 (per Brian Norris's review of v3):
- Use sizeof(*ptr) for the length checks instead of naming the struct
type, so a check cannot drift from the type the pointer is
dereferenced as. bcn_ht_cap/bcn_ht_oper/bcn_vht_cap/bcn_vht_oper/
oper_mode are all typed pointers.
- Check WLAN_EID_OPMODE_NOTIF against total_ie_len using
sizeof(*oper_mode): struct ieee_types_oper_mode_ntf includes the
element header and oper_mode points at the header, so a non-zero
length test was not sufficient.
- Keep -EINVAL on a too-short element (not break), matching the
FH/DS/CF/IBSS cases in the same function as introduced in v2.
Changes in v3 (per Francesco Dolcini's review of v2):
- Commit message only: spell out why ht_cap_ie->len is safe to test
against, and restore the no-dynamic-reproducer note.
Changes in v2 (per Francesco Dolcini's review of v1):
- Return -EINVAL on a too-short element instead of break, matching the
FH/DS/CF/IBSS and VENDOR_SPECIFIC cases. mwifiex_set_sta_ht_cap()
returns void, so there it stays a skip.
- Switch the Assisted-by trailer to 0sec:multi-model.
v1: https://lore.kernel.org/all/20260709100800.7026-1-doruk@0sec.ai/
v2: https://lore.kernel.org/all/20260715185543.14478-1-doruk@0sec.ai/
drivers/net/wireless/marvell/mwifiex/scan.c | 12 ++++++++++++
drivers/net/wireless/marvell/mwifiex/util.c | 2 +-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
index 97c0ec3b822e7..80572989bc81c 100644
--- a/drivers/net/wireless/marvell/mwifiex/scan.c
+++ b/drivers/net/wireless/marvell/mwifiex/scan.c
@@ -1384,6 +1384,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->beacon_buf);
break;
case WLAN_EID_HT_CAPABILITY:
+ if (element_len < sizeof(*bss_entry->bcn_ht_cap))
+ return -EINVAL;
bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *)
(current_ptr +
sizeof(struct ieee_types_header));
@@ -1392,6 +1394,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->beacon_buf);
break;
case WLAN_EID_HT_OPERATION:
+ if (element_len < sizeof(*bss_entry->bcn_ht_oper))
+ return -EINVAL;
bss_entry->bcn_ht_oper =
(struct ieee80211_ht_operation *)(current_ptr +
sizeof(struct ieee_types_header));
@@ -1400,6 +1404,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->beacon_buf);
break;
case WLAN_EID_VHT_CAPABILITY:
+ if (element_len < sizeof(*bss_entry->bcn_vht_cap))
+ return -EINVAL;
bss_entry->disable_11ac = false;
bss_entry->bcn_vht_cap =
(void *)(current_ptr +
@@ -1409,6 +1415,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->beacon_buf);
break;
case WLAN_EID_VHT_OPERATION:
+ if (element_len < sizeof(*bss_entry->bcn_vht_oper))
+ return -EINVAL;
bss_entry->bcn_vht_oper =
(void *)(current_ptr +
sizeof(struct ieee_types_header));
@@ -1417,6 +1425,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->beacon_buf);
break;
case WLAN_EID_BSS_COEX_2040:
+ if (!element_len)
+ return -EINVAL;
bss_entry->bcn_bss_co_2040 = current_ptr;
bss_entry->bss_co_2040_offset =
(u16) (current_ptr - bss_entry->beacon_buf);
@@ -1427,6 +1437,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
(u16) (current_ptr - bss_entry->beacon_buf);
break;
case WLAN_EID_OPMODE_NOTIF:
+ if (total_ie_len < sizeof(*bss_entry->oper_mode))
+ return -EINVAL;
bss_entry->oper_mode = (void *)current_ptr;
bss_entry->oper_mode_offset =
(u16)((u8 *)bss_entry->oper_mode -
diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c
index 7d3631d212236..844223c04e2ef 100644
--- a/drivers/net/wireless/marvell/mwifiex/util.c
+++ b/drivers/net/wireless/marvell/mwifiex/util.c
@@ -721,7 +721,7 @@ mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
ht_cap_ie = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies,
ies_len);
- if (ht_cap_ie) {
+ if (ht_cap_ie && ht_cap_ie->len >= sizeof(struct ieee80211_ht_cap)) {
ht_cap = (void *)(ht_cap_ie + 1);
node->is_11n_enabled = 1;
node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
--
2.43.0
reply other threads:[~2026-08-14 13:47 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260814134707.85925-1-doruk@0sec.ai \
--to=doruk@0sec.ai \
--cc=briannorris@chromium.org \
--cc=francesco@dolcini.it \
--cc=kees@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox