* [PATCH v5 1/3] staging: rtl8723bs: fix OOB reads in update_beacon_info() and bwmode_update_check()
2026-05-11 16:57 [PATCH v5 0/3] staging: rtl8723bs: fix OOB reads and heap overflow in IE parsing Alexandru Hossu
@ 2026-05-11 16:57 ` Alexandru Hossu
2026-05-11 16:57 ` [PATCH v5 2/3] staging: rtl8723bs: fix OOB reads in IE loops in issue_assocreq() and join_cmd_hdl() Alexandru Hossu
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Alexandru Hossu @ 2026-05-11 16:57 UTC (permalink / raw)
To: greg; +Cc: linux-staging, linux-kernel, stable
Three out-of-bounds read paths in Beacon IE processing:
1. Unsigned underflow in len computation.
update_beacon_info() computes:
len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN);
where len is unsigned int. If pkt_len is smaller than
_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN (36 bytes), the subtraction
wraps to a very large value, causing the IE loop to iterate over
memory far beyond the receive buffer. Add an early return when
pkt_len is too small.
2. WMM OUI comparison reads 6 bytes past a possibly short IE payload.
For WLAN_EID_VENDOR_SPECIFIC, the code calls
memcmp(pIE->data, WMM_PARA_OUI, 6) before checking
pIE->length == WLAN_WMM_LEN. An IE with pIE->length < 6 causes
memcmp to read into adjacent frame data. Swap the condition so the
length check comes first.
3. bwmode_update_check() missing minimum IE length check.
bwmode_update_check() rejects IEs longer than
sizeof(struct HT_info_element) but accepts any shorter length,
including zero. After the check it casts pIE->data to
struct HT_info_element * and reads infos[0] (offset 1), which is
out of bounds when pIE->length is 0 or 1. Change the guard from
> to != to require the IE to be exactly the expected size.
Fixes: 554c0a3abf21 ("staging: Add rtl8723bs sdio wifi driver")
Cc: stable@vger.kernel.org
Signed-off-by: Alexandru Hossu <hossu.alexandru@gmail.com>
---
Changes in v5:
- No code changes from v4.
Changes in v4:
- Add pkt_len < _BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN guard before the
len subtraction to prevent unsigned underflow (sashiko review of v3).
- Swap WLAN_EID_VENDOR_SPECIFIC condition: check pIE->length ==
WLAN_WMM_LEN before memcmp to avoid reading 6 bytes from a short IE
payload (sashiko review of v3).
- Fix bwmode_update_check(): change > sizeof(struct HT_info_element) to
!= sizeof(struct HT_info_element) to also reject IEs shorter than the
expected size, preventing the read of infos[0] on a zero-length IE
(sashiko review of v3).
Changes in v3:
- No code changes from v2.
Changes in v2:
- Add IE loop header and payload bounds checks in update_beacon_info().
- Use sizeof(*pIE) + pIE->length instead of pIE->length + 2 for
consistency with the sizeof(*pIE) guards (Dan Carpenter).
drivers/staging/rtl8723bs/core/rtw_wlan_util.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
index dd34f229df12..6ea0d646b961 100644
--- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
@@ -850,7 +850,7 @@ static void bwmode_update_check(struct adapter *padapter, struct ndis_80211_var_
if (phtpriv->ht_option == false)
return;
- if (pIE->length > sizeof(struct HT_info_element))
+ if (pIE->length != sizeof(struct HT_info_element))
return;
pHT_info = (struct HT_info_element *)pIE->data;
@@ -1287,6 +1287,9 @@ void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, stru
unsigned int len;
struct ndis_80211_var_ie *pIE;
+ if (pkt_len < _BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN)
+ return;
+
len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN);
for (i = 0; i < len;) {
@@ -1299,7 +1302,8 @@ void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, stru
switch (pIE->element_id) {
case WLAN_EID_VENDOR_SPECIFIC:
/* to update WMM parameter set while receiving beacon */
- if (!memcmp(pIE->data, WMM_PARA_OUI, 6) && pIE->length == WLAN_WMM_LEN) /* WMM */
+ if (pIE->length == WLAN_WMM_LEN &&
+ !memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */
if (WMM_param_handler(padapter, pIE))
report_wmm_edca_update(padapter);
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v5 2/3] staging: rtl8723bs: fix OOB reads in IE loops in issue_assocreq() and join_cmd_hdl()
2026-05-11 16:57 [PATCH v5 0/3] staging: rtl8723bs: fix OOB reads and heap overflow in IE parsing Alexandru Hossu
2026-05-11 16:57 ` [PATCH v5 1/3] staging: rtl8723bs: fix OOB reads in update_beacon_info() and bwmode_update_check() Alexandru Hossu
@ 2026-05-11 16:57 ` Alexandru Hossu
2026-05-11 16:57 ` [PATCH v5 3/3] staging: rtl8723bs: fix OOB reads in rtw_get_wps_ie() Alexandru Hossu
2026-05-21 8:40 ` [PATCH v5 0/3] staging: rtl8723bs: fix OOB reads and heap overflow in IE parsing Greg KH
3 siblings, 0 replies; 6+ messages in thread
From: Alexandru Hossu @ 2026-05-11 16:57 UTC (permalink / raw)
To: greg; +Cc: linux-staging, linux-kernel, stable
Seven out-of-bounds read paths in the IE parsing loops of
issue_assocreq() and join_cmd_hdl():
1. Vendor-specific OUI comparison reads 4 bytes past a possibly short
IE payload (issue_assocreq).
For WLAN_EID_VENDOR_SPECIFIC, the code calls memcmp(pIE->data,
OUI, 4) on RTW_WPA_OUI, WMM_OUI, and WPS_OUI without first
verifying that pIE->length is at least 4. Add pIE->length >= 4
guard before the comparisons.
2. WPS truncation path passes vs_ie_length = 14 when pIE->length < 14
(issue_assocreq).
When wifi_spec is 0 and the IE matches WPS_OUI, the code sets
vs_ie_length = 14 and passes pIE->data to rtw_set_ie() regardless
of pIE->length. If pIE->length is between 4 and 13, rtw_set_ie()
reads up to (14 - pIE->length) bytes past the IE payload. Skip the
IE with break when pIE->length < 14.
3. HT Capability IE memcpy reads sizeof(struct HT_caps_element) bytes
from an IE that may be shorter (issue_assocreq).
The WLAN_EID_HT_CAPABILITY handler copies:
memcpy(&pmlmeinfo->HT_caps, pIE->data, sizeof(struct HT_caps_element));
If pIE->length < sizeof(struct HT_caps_element), the memcpy reads
beyond the end of the IE payload. Add a minimum length check and
skip the IE if it is too short.
4. rtw_set_ie called with untrusted pIE->length for HT Capability
(issue_assocreq).
After the memcpy the code passes pIE->length directly to
rtw_set_ie() as the IE body length. If pIE->length exceeds
sizeof(struct HT_caps_element), rtw_set_ie copies that many bytes
from pmlmeinfo->HT_caps, reading past the end of the struct.
Use sizeof(struct HT_caps_element) instead.
5. WMM guard in join_cmd_hdl() insufficient for WMM_param_handler().
The WLAN_EID_VENDOR_SPECIFIC handler in join_cmd_hdl() calls
WMM_param_handler() after a pIE->length >= 4 OUI check.
WMM_param_handler() reads pIE->data + 6 and copies
sizeof(struct WMM_para_element) = 18 bytes, requiring a minimum of
24 bytes total. Strengthen the guard to pIE->length >= WLAN_WMM_LEN.
6. HT Operation IE accessed without minimum length check (join_cmd_hdl).
The WLAN_EID_HT_OPERATION handler casts pIE->data to
struct HT_info_element * and reads pht_info->infos[0] (offset 1)
without verifying pIE->length >= sizeof(struct HT_info_element).
A zero- or one-byte HT Operation IE causes an out-of-bounds read.
Add a minimum length check and break if the IE is too short.
7. Loop advancement uses literal 2 instead of sizeof(*pIE) in both
loops.
i += (pIE->length + 2) is functionally equivalent to
i += sizeof(*pIE) + pIE->length today, but the literal 2 is
inconsistent with the sizeof(*pIE) guards added at the top of each
loop. Use sizeof(*pIE) + pIE->length for consistency.
Fixes: 554c0a3abf21 ("staging: Add rtl8723bs sdio wifi driver")
Cc: stable@vger.kernel.org
Signed-off-by: Alexandru Hossu <hossu.alexandru@gmail.com>
---
Changes in v5:
- In the WPS truncation path of issue_assocreq(), v4 set
vs_ie_length = 14 and called rtw_set_ie() with pIE->data even when
pIE->length < 14, reading (14 - pIE->length) bytes past the IE
payload. Fixed by breaking out of the switch when pIE->length < 14
(sashiko review of v4).
- The WMM guard in join_cmd_hdl() was pIE->length >= 4, sufficient for
the OUI check but not for WMM_param_handler(), which reads
pIE->data + 6 and copies sizeof(struct WMM_para_element) = 18 bytes
(total 24). Strengthened to pIE->length >= WLAN_WMM_LEN
(sashiko review of v4).
Changes in v4:
- Add pIE->length >= 4 guard before the 4-byte OUI memcmps in the
WLAN_EID_VENDOR_SPECIFIC cases of both functions (sashiko review of v3).
- In issue_assocreq() WLAN_EID_HT_CAPABILITY: add minimum length check
(pIE->length < sizeof(struct HT_caps_element)) and use
sizeof(struct HT_caps_element) instead of pIE->length in rtw_set_ie()
to prevent OOB reads past the HT_caps struct (sashiko review of v3).
- In join_cmd_hdl() WLAN_EID_HT_OPERATION: add minimum length check
(pIE->length < sizeof(struct HT_info_element)) before casting pIE->data
to struct HT_info_element * and reading infos[0] (sashiko review of v3).
Changes in v3:
- No code changes from v2.
Changes in v2:
- Add IE loop header and payload bounds checks for issue_assocreq()
and join_cmd_hdl().
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
index 68ce422305ed..0c4a73805d39 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
@@ -2943,9 +2943,10 @@ void issue_assocreq(struct adapter *padapter)
switch (pIE->element_id) {
case WLAN_EID_VENDOR_SPECIFIC:
- if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) ||
+ if (pIE->length >= 4 &&
+ ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) ||
(!memcmp(pIE->data, WMM_OUI, 4)) ||
- (!memcmp(pIE->data, WPS_OUI, 4))) {
+ (!memcmp(pIE->data, WPS_OUI, 4)))) {
vs_ie_length = pIE->length;
if ((!padapter->registrypriv.wifi_spec) && (!memcmp(pIE->data, WPS_OUI, 4))) {
/* Commented by Kurt 20110629
@@ -2953,7 +2954,8 @@ void issue_assocreq(struct adapter *padapter)
* would be fail if we append vendor
* extensions information to AP
*/
-
+ if (pIE->length < 14)
+ break;
vs_ie_length = 14;
}
@@ -2967,8 +2969,10 @@ void issue_assocreq(struct adapter *padapter)
case WLAN_EID_HT_CAPABILITY:
if (padapter->mlmepriv.htpriv.ht_option) {
if (!(is_ap_in_tkip(padapter))) {
+ if (pIE->length < sizeof(struct HT_caps_element))
+ break;
memcpy(&(pmlmeinfo->HT_caps), pIE->data, sizeof(struct HT_caps_element));
- pframe = rtw_set_ie(pframe, WLAN_EID_HT_CAPABILITY, pIE->length, (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen));
+ pframe = rtw_set_ie(pframe, WLAN_EID_HT_CAPABILITY, sizeof(struct HT_caps_element), (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen));
}
}
break;
@@ -2981,7 +2985,7 @@ void issue_assocreq(struct adapter *padapter)
break;
}
- i += (pIE->length + 2);
+ i += sizeof(*pIE) + pIE->length;
}
if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK)
@@ -5340,7 +5344,8 @@ u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf)
switch (pIE->element_id) {
case WLAN_EID_VENDOR_SPECIFIC:/* Get WMM IE. */
- if (!memcmp(pIE->data, WMM_OUI, 4))
+ if (pIE->length >= WLAN_WMM_LEN &&
+ !memcmp(pIE->data, WMM_OUI, 4))
WMM_param_handler(padapter, pIE);
break;
@@ -5353,7 +5358,12 @@ u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf)
/* spec case only for cisco's ap because cisco's ap issue assoc rsp using mcs rate @40MHz or @20MHz */
{
- struct HT_info_element *pht_info = (struct HT_info_element *)(pIE->data);
+ struct HT_info_element *pht_info;
+
+ if (pIE->length < sizeof(struct HT_info_element))
+ break;
+
+ pht_info = (struct HT_info_element *)(pIE->data);
if (pnetwork->configuration.ds_config <= 14) {
if ((pregpriv->bw_mode & 0x0f) > CHANNEL_WIDTH_20)
@@ -5384,7 +5394,7 @@ u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf)
break;
}
- i += (pIE->length + 2);
+ i += sizeof(*pIE) + pIE->length;
}
/* check channel, bandwidth, offset and switch */
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v5 3/3] staging: rtl8723bs: fix OOB reads in rtw_get_wps_ie()
2026-05-11 16:57 [PATCH v5 0/3] staging: rtl8723bs: fix OOB reads and heap overflow in IE parsing Alexandru Hossu
2026-05-11 16:57 ` [PATCH v5 1/3] staging: rtl8723bs: fix OOB reads in update_beacon_info() and bwmode_update_check() Alexandru Hossu
2026-05-11 16:57 ` [PATCH v5 2/3] staging: rtl8723bs: fix OOB reads in IE loops in issue_assocreq() and join_cmd_hdl() Alexandru Hossu
@ 2026-05-11 16:57 ` Alexandru Hossu
2026-05-21 8:40 ` [PATCH v5 0/3] staging: rtl8723bs: fix OOB reads and heap overflow in IE parsing Greg KH
3 siblings, 0 replies; 6+ messages in thread
From: Alexandru Hossu @ 2026-05-11 16:57 UTC (permalink / raw)
To: greg; +Cc: linux-staging, linux-kernel, stable
Three out-of-bounds read paths in rtw_get_wps_ie():
1. rtw_get_wps_ie() reads the IE length byte without a header bounds
check.
The loop only guards on cnt < in_len, so when the buffer ends with
a single element_id byte and no length byte, in_ie[cnt + 1] is read
one byte past the end of the buffer. Add a check that at least
two header bytes remain (cnt + 2 <= in_len) before reading
in_ie[cnt + 1].
2. rtw_get_wps_ie() does not verify the declared IE payload fits within
in_len.
After reading the length byte, the loop does not verify that
in_ie[cnt + 1] + 2 bytes are available starting at cnt. A crafted
length value can cause the subsequent memcmp and memcpy to read past
the end of the buffer. Add a check that the full IE (header plus
payload) fits within in_len.
3. rtw_get_wps_ie() reads 4 bytes from the IE payload via memcmp
without checking that pIE->length >= 4.
The code calls memcmp(&in_ie[cnt + 2], wps_oui, 4) without first
verifying that the IE payload is at least 4 bytes long. Add an
in_ie[cnt + 1] >= 4 guard before the comparison.
Fixes: 554c0a3abf21 ("staging: Add rtl8723bs sdio wifi driver")
Cc: stable@vger.kernel.org
Signed-off-by: Alexandru Hossu <hossu.alexandru@gmail.com>
---
Changes in v5:
- No code changes from v4.
Changes in v4:
- Add two IE bounds checks in rtw_get_wps_ie(): break if fewer than two
header bytes remain, and break if the declared payload extends past
in_len; add in_ie[cnt + 1] >= 4 guard before the 4-byte WPS OUI memcmp
(sashiko review of v3).
Changes in v3:
- No code changes from v2.
Changes in v2:
- Add explicit size checks in rtw_cfg80211_set_wpa_ie() before memcpy
to prevent the 256-byte supplicant_ie buffer overflow (now in tree
as 92f3954ca9e9).
drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
index 72b7f731dd47..d6d5f3a8db4c 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
@@ -661,7 +661,14 @@ u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
while (cnt < in_len) {
eid = in_ie[cnt];
- if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) {
+ if (cnt + 2 > in_len)
+ break;
+
+ if (in_ie[cnt + 1] + 2 > in_len - cnt)
+ break;
+
+ if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (in_ie[cnt + 1] >= 4) &&
+ (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) {
wpsie_ptr = &in_ie[cnt];
if (wps_ie)
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread