Nightjar

Zero-click block pool overflow in Marvell Avastar Wi-Fi firmware (CVE-2019-6496)

Identifier
CVE-2019-6496
Software
Marvell Avastar
Affected
Marvell Avastar Wi-Fi SoCs 88W8787, 88W8797, 88W8801, 88W8897, 88W8997
Fixed in
Marvell states it deployed a fix in its standard driver and firmware
Reported by
Denis Selianin, Embedi
Disclosed
15 June 2018

A laptop holds more processors than the spec sheet lists. One of them runs your operating system. The others run firmware you will never see, on memory your operating system cannot read. Their work has to happen faster than a general-purpose scheduler can promise.

The Marvell Avastar family is one of those. It is a wireless system-on-chip: radio, MAC layer, its own CPU core, its own RAM, and an operating system of its own. The host loads firmware onto it over the bus at boot. After that it talks to the chip the way you talk to a peripheral, in commands and buffers.

Denis Selianin, working at Embedi, looked inside one. He read the driver code and fuzzed the firmware. Several vulnerabilities came out. He presented the work at ZeroNights in November 2018. CERT gives 21 November as the date it became public, and a write-up followed in January 2019. The one everybody remembers is a block pool overflow that a device reaches on its own, with nobody touching it. Marvell's own statement notes that the demonstration ran on the open-source Valve Steam Link.

how the parser gets reached every 5 minutes not connected connected scan: hop channels, parse every element out-of-bounds write one bad length byte no association, no key, no user action
Both states reach the same parser on a five-minute timer, on frames from anyone in range.

The Avastar and ThreadX#

Wi-Fi has deadlines. Frames need acknowledging inside microseconds, and timing has to hold across channel switches. A general-purpose kernel might decide to page something in, and the timing is gone. So the time-critical half of 802.11 moved onto dedicated silicon a long time ago. That silicon needs software, and that software needs a real-time operating system. NVD's description of the CVE names what the Avastar runs: "The ThreadX-based firmware on Marvell Avastar Wi-Fi devices".

An RTOS of that kind is a library you link against. It is not a kernel that lives behind a privilege boundary. Tasks share one flat address space. There is no process isolation to breach because there are no processes.

The whole arrangement also sits outside anything your host does about security. Secure boot on the main CPU, a hardened kernel, an EDR agent watching syscalls: none of it can see a single byte of the Wi-Fi chip's RAM.

The affected parts are the 88W8787, 88W8797, 88W8801, 88W8897 and 88W8997. Between them they turned up in Microsoft Surface devices, the Xbox One, the PlayStation 4, Samsung Chromebooks, the Galaxy J1 and the Steam Link. Not a niche part.

Parsing scan results#

To show you a list of nearby networks, a station listens. It hops channels and collects beacon frames and probe responses. Those arrive as a sequence of information elements: a one-byte tag, a one-byte length, then that many bytes of value. The network name is one of those. So are the supported rates, the country code, the vendor extensions, and a long tail of things added over twenty years of amendments.

Every byte of that came off the air, from a transmitter nobody authenticated. There is no association, no key exchange, no password. Parsing scan results is the first thing a Wi-Fi stack does. It does it for anyone in range.

Selianin's point about this bug was that the scan is not something you trigger. In his words: "This procedure is launched every 5 minutes regardless of a device being connected to some Wi-Fi network or not." The chip does it on a timer.

He gives the reason it matters.

That's why this bug is so cool and provides an opportunity to exploit devices literally with zero-click interaction at any state of wireless connection (even when a device isn't connected to any network).

His example: "one can do RCE in just powered-on Samsung Chromebook." CERT says the same thing in flatter language. Exploitation is possible "regardless of whether the target is connected to a Wi-Fi network and without user interaction."

That is a different shape of problem from a bug in a PDF reader. A bug that needs a click has a person involved, and that person can be trained, warned, or away from the desk. This one has a timer. The CVSS vector NVD assigned records the same thing in shorthand: AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, 8.8. Adjacent network, low complexity, no privileges, no user interaction.

Block pools#

Firmware like this rarely uses a general-purpose heap. malloc has variable-length behaviour and can fragment memory until an allocation fails at an inconvenient moment. Neither of those is acceptable when you have a hard deadline. ThreadX offers block pools instead. You carve a region of memory into blocks of one fixed size at startup. After that, allocation is popping the head off a free list, and freeing is pushing it back. Constant time, no fragmentation, nothing to tune.

