EDK II - Out-of-Bounds Heap Read in RndisUndiReceive
RndisUndiReceive is the RNDIS implementation of the same EDKII_USB_ETHERNET_PROTOCOL.UsbEthReceive handler interface.
- Advisory
- BYTERAY-2026-0286
- CWE
- CWE-125, CWE-129, CWE-20
- Vendor
- TianoCore
- Product
- EDK II
- Reported
- 2026-06-25
- Disclosure
- 2026-10-29
- Affected
- EDK II at commit 70741a15d9a714323a5598eac47727e60507e22f (master, 2026-06-21); affected code in MdeModulePkg/Bus/Usb/UsbNetwork/UsbRndis/UsbRndisFunction.c.
- Credit
- Argus-Systems
Executive Summary
RndisUndiReceive is the RNDIS implementation of the same EDKII_USB_ETHERNET_PROTOCOL.UsbEthReceive handler interface. In the packet extraction block (lines 1366–1391), the CopyMem at lines 1376–1380 copies RndisPacketMsg->DataLength bytes from source pointer (UINT8*)RndisPacketMsg + (DataOffset + RNDIS_RESERVED_BYTE_LENGTH) into the caller-supplied BulkInData buffer. While DataOffset is constrained to a fixed value (checked at line 1372), the DataLength field is a 32-bit value taken directly from the attacker-controlled REMOTE_NDIS_PACKET_MSG and is never validated against the actual received data length (RemainingLength/TransferLength). The only length checks validate the message envelope (RemainingLength >= MessageLength) and destination capacity (*DataLength >= RndisPacketMsg->DataLength), neither of which constrains the source read. The destination capacity is Nic->MaxSegmentSize (set by the caller UndiReceive, PxeFunction.c:1549), so the over-read is bounded by that size. Additionally, the pool allocation size at line 1327 is derived from UsbRndisDevice->MaxTransferSize, which is itself an attacker-controlled value from the device's RNDIS_INITIALIZE_CMPLT response (set at line 1107), allowing the attacker to manipulate heap layout.
This advisory is one of a set reported to VulnCheck on 2026-06-25 for coordinated disclosure to the EDK II maintainers. After several follow-ups over the following months no response was received. 126 days after the initial report, ByteRay is publishing the findings in good faith so that affected integrators can assess and remediate them. All findings were identified against EDK II commit 70741a15d9a714323a5598eac47727e60507e22f (master, 2026-06-21).
Affected Products and Versions
- Vendor: TianoCore
- Product: EDK II (
MdeModulePkg) - Affected commit:
70741a15d9a714323a5598eac47727e60507e22f(master, 2026-06-21). The code is present on that commit and later revisions that have not changed it. - Location:
MdeModulePkg/Bus/Usb/UsbNetwork/UsbRndis/UsbRndisFunction.c:1376 - Function:
RndisUndiReceive - Category:
CWE-125/129/20 — Out-of-bounds heap read via attacker-controlled header length field in CopyMem
Technical Details
Controllability: EXTERNAL_UNTRUSTED — confidence: high
Data Flow
At UsbRndisFunction.c:1107, MaxTransferSize is set from the attacker-controlled RNDIS_INITIALIZE_CMPLT response. At line 1327, the receive buffer is allocated with size derived from this attacker value. At lines 1339–1343, RndisReceiveDataMsg performs a USB bulk transfer filling RndisPacketMsg (TransferLength = actual bytes received). At lines 1371–1374, envelope checks pass (MessageType == RNDIS_PACKET_MSG, DataOffset == fixed constant, RemainingLength >= MessageLength) but do not validate DataLength against the actual received payload. At line 1375, the destination capacity check (*DataLength >= DataLength) only verifies the destination buffer is large enough. At lines 1376–1380, CopyMem reads DataLength bytes (at most the caller's *DataLength, Nic->MaxSegmentSize) from the source without any source-bounds check, enabling an OOB heap read past valid received data; with a small device-reported MaxTransferSize the read goes past the pool allocation into adjacent pool memory.
Affected Callers
PxeFunction.c:UndiReceive(Nic->UsbEth->UsbEthReceive→RndisUndiReceive)
Sanitization / Security Controls
One partially effective sanitization point and three ineffective controls were identified:
DataOffset == sizeof(REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH(line 1372): Partially effective — constrainsDataOffsetto a fixed known value, preventing arbitrary source pointer computation viaDataOffset. However, it does not constrainDataLength.RemainingLength >= MessageLength(line 1373): Ineffective — validates the message envelope only.DataLengthis independent ofMessageLengthand never checked againstRemainingLength.*DataLength >= RndisPacketMsg->DataLength(line 1375): Ineffective — validates destination capacity only, not source bounds. An attacker setsDataLengthto a value within destination capacity but larger than the actual received payload.MessageType == RNDIS_PACKET_MSG(line 1371): Ineffective — trivially satisfied by a malicious device.
Reachability and Preconditions
Attacker position and trust level for this issue are stated in the Controllability line and Data Flow above, and the concrete trigger is in Reproduction below.
Exploitability: Medium
Realism: Medium
Reproduction
- Attacker connects a malicious USB RNDIS adapter to the target.
- During RNDIS initialization, the device supplies a crafted
MaxTransferSizeto influence allocation size. - During PXE boot, the firmware calls
RndisUndiReceive. - The adapter responds with a crafted
REMOTE_NDIS_PACKET_MSGwhereMessageType = RNDIS_PACKET_MSG,DataOffsetmatches the fixed expected value,MessageLength <= RemainingLength, andDataLengthexceeds the actual payload but is within destination capacity. CopyMemreadsDataLengthbytes past the valid received data into adjacent heap memory.- OOB data (at most
Nic->MaxSegmentSizebytes in total) is copied intoBulkInDataand returned up the network stack.
Impact
Out-of-bounds heap read of up to Nic->MaxSegmentSize bytes past the received data, requiring a malicious USB RNDIS device attached to the target. The over-read bytes are delivered up the firmware network stack as part of a received frame (PxeFunction.c:1583), which can expose adjacent pool contents to the boot network stack, or fault if the read reaches unmapped memory. The destination is bounded, so there is no write. The attacker-controlled MaxTransferSize also sets the receive allocation size.
Remediation and Mitigation
As of commit 70741a15d9a714323a5598eac47727e60507e22f this issue is unfixed upstream and no CVE has been assigned. Before reading each field, validate that its full width fits within the remaining bytes derived from the packet or record size, and stop parsing or reject the input when it does not. Validate the array index against the number of elements before using it to read or write the array. The specific control that is absent or ineffective is identified in the Sanitization / Security Controls list under Technical Details.
Timeline
- 2026-06-25 - Reported to VulnCheck for coordinated disclosure to the TianoCore / EDK II security team.
- 2026-07 to 2026-10 - Several follow-ups sent; no response received.
- 2026-10-29 - Public disclosure in good faith, 126 days after the initial report.
Credits
Discovered and reported by Argus-Systems.