# CVE-2026-40404 — Windows UDFS `udfs.sys` Allocation-Descriptor Length Truncation in `UdfInitializeAllocations` → Heap Overflow

---

## Summary

| | |
|---|---|
| **Product** | Windows — `udfs.sys` (Universal Disk Format File System driver) |
| **CVE ID** | CVE-2026-40404 |
| **Impact** | Elevation of Privilege |
| **MSRC severity** | Important |
| **CVSS** | 7.8 / 6.8 — `CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H/E:U/RL:O/RC:C` |
| **CWE** | CWE-197 Numeric Truncation Error → CWE-122 Heap-based Buffer Overflow |
| **Delivery** | Local — a crafted UDF image (`.iso` / `.img` / UDF VHD) mounted or opened |
| **KB / Fixed build** | KB5094126 — `udfs.sys` 10.0.26100.8655 (Win11 24H2 x64) |
| **Patch Date** | June 9, 2026 (2026-Jun) |
| **Pre-patch binary** | `udfs.sys` 10.0.26100.8521 — SHA256 `b177af321fdb4ff6907f05b028e7ac33486c2000dbc1e75c4bed848f84e164c6` |
| **Post-patch binary** | `udfs.sys` 10.0.26100.8655 — SHA256 `2a9b930ad0ccb43fc6b31cb8a600cb026bb5dea9ccf79c28c7d311d65e62be99` |
| **Feature flag** | `Feature_2146947386` — **the fix is CFR-gated** |
| **Exploitability** | Exploitation Less Likely; not publicly disclosed; not exploited (per MSRC) |

---

## Product Description

`UdfInitializeAllocations` parses **Allocation Descriptors** and initializes a
file's allocation (extent/run) information while mounting a UDF volume. It sums
the Allocation-Descriptor lengths and file-size information and converts them into
block/sector units by right-shifting by `Vcb->LBSizeShift` (`Vcb + 0x48`), using
the result as a 32-bit **VBN** (Virtual Block Number) / sector count.

---

## Vulnerability Summary

The accumulated Allocation-Descriptor length sum, and the file-size value, can
exceed the 32-bit range, but pre-patch the code did **not** upper-bound them before
consuming the shifted result as a **32-bit** value. When the value exceeds 32 bits
(even after shifting by `LBSizeShift`), the **upper bits are silently truncated**
(e.g. `mov edx, edx`), producing a VBN / sector count **smaller than the real
value**.

That truncated VBN flows into `FsRtlAddLargeMcbEntry` (the MCB run-list mapping) or
into a disk-I/O sector count, so the on-disk extent is mapped **smaller than it
actually is** and the backing pool buffer / bitmap is under-allocated. Later I/O
proceeds on the **original (untruncated)** size and writes past the end of the
under-sized kernel heap/pool buffer or bitmap — a **heap-based buffer overflow**
(CWE-197 → CWE-122).

---

## Prerequisites and Constraints

- Local, low-privileged (`PR:L`, `AV:L`, `AC:L`): auto-mount or open a crafted UDF
  image (`.iso`/`.img`/UDF VHD), or reach the write path.
- The image sets an Allocation-Descriptor length sum or file size whose
  block-converted value overflows 32 bits.
- Result: truncated VBN/sector count → under-allocated pool/bitmap → OOB write.

---

## Vulnerability Details

### Root Cause

A 64-bit byte length/size was converted to a block unit and stored/used as 32 bits
without first checking that the value fits, so the high bits were dropped and the
allocation was sized from the truncated (too-small) value while I/O used the real
size.

### The patch (confirmed — diff, .8521 → .8655)

Gated behind `Feature_2146947386`, upper-bound checks are added **before** the
truncation:

- Before `ScbMcb` initialization: if the file-size value (`Scb + 0x20`) exceeds
  `0xFFFFFFFF << LBSizeShift`, abort with `UdfRaiseStatusEx(0xC0000102 =
  STATUS_DISK_CORRUPT_ERROR)`.
- Immediately after accumulating the AD-length sum (`v5 += ad_len & 0x3FFFFFFF`):
  if the running total exceeds the same `0xFFFFFFFF << LBSizeShift` bound, abort
  likewise.

```c
// UdfInitializeAllocations (10.0.26100.8655) — PATCHED, feature-enabled branch (from our diff)
if ( (0xffffffffL << (Vcb->LBSizeShift & 0x3f)) < *(u64*)(Scb + 0x20) )
    UdfRaiseStatusEx(param_1, 0xC0000102, 0);   // STATUS_DISK_CORRUPT_ERROR
...
v5 += ad_len & 0x3fffffff;
if ( (0xffffffffL << (Vcb->LBSizeShift & 0x3f)) < v5 )
    UdfRaiseStatusEx(param_1, 0xC0000102, 0);
```

`0xFFFFFFFF << LBSizeShift` is the largest byte value that still yields a valid
32-bit VBN/sector count after the shift. The same guard was applied across **six
functions** on the mount, write and SetEOF paths.

### Patch Completeness Assessment

**CFR-gated behind `Feature_2146947386`.** The bound runs only when the flag is
enabled; the original truncating path still ships when disabled. Verify the flag is
enabled to confirm the fix is live. (Related same-KB UDFS fix: CVE-2026-40409 in
`UdfGetBlocksNeeded`, gated by `Feature_3105867064`.)

---

## Detection Guidance

**Behavioural.** Mounting/opening UDF images with Allocation-Descriptor length sums
or file sizes near/over the 32-bit block boundary; UDFS returning
`STATUS_DISK_CORRUPT_ERROR` for such images once the fix is active; kernel-pool
overflow crashes in `udfs!UdfInitializeAllocations` / MCB handling on
unpatched/flag-disabled builds.

**Config.** The fix is CFR-gated — confirm `Feature_2146947386` is enabled.

---

## References

- MSRC advisory — CVE-2026-40404 (Windows UDFS Elevation of Privilege), released 2026-06-09, KB5094126.
- Full binary diff: `/data/patch_diffs/udfs_sys-cve-2026-40404-40409-ghidriff.md`
