← ALL ADVISORIES

LOW BYTERAY-2026-0233Disclosed

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) calls UsbBusBuildProtocol on the first start of the USB bus driver for a host controller.
  • Any USB host controller driver binding path that triggers EFI_OUT_OF_RESOURCES during root hub interface allocation.

Sanitization / Security Controls

  • NULL-check guard at FREE_ROOTHUB label (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->OpenProtocol on gEfiUsb2HcProtocolGuid (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

  1. Induce severe memory pressure during the DXE phase so that the RootIf allocation fails while the RootHub allocation succeeded — requires pathological firmware memory state or a malicious Option ROM/DXE driver already consuming pool memory.
  2. On the error branch, RootHub is freed at line 1047 without being nulled, then re-freed at lines 1086-1087, corrupting the UEFI pool allocator.
  3. 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.

References