EDK II - Double Free in UsbBusBuildProtocol
In UsbBusBuildProtocol (whose debug messages are prefixed UsbBusStart), RootHub is allocated at line 1037 (AllocateZeroPool(sizeof(USB_DEVICE))).
- Advisory
- BYTERAY-2026-0233
- CWE
- CWE-1341
- 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/UsbBusDxe/UsbBus.c.
- Credit
- Argus-Systems
Executive Summary
In UsbBusBuildProtocol (whose debug messages are prefixed UsbBusStart), RootHub is allocated at line 1037 (AllocateZeroPool(sizeof(USB_DEVICE))). When the subsequent RootIf allocation at line 1044 fails (returns NULL), control reaches line 1047 where FreePool(RootHub) is called without setting RootHub to NULL, followed by goto FREE_ROOTHUB at line 1049. The FREE_ROOTHUB label (line 1081) falls through to the cleanup block at lines 1086-1087 where if (RootHub != NULL) { FreePool(RootHub); } passes because the dangling pointer is non-NULL, re-freeing the already-freed allocation. This is the exact same double-free shape as the confirmed EfiHttpRequest finding.
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/UsbBusDxe/UsbBus.c:1047 - Function:
UsbBusBuildProtocol - Category:
CWE-1341 / CWE-415 (Double Free)
Technical Details
Controllability: SYSTEM_CONTROLLED — confidence: high
Data Flow
UsbBusBuildProtocol is invoked by UsbBusControllerDriverStart (UsbBus.c:1315) during USB host controller driver binding and itself opens gEfiUsb2HcProtocolGuid (UsbBus.c:986-1000) before the root hub allocation. RootHub is allocated at line 1037 (AllocateZeroPool(sizeof(USB_DEVICE))). The subsequent allocation of RootIf at line 1044 (AllocateZeroPool(sizeof(USB_INTERFACE))) fails and returns NULL. At line 1046-1049, the error branch frees RootHub at line 1047 without setting it to NULL (dangling pointer), sets Status = EFI_OUT_OF_RESOURCES, and executes goto FREE_ROOTHUB. The FREE_ROOTHUB label at line 1081 falls through to lines 1086-1087, where the NULL guard if (RootHub != NULL) passes because the dangling pointer is non-NULL, re-freeing RootHub — a double-free.
Affected Callers
UsbBusControllerDriverStart(UsbBus.c:1315) callsUsbBusBuildProtocolon the first start of the USB bus driver for a host controller.- Any USB host controller driver binding path that triggers
EFI_OUT_OF_RESOURCESduring root hub interface allocation.
Sanitization / Security Controls
- NULL-check guard at
FREE_ROOTHUBlabel (UsbBus.c:1086) — ineffective: the guard is defeated by the dangling non-NULL pointer, which is precisely the double-free bug. - Driver binding entry requires successful
gBS->OpenProtocolongEfiUsb2HcProtocolGuid(UsbBus.c:986-1000) — effective for gating enumeration but irrelevant to the memory-corruption defect once reached.
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: Low
Realism: Low — no external/remote input reaches the path; the trigger is a system OOM condition, and any actor able to deterministically induce it already holds the privilege the sink confers.
Reproduction
- Induce severe memory pressure during the DXE phase so that the
RootIfallocation fails while theRootHuballocation succeeded — requires pathological firmware memory state or a malicious Option ROM/DXE driver already consuming pool memory. - On the error branch,
RootHubis freed at line 1047 without being nulled, then re-freed at lines 1086-1087, corrupting the UEFI pool allocator. - Pool corruption may lead to a boot-time crash (denial of service); reliable code execution would require a prior foothold at DXE privilege to groom the allocator.
Impact
Boot-time UEFI memory pool corruption; primarily denial of service (firmware hang/reboot during USB init). Arbitrary code execution is theoretical and requires a pre-existing DXE-privilege foothold (self-injection / no privilege boundary crossed).
Remediation and Mitigation
As of commit 70741a15d9a714323a5598eac47727e60507e22f this issue is unfixed upstream and no CVE has been assigned. After freeing a buffer, clear the pointer and restructure the error path so each allocation is freed exactly once. 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.