# cldflt.sys Patch Diff — CVE-2025-50170

| | |
|---|---|
| Binary | cldflt.sys (Windows Cloud Files Mini Filter Driver) |
| Pre-patch version | 10.0.26100.4484 |
| Post-patch version | 10.0.26100.4946 |
| KB | KB5063878 |
| CVE | CVE-2025-50170 — Improper Handling of Insufficient Permissions or Privileges (CWE-280), Elevation of Privilege, CVSS 7.8 |
| Diff tool | ghidriff (Ghidra VersionTrackingDiff engine) |
| Functions changed | 1 with security-relevant code changes (out of 2,836 total, 99.9% avg similarity) |
| Functions added | 2 (WIL Controlled-Feature-Rollout accessors for `Feature_2594491707`) |
| Independent analysis | [STAR Labs SG — CVE-2025-50170](https://starlabs.sg/advisories/25/25-50170/) by Chen Le Qi |

## Summary

The fix closes an **arbitrary file corruption** vulnerability in
`HsmpOpCreatePlaceholders` that allows an unprivileged local attacker to
overwrite the contents of arbitrary files — including system binaries and
loaded DLLs — achieving code execution as SYSTEM.

The root cause is an `IoReadAccess` / write mismatch: the function accepts
a usermode pointer, creates an MDL (Memory Descriptor List) from it, and
probes/locks the pages with `IoReadAccess` (value `0`), signalling that
the kernel will only *read* the buffer. However, the function subsequently
*writes* to the locked pages in multiple places — specifically
`FILE_BASIC_INFORMATION` data at offset `+0x10` and an error status at
offset `+0x40`.

Because the MDL was locked with `IoReadAccess`, the kernel bypasses the
page-table write-protection check. An attacker can map a read-only view of
a victim file (e.g. a system binary) to the usermode address and pass it
to the kernel, causing the kernel to write directly to the file's physical
pages — corrupting the file without having write permission.

The fix, gated on `Feature_2594491707`, changes the `MmProbeAndLockPages`
call from `IoReadAccess` (0) to `IoWriteAccess` (1), so the memory
manager now verifies the pages are writable before locking them. Passing a
read-only file mapping will cause `MmProbeAndLockPages` to raise
`STATUS_ACCESS_VIOLATION`.

**Confidence:** high. The ghidriff output shows exactly the change
described in STAR Labs' independent advisory — `MmProbeAndLockPages`
access mode upgraded from `IoReadAccess` to `IoWriteAccess` via the
feature flag, one-to-one with the documented root cause.

**Credit.** MSRC credits
[Chen Le Qi (@cplearns2h4ck)](https://x.com/cplearns2h4ck) of STAR Labs
SG Pte. Ltd.

## Product background

`cldflt.sys` is a filesystem minifilter driver that acts as a proxy between
user applications and cloud sync engines (e.g. OneDrive). It supports
on-demand downloading and uploading of data, presenting cloud-backed files
as locally available. Users can create placeholder files under syncroot
directories via the `cldapi.dll!CfCreatePlaceholders()` usermode API,
which internally dispatches to `cldflt.sys!HsmpOpCreatePlaceholders()` in
the kernel.

## Function changed

### HsmpOpCreatePlaceholders (the MDL IoReadAccess bug)

| | |
|---|---|
| Change type | code, length, sig, called |
| Similarity | 0.82 (b_ratio) |
| Fix pattern | MmProbeAndLockPages access mode changed from IoReadAccess to IoWriteAccess via CFR flag |

The function receives a usermode pointer and length, allocates an MDL,
and probes/locks the pages:

Before (pre-patch — vulnerable):

```c
// cldflt.sys 10.0.26100.4484 — VULNERABLE
lVar10 = IoAllocateMdl(param_4, param_5, 0, 0);
ProbeForRead(param_4, param_5);
MmProbeAndLockPages(lVar10, 1);   // 3rd param absent → IoReadAccess (0)
if ((*(byte *)(lVar10 + 10) & 5) == 0) {
    local_1c0 = (uint *)MmMapLockedPagesSpecifyCache(lVar10, 0, 1, 0);
} else {
    local_1c0 = *(uint **)(lVar10 + 0x18);
}
```

The `MmProbeAndLockPages` call uses `IoReadAccess` (the third parameter
is 0, elided by the decompiler). This tells the memory manager the kernel
will only read the buffer, so it does not verify that the virtual pages
are writable. But the function then **writes** to the mapped address:

```c
// Write FILE_BASIC_INFORMATION at curEntry + 0x10
status_ = FltQueryInformationFile(Instance, FileObject, &v72, 0x28u,
                                   FileBasicInformation, 0);
if (status_ >= 0) {
    *(curEntry_ + 0x10) = v72;   // <-- WRITE to "read-only" buffer
}

// Write error status at curEntry + 0x40
*(curEntry_ + 0x40) = status_;   // <-- WRITE to "read-only" buffer
```

After (post-patch — fixed):

```c
// cldflt.sys 10.0.26100.4946 — FIXED
lVar9 = IoAllocateMdl(param_4, param_5, 0, 0);
ProbeForRead(param_4, param_5, 4);
uVar10 = Feature_2594491707__private_IsEnabledDeviceUsageNoInline();
MmProbeAndLockPages(lVar9, 1, (int)uVar10 != 0);
                                  // ^^ When flag enabled: IoWriteAccess (1)
                                  //    When flag disabled: IoReadAccess (0) — kill-switch fallback
if ((*(byte *)(lVar9 + 10) & 5) == 0) {
    local_1c0 = (uint *)MmMapLockedPagesSpecifyCache(lVar9, 0, 1, 0);
} else {
    local_1c0 = *(uint **)(lVar9 + 0x18);
}
```

When `Feature_2594491707` is enabled (production path):
- `uVar10 != 0` evaluates to `1` = `IoWriteAccess`
- `MmProbeAndLockPages` now verifies the pages are writable
- Passing a read-only file mapping causes `STATUS_ACCESS_VIOLATION`
- The side channel is closed: the kernel refuses to lock read-only pages
  for a write operation

### New functions (feature-flag plumbing)

`Feature_2594491707__private_IsEnabledDeviceUsageNoInline`,
`Feature_2594491707__private_IsEnabledFallback` — WIL CFR accessors for
the IoReadAccess fix in `HsmpOpCreatePlaceholders`.

## Exploitation (from STAR Labs advisory)

STAR Labs' [advisory](https://starlabs.sg/advisories/25/25-50170/)
documents the full exploitation technique:

### The primitive

`CfCreatePlaceholders()` dispatches to `HsmpOpCreatePlaceholders()` in
the kernel. The function accepts a usermode pointer to a
`CF_PLACEHOLDER_CREATE_INFO` array, creates an MDL from it, and maps
it into system space. Because the MDL is locked with `IoReadAccess`,
the kernel can write to read-only pages that back the mapping.

### Memory layout spray

The attacker maps a writable page contiguous in virtual memory with a
read-only view of the victim file:

```c
for (DWORD counter = 1; ; counter++) {
    attackerView = MapViewOfFile(hAttackerMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
    victimView   = MapViewOfFile(hVictimMap,   FILE_MAP_READ,       0, 0, 0);
    if (attackerView + 0x10000 == victimView)
        break;
}
```

By mapping a `0x10000`-byte attacker-controlled region immediately before
the victim read-only file, the attacker passes `victimView - 0x40` as the
usermode pointer. The first `0x40` bytes (including the `0x10` bytes
checked by internal validation) fall within the writable region, while the
kernel write at `+0x40` lands precisely at the start of the victim file.

### Impact

The attacker can corrupt arbitrary files including:

- **System binaries** executed as SYSTEM (e.g. shell scripts containing
  `cmd.exe /c ...` paths redirected to attacker-controlled directories)
- **In-memory DLLs/EXEs** — because all copies of a loaded DLL across
  different processes share the same physical pages, this bug can corrupt
  running code *without leaving traces on disk*, enabling forensically
  invisible backdoors or killing security processes

---

<sub>Source: ghidriff diff of cldflt-2025-07.sys (10.0.26100.4484,
pre-patch) vs cldflt-2025-08.sys (10.0.26100.4946, post-patch) —
[download pre](/data/patch_diffs/binaries/cldflt-2025-07.sys) /
[download post](/data/patch_diffs/binaries/cldflt-2025-08.sys). Independent
analysis: [Chen Le Qi / STAR Labs SG — CVE-2025-50170](https://starlabs.sg/advisories/25/25-50170/).</sub>
