* [PATCH wireless 1/2] wifi: rtw89: fix OOB read in rtw89_core_cancel_6ghz_probe_tx()
@ 2026-08-30 14:31 Tristan Madani
2026-08-30 14:31 ` [PATCH wireless 2/2] wifi: rtw89: fix OOB read in __rtw89_wow_parse_akm() Tristan Madani
2026-09-07 2:31 ` [PATCH wireless 1/2] wifi: rtw89: fix OOB read in rtw89_core_cancel_6ghz_probe_tx() Ping-Ke Shih
0 siblings, 2 replies; 5+ messages in thread
From: Tristan Madani @ 2026-08-30 14:31 UTC (permalink / raw)
To: Ping-Ke Shih
Cc: Kalle Valo, Po-Hao Huang, Chin-Yen Lee, linux-wireless, stable,
Tristan Madani
From: Tristan Madani <tristan@talencesecurity.com>
rtw89_core_cancel_6ghz_probe_tx() computes a pointer to the IE area
with
ies = mgmt->u.beacon.variable;
and then passes skb->len as the IE data length to cfg80211_find_ie():
ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, ies, skb->len);
skb->len is the total frame length, not the length of the IE portion.
The IEs start at offset 36 (24-byte header + 12-byte fixed fields), so
the correct IE length is skb->len minus that offset. Passing the full
frame length causes cfg80211_find_ie() to walk up to 36 bytes past the
end of the skb data buffer, triggering a slab-out-of-bounds read.
Additionally, the function does not verify that the frame is long enough
to contain the fixed beacon/probe-response fields before computing the
IE pointer.
Fix by returning early when skb->len is shorter than the variable-IE
offset, and pass the correct IE data length to cfg80211_find_ie().
Fixes: c6aa9a9c4725 ("wifi: rtw89: add RNR support for 6 GHz scan")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
---
drivers/net/wireless/realtek/rtw89/core.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 68dad6090f87e..7b46715ea12db 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -2532,9 +2532,11 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev,
{
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+ size_t hdr_len = offsetof(struct ieee80211_mgmt, u.beacon.variable);
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
struct rtw89_pktofld_info *info;
const u8 *ies = mgmt->u.beacon.variable, *ssid_ie;
+ size_t ie_len;
bool queue_work = false;
if (rx_status->band != NL80211_BAND_6GHZ)
@@ -2545,7 +2547,12 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev,
return;
}
- ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, ies, skb->len);
+ if (skb->len < hdr_len)
+ return;
+
+ ie_len = skb->len - hdr_len;
+
+ ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, ies, ie_len);
list_for_each_entry(info, &pkt_list[NL80211_BAND_6GHZ], list) {
if (ether_addr_equal(info->bssid, mgmt->bssid)) {
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH wireless 2/2] wifi: rtw89: fix OOB read in __rtw89_wow_parse_akm()
2026-08-30 14:31 [PATCH wireless 1/2] wifi: rtw89: fix OOB read in rtw89_core_cancel_6ghz_probe_tx() Tristan Madani
@ 2026-08-30 14:31 ` Tristan Madani
2026-09-05 23:43 ` [PATCH " Maxim Skokov
2026-09-07 2:40 ` [PATCH wireless " Ping-Ke Shih
2026-09-07 2:31 ` [PATCH wireless 1/2] wifi: rtw89: fix OOB read in rtw89_core_cancel_6ghz_probe_tx() Ping-Ke Shih
1 sibling, 2 replies; 5+ messages in thread
From: Tristan Madani @ 2026-08-30 14:31 UTC (permalink / raw)
To: Ping-Ke Shih
Cc: Kalle Valo, Po-Hao Huang, Chin-Yen Lee, linux-wireless, stable,
Tristan Madani
From: Tristan Madani <tristan@talencesecurity.com>
__rtw89_wow_parse_akm() computes a pointer to the IE area with
ies = mgmt->u.assoc_req.variable;
and then passes skb->len as the IE data length to cfg80211_find_ie():
rsn = cfg80211_find_ie(WLAN_EID_RSN, ies, skb->len);
skb->len is the total frame length, not the length of the IE portion.
The IEs in an association request start at offset 28 (24-byte header +
4-byte fixed fields), so the correct IE length is skb->len minus that
offset. Passing the full frame length causes cfg80211_find_ie() to walk
up to 28 bytes past the end of the skb data buffer, triggering a
slab-out-of-bounds read.
Fix by validating the minimum frame length and passing the correct IE
data length to cfg80211_find_ie().
Fixes: 480dd4dddfc5 ("wifi: rtw89: enter power save mode aggressively")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
---
drivers/net/wireless/realtek/rtw89/wow.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c
index 8dadd8df4fc65..82b74ded68631 100644
--- a/drivers/net/wireless/realtek/rtw89/wow.c
+++ b/drivers/net/wireless/realtek/rtw89/wow.c
@@ -16,10 +16,16 @@ void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
+ size_t hdr_len = offsetof(struct ieee80211_mgmt, u.assoc_req.variable);
const u8 *rsn, *ies = mgmt->u.assoc_req.variable;
struct rtw89_rsn_ie *rsn_ie;
- rsn = cfg80211_find_ie(WLAN_EID_RSN, ies, skb->len);
+ if (skb->len < hdr_len)
+ return;
+
+ rsn = cfg80211_find_ie(WLAN_EID_RSN, ies,
+ skb->len - hdr_len);
+
if (!rsn)
return;
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] wifi: rtw89: fix OOB read in __rtw89_wow_parse_akm()
2026-08-30 14:31 ` [PATCH wireless 2/2] wifi: rtw89: fix OOB read in __rtw89_wow_parse_akm() Tristan Madani
@ 2026-09-05 23:43 ` Maxim Skokov
2026-09-07 2:40 ` [PATCH wireless " Ping-Ke Shih
1 sibling, 0 replies; 5+ messages in thread
From: Maxim Skokov @ 2026-09-05 23:43 UTC (permalink / raw)
To: tristan, tristmd; +Cc: pkshih, linux-wireless, linux-kernel
On Sun, Aug 30, 2026 at 02:31:53PM +0000, Tristan Madani wrote:
> skb->len is the total frame length, not the length of the IE portion.
> The IEs in an association request start at offset 28 (24-byte header +
> 4-byte fixed fields), so the correct IE length is skb->len minus that
> offset. Passing the full frame length causes cfg80211_find_ie() to walk
> up to 28 bytes past the end of the skb data buffer, triggering a
> slab-out-of-bounds read.
The length passed to cfg80211_find_ie() is indeed wrong and the fix looks
correct to me. I did try to reproduce the reported slab-out-of-bounds
though, and I don't think it is reachable. If I'm wrong about this,
I'd be glad to be corrected.
cfg80211_find_ie() walks the elements via for_each_element(), which is
bounded by _data + _datalen and never dereferences past it. With
ies = skb->data + 28 and len = skb->len, the highest byte the walk can
touch is skb->data + 28 + skb->len - 1, i.e. exactly 28 bytes past
skb_tail_pointer(), as you describe.
What follows skb_tail_pointer(), however, is the skb tailroom and then
struct skb_shared_info, and both live inside the same allocation.
sizeof(struct skb_shared_info) is 320 bytes on x86_64, so even with zero
tailroom the 28-byte overread stays within the object and KASAN has
nothing to report.
Measured on RTL8851BE (rtw89_8851be) with a kprobe on
__rtw89_wow_parse_akm(), on a real association request:
skb->len tailroom overread slack to end of allocation
160 1552 28 1872
So the defect is a read of uninitialised memory inside the skb rather
than an out-of-bounds access -- KMSAN territory, not KASAN. The
practical consequence is that on a network with no RSN IE (an open BSS,
where mac80211 emits no RSN element at all), the walk continues into the
tailroom and may match a bogus element with id 48, after which
rtw_wow->akm is set from garbage.
That is still worth fixing, but it may be worth rewording the commit
message, since the "slab-out-of-bounds" wording is what justifies the
Cc: stable here. The same reasoning applies to patch 1/2.
One more thing in the same function, which this patch does not address:
rsn_ie = (struct rtw89_rsn_ie *)rsn;
rtw_wow->akm = rsn_ie->akm_cipher_suite.type;
struct rtw89_rsn_ie is 20 bytes and akm_cipher_suite.type sits at offset
19, but cfg80211_find_ie() only validates the element header. A minimal
RSN element with datalen = 2 (version only) makes that read land 15
bytes past the end of the element, and with the length fix applied it can
still reach past the end of the frame when the element sits at the tail.
Checking rsn[1] before the cast would close that too.
Thanks,
Maxim
^ permalink raw reply [flat|nested] 5+ messages in thread
* RE: [PATCH wireless 1/2] wifi: rtw89: fix OOB read in rtw89_core_cancel_6ghz_probe_tx()
2026-08-30 14:31 [PATCH wireless 1/2] wifi: rtw89: fix OOB read in rtw89_core_cancel_6ghz_probe_tx() Tristan Madani
2026-08-30 14:31 ` [PATCH wireless 2/2] wifi: rtw89: fix OOB read in __rtw89_wow_parse_akm() Tristan Madani
@ 2026-09-07 2:31 ` Ping-Ke Shih
1 sibling, 0 replies; 5+ messages in thread
From: Ping-Ke Shih @ 2026-09-07 2:31 UTC (permalink / raw)
To: Tristan Madani
Cc: Kalle Valo, Bernie Huang, Timlee, linux-wireless@vger.kernel.org,
stable@vger.kernel.org, Tristan Madani
Tristan Madani <tristmd@gmail.com> wrote:
> @@ -2545,7 +2547,12 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev,
> return;
> }
>
> - ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, ies, skb->len);
> + if (skb->len < hdr_len)
> + return;
> +
> + ie_len = skb->len - hdr_len;
> +
> + ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, ies, ie_len);
We are working on a patch to correct logic of scanning on 6GHz band, and
remove the use of cfg80211_find_ie(). I'd take the patch.
>
> list_for_each_entry(info, &pkt_list[NL80211_BAND_6GHZ], list) {
> if (ether_addr_equal(info->bssid, mgmt->bssid)) {
> --
> 2.47.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* RE: [PATCH wireless 2/2] wifi: rtw89: fix OOB read in __rtw89_wow_parse_akm()
2026-08-30 14:31 ` [PATCH wireless 2/2] wifi: rtw89: fix OOB read in __rtw89_wow_parse_akm() Tristan Madani
2026-09-05 23:43 ` [PATCH " Maxim Skokov
@ 2026-09-07 2:40 ` Ping-Ke Shih
1 sibling, 0 replies; 5+ messages in thread
From: Ping-Ke Shih @ 2026-09-07 2:40 UTC (permalink / raw)
To: Tristan Madani
Cc: Kalle Valo, Bernie Huang, Timlee, linux-wireless@vger.kernel.org,
stable@vger.kernel.org, Tristan Madani
Tristan Madani <tristmd@gmail.com> wrote:
> From: Tristan Madani <tristan@talencesecurity.com>
>
> __rtw89_wow_parse_akm() computes a pointer to the IE area with
>
> ies = mgmt->u.assoc_req.variable;
>
> and then passes skb->len as the IE data length to cfg80211_find_ie():
>
> rsn = cfg80211_find_ie(WLAN_EID_RSN, ies, skb->len);
>
> skb->len is the total frame length, not the length of the IE portion.
> The IEs in an association request start at offset 28 (24-byte header +
> 4-byte fixed fields), so the correct IE length is skb->len minus that
> offset. Passing the full frame length causes cfg80211_find_ie() to walk
> up to 28 bytes past the end of the skb data buffer, triggering a
> slab-out-of-bounds read.
>
> Fix by validating the minimum frame length and passing the correct IE
> data length to cfg80211_find_ie().
>
> Fixes: 480dd4dddfc5 ("wifi: rtw89: enter power save mode aggressively")
> Cc: stable@vger.kernel.org
> Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
> ---
> drivers/net/wireless/realtek/rtw89/wow.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c
> index 8dadd8df4fc65..82b74ded68631 100644
> --- a/drivers/net/wireless/realtek/rtw89/wow.c
> +++ b/drivers/net/wireless/realtek/rtw89/wow.c
> @@ -16,10 +16,16 @@ void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb)
> {
> struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
> struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
> + size_t hdr_len = offsetof(struct ieee80211_mgmt, u.assoc_req.variable);
> const u8 *rsn, *ies = mgmt->u.assoc_req.variable;
> struct rtw89_rsn_ie *rsn_ie;
>
> - rsn = cfg80211_find_ie(WLAN_EID_RSN, ies, skb->len);
> + if (skb->len < hdr_len)
Since the skb is generated by local to do association, I wonder that
does it possibly happen?
> + return;
> +
> + rsn = cfg80211_find_ie(WLAN_EID_RSN, ies,
> + skb->len - hdr_len);
Straighten the line.
> +
no need this blank line.
> if (!rsn)
> return;
>
> --
> 2.47.3
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-07 2:40 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-30 14:31 [PATCH wireless 1/2] wifi: rtw89: fix OOB read in rtw89_core_cancel_6ghz_probe_tx() Tristan Madani
2026-08-30 14:31 ` [PATCH wireless 2/2] wifi: rtw89: fix OOB read in __rtw89_wow_parse_akm() Tristan Madani
2026-09-05 23:43 ` [PATCH " Maxim Skokov
2026-09-07 2:40 ` [PATCH wireless " Ping-Ke Shih
2026-09-07 2:31 ` [PATCH wireless 1/2] wifi: rtw89: fix OOB read in rtw89_core_cancel_6ghz_probe_tx() Ping-Ke Shih
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).