EDK II - Incorrect Bitwise Shift of Integer in EnumerateNvmeDevNamespace
The device-controlled LBA Data Size (Lbads) field — a full UINT8 (0–255) from the NVMe Identify Namespace response — is used directly as the shift amount in (UINT32)1 << Lbads without any bounds validation.
- Advisory
- BYTERAY-2026-0231
- CWE
- CWE-1335
- 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/Pci/NvmExpressDxe/NvmExpress.c.
- Credit
- Argus-Systems
Executive Summary
The device-controlled LBA Data Size (Lbads) field — a full UINT8 (0–255) from the NVMe Identify Namespace response — is used directly as the shift amount in (UINT32)1 << Lbads without any bounds validation. The only check before the shift is on the metadata size (Ms != 0). For Lbads >= 32 this is an overshift producing undefined behavior. On x86 and AArch64 the hardware masks a register shift count to 5 bits, so the result is still a power of two; BlockSize == 0 depends on how the compiler and target handle the oversized shift. Values 0 to 31 are also accepted, so the device can already set nonsense block sizes such as 1 or 2^31. The resulting BlockSize propagates to Device->Media.BlockSize and is used in all subsequent block I/O operations, where a zero value divides by zero and a very large value overflows the byte count. The same pattern is replicated in NvmExpressMediaSanitize.c:159 (Format NVM path) and NvmExpressPei.c:140 (PEI phase).
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/Pci/NvmExpressDxe/NvmExpress.c:159 - Function:
EnumerateNvmeDevNamespace - Category:
CWE-1335 Incorrect Bitwise Shift of Integer
Technical Details
Controllability: EXTERNAL_UNTRUSTED — confidence: high
Data Flow
The NVMe Identify Namespace command (NvmeIdentifyNamespace() at NvmExpress.c:95) issues a command to the external NVMe device, which returns device-controlled NamespaceData. The Lbads field (UINT8, 0–255) is extracted at NvmExpress.c:158 from NamespaceData->LbaFormat[LbaFmtIdx].Lbads with no bounds validation — the only check is Ms != 0 at line 147. At line 159, the unsanitized Lbads is used as a shift amount in Device->Media.BlockSize = (UINT32)1 << Lbads, triggering undefined behavior for Lbads >= 32 (overshift). The unvalidated BlockSize propagates downstream to NvmExpressBlockIo.c:42 (Bytes = Blocks * BlockSize, which can overflow for a large BlockSize), NvmExpressBlockIo.c:193 (MaxTransferBlocks = (...) / BlockSize, divide-by-zero if BlockSize == 0), and NvmExpressBlockIo.c:203 (Buffer += MaxTransferBlocks * BlockSize).
Affected Callers
EnumerateNvmeDevNamespaceNvmeFormatNvmNvmeReadSectorsNvmeWriteSectorsNvmeReadNvmeWrite
Sanitization / Security Controls
- Only
Ms != 0check at line 147 — does NOT validateLbads. No sanitization points or security controls exist for the shift amount.
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
Reproduction
- Craft malicious NVMe device firmware returning Identify Namespace response with
Lbadsset to 32+. - Connect device.
- Boot system triggers enumeration.
Ms==0passes the only check.1 << Lbadsproduces UB.- Invalid
BlockSizepropagates. - Block I/O runs with the invalid
BlockSize; if the shift produced 0, the divide atNvmExpressBlockIo.c:193crashes firmware.
Impact
Mis-sized block I/O or a firmware crash (denial of service during boot) in the DXE or PEI NVMe driver, triggered by a malicious NVMe device with physical PCIe access. Such a device can already reach memory through DMA on systems without an IOMMU.
Remediation and Mitigation
As of commit 70741a15d9a714323a5598eac47727e60507e22f this issue is unfixed upstream and no CVE has been assigned. Validate that the shift count is within the range of the operand width before shifting. 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.