From a toy driver to a real one
The last writeup linked a .ko into
mwemu, resolved its imports to a synthetic kernel, and modelled the slab so a lifetime
bug surfaced as a report instead of a panic. The natural next question: does the same
rig say anything useful about code that ships to real machines? So I loaded
drivers/staging/rtl8723bs — the driver for a common RTL8723BS SDIO Wi-Fi
part — exactly as the tree ships it, and drove one function that parses received
frames.
An attribute that lies about its length
A WPS information element is a list of attributes, each
[id:2][data_len:2][data…]. rtw_get_wps_attr_content()
finds one and copies its data into the caller's buffer — using the length straight from
the frame, with nothing said about how big the destination is:
memcpy(buf_content, attr_ptr + 4, attr_len - 4); /* no bound on the destination */
The Selected Registrar attribute is one byte by spec, so callers hand it a
one-byte destination. And this runs on the ordinary scan path — for every network seen,
rtw_cfg80211_inform_bss() reads the WPS IE out of a received
beacon / probe-response into a single stack byte:
u8 sr = 0; /* one byte on the stack */
...
rtw_get_wps_attr_content(wpsie, wpsielen,
WPS_ATTR_SELECTED_REGISTRAR, &sr, NULL);
A frame whose Selected Registrar attribute declares a length larger than one byte makes the copy run long, over the stack. The IEs come verbatim from the received frame, so the length is attacker-controlled — and a scan happens on its own under NetworkManager/iwd. No pairing, no association, just being in radio range while the machine looks around.
What mwemu saw
Driven with a crafted WPS IE (a Selected Registrar attribute of declared length 100) into a one-byte tracked chunk, the ledger flags the copy exactly where it leaves the object:
BUG: KMWEMU: slab-out-of-bounds in u8 sr of size 100 at addr 0xffff888000000001
object 0xffff888000000000..0xffff888000000008 (requested 1 bytes, bucket 8), offset 1
Same idea as the toy driver: the destination stays mapped and guarded, so the write
past it becomes a line of text instead of an invisible corruption. On a normal kernel
the corrupted stack canary lands you, at minimum, in a __stack_chk_fail
panic — a remote, unauthenticated denial of service for a machine with this chip that
happens to be scanning nearby.
What emulation can and can't tell you
This is the honest part, and it is the whole reason the workflow is healthy.
Emulation drove the parser in isolation and proved the mechanism; the reachability
chain — received frame → scan queue → the one-byte destination — was read
from the source. What I did not do is run the whole path end to end on a real
RTL8723BS. That last step matters: analysis and LLM-assisted review are good at
producing plausible memory-safety candidates, and a healthy fraction of plausible
candidates are wrong. Confirming them on the actual hardware is what separates a real
fix from noise, and asking for that confirmation is good stewardship, not
gatekeeping — drivers/staging/ is explicitly low-assurance
(TAINT_CRAP) and treated accordingly.
So this is written as what it is: a strong, tool-surfaced candidate with a one-line fix, reported upstream, waiting on someone with the part to close the loop on metal.
The fix, and the wider pattern
The fix is small — reject an attribute that claims more data than the IE holds, hand
the function the destination size, and clamp the copy to it (and compute the length in
a wider type so it can't wrap). Worth a broader look: this
rtw_get_wps_attr* code is vendor code duplicated across the wider Realtek
family, so the same shape is worth checking wherever it was copied — several out-of-tree
forks carry it, and at least one already clamps.
The takeaway isn't alarm. It's that over-the-air parsers are reachable by design, the bugs in them are ordinary and fixable, and a driver emulator is a cheap early net — one that hands a finding to a human, who still has to prove it on hardware.
References
- mwemu — the emulator (kernel-mode lives in
libmwemu::kernel) - A kernel without a kernel — the toy-driver chapter
- The patch and its review on lore (linux-staging)
Reported to the kernel security list and the staging maintainers; a fix was posted publicly. Found by source review plus function-level emulation under mwemu, assisted by an AI, and reviewed and signed off by a human. Not yet confirmed on real hardware.