The part that matters here is where the free list lives. A free block has nothing useful in it, so the pointer to the next free block is stored inside the block itself. The bookkeeping and the data occupy the same memory at different times.

before: the free list runs through the blocks themselves next next next block A block B block C after: 255 bytes are copied into block A next next block A block B block C written: all of A, then B's pointer an address off the air the next allocation hands that address out as a free block
The free list lives inside the free blocks, so a copy that runs long rewrites the list.

So an overflow past the end of one block writes into the bookkeeping of the next. That is what CERT recorded: a block pool overflow, during the Wi-Fi network scan, that can overwrite block pool data structures. The allocator does no consistency checking on its own metadata. It has no reason to. It was designed for determinism on a processor with a fixed workload, in an era when nothing hostile was supposed to reach it.

The out-of-bounds write#

The written record is a CERT note and a CVE, not a patch. The exact call site is not public the way a kernel commit would be. What is public is the class. NVD files it as CWE-787, out-of-bounds write, "via malformed Wi-Fi packets during identification of available Wi-Fi networks".

Here is that class, written out in C that is nobody's actual code:

c
/* illustrative only */
buf = block_allocate(&scan_pool);      /* fixed size, decided at pool setup */
memcpy(buf, ie->data, ie->len);        /* ie->len is a byte off the air */
one information element, straight off the air tag len value 1 byte 1 byte len bytes, sender's choice len sets the copy length: up to 255 memory in the scan pool end of block block: fixed size next ptr next block untouched bytes actually written
The block size is decided at pool setup and the copy length arrives from the air.

This is easy to write because the block's size is not present at the call site. With malloc you at least typed the number, and it sits there for a reviewer to compare against. With a fixed-size pool the size was decided somewhere else, at configuration time, possibly in another file. The relationship between "how big are blocks in this pool" and "how big can this field be" lives in a person's head. It stays correct for as long as everyone remembers it.

And nobody was fuzzing it. Firmware ships as a blob with no build system you can reach, no sanitizers, no test harness. Getting a fuzzer pointed at it was work that had to happen before any bug could surface. That is most of why this went unexamined for so long.

Impact#

A compromised Wi-Fi SoC is bad on its own terms. It sees every frame the device sends and receives. CERT puts the impact wider than that. An unauthenticated attacker in radio range "may be able to use a specially-crafted series of Wi-Fi frames execute arbitrary code on a system with a vulnerable Marvell SoC".

Depending on implementation, the compromised SoC may then be used to intercept network traffic or achieve code execution on the host system.

Drivers are written on the assumption that their own hardware is not lying to them. That assumption is the whole of the defence in that direction.

The fix#

Marvell's statement to CERT says: "Marvell deployed a fix to address this issue which we have made available in our standard driver and firmware". The statement adds: "Marvell is not aware of any real world exploitation of this vulnerability outside of a controlled environment". Microsoft confirmed affected Marvell firmware on a long list of Surface models: Surface 3, Book, Book 2, Laptop, Studio, Pro 3, Pro 4 and Pro 5th Gen. Microsoft issued updates for them. Synology told CERT it does not use Marvell Avastar SoCs in its products.

There is no diff to show you. That is the honest ending here. For the Python and kernel bugs we've written up you can pull the commit and read the added bounds check yourself. For this one the fix is a new blob. Whether your particular device ever received it depended on a chain of firmware handoffs: Marvell to a module vendor, to a device maker, to whatever update mechanism that device has, if it has one. CERT suggested restricting physical access to affected devices and disabling Wi-Fi where another connection is available. Neither is a workaround for a games console or a Chromebook.

The vulnerability is CVE-2019-6496, tracked by CERT as VU#730261, released 5 February 2019 and last revised 19 April that year. CERT's note lists three vendors as affected: Marvell, Microsoft and Valve. A dozen or so are listed as not affected, and well over a hundred as unknown. That last number is the more honest one for a part that shipped inside other people's products.

Sources

  1. 1VU#730261: Marvell Avastar wireless SoCs have multiple vulnerabilitieskb.cert.org
  2. 2CVE-2019-6496: block pool overflow in Marvell Avastar Wi-Fi firmwarenvd.nist.gov
  3. 3Bug in widespread Wi-Fi chipset firmware can lead to zero-click code executionhelpnetsecurity.com