1. Overview

  • Unpatched Binary: cldflt_unpatched.sys
  • Patched Binary: cldflt_patched.sys
  • Similarity Score: 0.9884
  • Diff Statistics: 888 matched functions (879 identical, 9 changed). 0 unmatched functions in either binary.
  • Verdict: The security-relevant change is in HsmiOpUpdatePlaceholderFile (sub_1C006BC60 → sub_1C006A9B8). In the unpatched driver the check that rejects a negative file size / valid-data-length (*a9 < 0) is gated behind the staging feature g_Feature_2333116728_58628732; when that feature is disabled the rejection is skipped and a negative (interpreted as a very large unsigned) size flows into the placeholder size/metadata operations (FltSetInformationFile(FileEndOfFileInformation), HsmpSetFileVDL, HsmpUpdateBitmapSizesNoLock, and the placeholder size field at +0x98 of the context). The patch removes the feature gate entirely (the feature is absent from the patched binary) so the negative-size rejection is enforced unconditionally. The remaining changed functions are servicing-feature refactoring: the sync-root connect handler CldSyncConnectRoot and the service-command dispatcher CldiPortProcessServiceCommands drop a feature flag (Feature_Servicing_PostRelOutlookHangIssue_60816934) that selected between two already-equivalent code paths, and several functions only change the feature-evaluation call signature or relocate logging. Those are not security-relevant.

2. Vulnerability Summary

Finding 1: Negative File Size / Valid-Data-Length Rejection Made Unconditional in Placeholder Update

  • Severity: Low
  • Vulnerability Class: CWE-1284 (Improper Validation of Specified Quantity in Input) / CWE-20 (Improper Input Validation)
  • Affected Function: HsmiOpUpdatePlaceholderFile (sub_1C006BC60 → sub_1C006A9B8)
  • Root Cause: HsmiOpUpdatePlaceholderFile takes a pointer argument (a9) to a signed 64-bit file size / valid-data-length supplied by the caller. In the unpatched binary the guard that rejects a negative value is if (EvaluateCurrentState(&g_Feature_2333116728_58628732_FeatureDescriptorDetails) && a9 != nullptr && *a9 < 0) — the rejection only runs when the staging feature g_Feature_2333116728_58628732 is enabled. When that feature is disabled, EvaluateCurrentState returns FALSE, the guard is skipped, and a negative *a9 proceeds. Downstream the same pointer (v45 = a9) is consumed as a size: FltSetInformationFile(..., a9, 8, FileEndOfFileInformation), HsmpUpdateBitmapSizesNoLock(a2, *a9), a store into the placeholder context (**(a2 + 0x98) = *a9), and HsmpSetFileVDL(..., FileObject, *a9). A negative signed value is a very large unsigned quantity when used as a length. The patch removes the feature gate; the patched guard is simply if (a9 != nullptr && *a9 < 0), so the negative-size rejection (STATUS 0xC000CF0B) is always performed. The feature symbol g_Feature_2333116728_58628732 is entirely absent from the patched binary.
  • Direction: The patched build is the stricter one. The unpatched build could skip the rejection (feature off); the patched build always rejects. This is a delivered input-validation hardening, not a relaxation.
  • Attacker-Reachable Entry Point: Cloud Files placeholder-update operation. HsmiOpUpdatePlaceholderFile is called by HsmFltProcessUpdatePlaceholder, which parses the size/length fields out of a caller-supplied buffer (v11 + 0x3C/0x40/0x44/0x48 offsets) before passing them down, and by HsmRecallUpdatePlaceholderFile.
  • Impact: No memory-corruption primitive is demonstrated. The rejected value is a file size / valid-data-length that feeds FltSetInformationFile(FileEndOfFileInformation) and HsmpSetFileVDL; the underlying file-system layer performs its own validation of these values. The demonstrable difference is that a caller-supplied negative size is consistently rejected only after the patch. Severity is Low.

Finding 2: Feature-Flag-Gated Divergence in Sync-Root Context Entry Reuse — No Security Impact

  • Severity: None (informational)
  • Vulnerability Class: Not applicable — no CWE condition present. (Considered CWE-416 / CWE-672; neither is reachable because both builds gate reuse on refcount.)
  • Affected Function: CldSyncConnectRoot (sub_1C0033950 → sub_1C0032880)
  • Root Cause: In the unpatched binary, CldSyncConnectRoot looks up an existing sync-root context entry in an AVL tree (RtlLookupElementGenericTableAvl on a1+0x10). A feature flag (EvaluateCurrentState(&reg_FeatureDescriptors_a), which resolves to Feature_Servicing_PostRelOutlookHangIssue_60816934) selects between two branches. When the flag returns TRUE (retained path) the function first treats an entry whose connected-object id (+0x60) is 0 as a free slot and recreates it, then on an identity match requires refcount (+0x30) > 0 before returning the entry. When the flag returns FALSE (legacy path) the function instead uses refcount (+0x30) > 0 as the first gate before the identity match and lacks the connectedId == 0 recovery, so a live entry with a zero connected id yields STATUS 0xC000CF09 instead of being recreated. Both branches require refcount > 0 before handing an existing entry back to the caller, so an entry with an exhausted refcount is never returned in either binary. The patch removes the flag and always takes the TRUE-branch logic. Because the two paths are equivalent with respect to the refcount gate, there is no use-after-free and no security-relevant difference; the only behavioral difference is error-vs-recreate for a disconnected slot.
  • Attacker-Reachable Entry Point: Cloud Files communication-port service command (the user-mode sync provider's CfConnectSyncRoot-style message), delivered to the registered FLT_MESSAGE_NOTIFY callback, not an IRP_MJ_SET_REPARSE_POINT file-system operation.
  • Call Chain:
  • CldHsmInitialize (sub_1C0075010) — driver init, calls CldPortInitialize.
  • CldPortInitialize (sub_1C00320F8) — registers CldiPortNotifyMessage as the port FLT_MESSAGE_NOTIFY callback.
  • CldiPortNotifyMessage (sub_1C002F5B0) — runtime port-message callback (attacker-reachable entry).
  • CldiPortProcessServiceCommands (sub_1C002A7E8) — service-command dispatch.
  • CldSyncConnectRoot (sub_1C0033950) — AVL sync-root entry lookup/create with feature-flag path divergence.

Finding 3: Feature-Flag-Gated Sync-Root Insert Method Divergence — No Security Impact

  • Severity: None (informational)
  • Vulnerability Class: Not applicable — no CWE condition present. (Considered CWE-668 / state inconsistency; both flag paths insert the entry, so there is no tracking bypass.)
  • Affected Function: CldiPortProcessServiceCommands (sub_1C002A7E8 → sub_1C00297E4)
  • Root Cause: After a successful connect, the unpatched binary uses the same Feature_Servicing_PostRelOutlookHangIssue_60816934 flag (EvaluateCurrentState(&reg_FeatureDescriptors_a)) to select how the sync root is inserted into the tracking AVL table. When the flag is TRUE it calls the helper CldiPortInsertSyncRootNoLock (sub_1C002A6C8); when FALSE it performs an inline RtlInsertElementGenericTableAvl on a1+0x60. Both paths insert the entry; they differ in method and in the extra bookkeeping the helper performs. The patch removes the flag and always uses CldiPortInsertSyncRootNoLock. Both paths insert, so there is no tracking bypass and no security-relevant difference.
  • Call Chain: Follows the same dispatch path as Finding 2, terminating at CldiPortProcessServiceCommands (sub_1C002A7E8).

3. Pseudocode Diff

Finding 1 — HsmiOpUpdatePlaceholderFile

// --- UNPATCHED: negative-size rejection gated behind the staging feature ---
if (EvaluateCurrentState(&g_Feature_2333116728_58628732_FeatureDescriptorDetails)
    && a9 != nullptr
    && *a9 < 0)
{
    SyncPolicy = 0xC000CF0B;      // reject negative size
    ...
}
// feature OFF -> guard skipped -> negative *a9 continues to the size operations below

// --- PATCHED: rejection is unconditional (feature gate removed) ---
if (a9 != nullptr && *a9 < 0)
{
    SyncPolicy = 0xC000CF0B;      // always reject negative size
    ...
}

// Downstream use of *a9 (v45 = a9) in both builds:
//   FltSetInformationFile(..., v45, 8, FileEndOfFileInformation);
//   if (*v45 != old) HsmpUpdateBitmapSizesNoLock(a2, *v45);
//   **(a2 + 0x98) = *v45;                       // placeholder size field
//   HsmpSetFileVDL(..., FileObject, *v45);       // valid-data-length

Finding 2 — CldSyncConnectRoot (no security difference)

// --- UNPATCHED: legacy branch (flag == FALSE) ---
if (!EvaluateCurrentState(&reg_FeatureDescriptors_a)) {
    if (*(int *)(entry + 0x30) <= 0)   // refcount gate FIRST
        goto create_new_entry;
    if (*(entry + 0x60) == arg2 && *entry == arg7)   // identity match
        *arg8 = entry;                  // reuse (refcount already gated > 0)
    else
        status = 0xC000CF09;
    goto done;
}

// --- UNPATCHED flag == TRUE branch  ==  PATCHED unified path (sub_1C0032880) ---
if (*(entry + 0x60) == 0)               // stale/disconnected slot
    goto create_new_entry;              // recreate (missing in legacy branch)
if (*(entry + 0x60) == arg2 && *entry == arg7) {
    if (*(int *)(entry + 0x30) <= 0)    // refcount check before reuse
        goto create_new_entry;
    *arg8 = entry;                      // reuse
} else {
    status = 0xC000CF09;
}

Both branches require refcount (+0x30) > 0 before returning an existing entry, so neither binary returns a refcount-exhausted entry.

4. Assembly Analysis

Finding 1 — HsmiOpUpdatePlaceholderFile

Unpatched (sub_1C006BC60), rejection gated behind the feature (at 0x1C006BD31):

00000001C006BD31  lea     rcx, g_Feature_2333116728_58628732_FeatureDescriptorDetails
00000001C006BD4A  call    EvaluateCurrentState
00000001C006BD4F  test    eax, eax
00000001C006BD51  jz      loc_1C006BDE5           ; feature OFF -> skip rejection
00000001C006BD57  test    r12, r12                ; a9 != NULL ?
00000001C006BD5A  jz      loc_1C006BDE5
00000001C006BD60  cmp     [r12], r14              ; *a9 vs 0  (r14 = 0)
00000001C006BD64  jge     short loc_1C006BDE5     ; *a9 >= 0 -> skip
00000001C006BD66  mov     r15d, 0C000CF0Bh        ; reject: STATUS 0xC000CF0B

Patched (sub_1C006A9B8), rejection unconditional (at 0x1C006AA9E):

00000001C006AA9E  test    rdi, rdi                ; a9 != NULL ?
00000001C006AAA7  cmp     [rdi], r15              ; *a9 vs 0  (r15 = 0)
00000001C006AAAA  jge     short loc_1C006AB2B     ; *a9 >= 0 -> skip
00000001C006AAAC  mov     r14d, 0C000CF0Bh        ; reject: STATUS 0xC000CF0B

There is no EvaluateCurrentState call and no reference to g_Feature_2333116728_58628732 before the check in the patched function; the feature symbol does not appear anywhere in the patched binary.

Finding 2 — CldSyncConnectRoot (both branches gate refcount)

Unpatched legacy branch (sub_1C0033950, flag == FALSE, at 0x1C0033A79):

00000001C0033A79  mov     eax, [rsi+30h]          ; load refcount (offset 0x30)
00000001C0033A7C  test    eax, eax
00000001C0033A7E  jle     loc_1C0033B05           ; refcount <= 0 -> create new entry
00000001C0033A88  mov     rax, [rsi+60h]          ; load connectedId (offset 0x60)
00000001C0033A8C  cmp     rax, rbx                ; compare with arg2
00000001C0033A8F  jnz     short loc_1C0033AAB     ; mismatch -> STATUS 0xC000CF09

Unpatched retained branch (sub_1C0033950, flag == TRUE, at 0x1C00339CB):

00000001C00339CB  mov     rax, [rsi+60h]          ; connectedId
00000001C00339CF  test    rax, rax
00000001C00339D2  jz      loc_1C0033B05           ; connectedId == 0 -> create new entry
00000001C00339DC  cmp     rax, rbx                ; compare with arg2
00000001C00339DF  jnz     short loc_1C0033A07     ; mismatch -> error
00000001C00339E5  cmp     [rax], r15              ; object-pointer match
00000001C00339E8  jnz     short loc_1C0033A07
00000001C00339EA  mov     eax, [rax+30h]          ; refcount check
00000001C00339ED  test    eax, eax
00000001C00339EF  jle     loc_1C0033B05           ; refcount <= 0 -> create new entry

Create-new path (present in both binaries), initializing a fresh entry (unpatched 0x1C0033B5C):

mov     eax, [rbp+arg_28]
mov     [r8+60h], rbx           ; store connectedId (arg2)
mov     [r8+2Ch], eax
mov     rax, [rbp+arg_38]
mov     [r8], r15               ; store object pointer (arg7)
mov     dword ptr [r8+30h], 1   ; refcount = 1
mov     [rax], r8

5. Trigger Conditions

Finding 1 (the delivered fix)

  1. Ensure the target volume is attached to the Cloud Files filter (cldflt.sys), typically via OneDrive or Files On-Demand.
  2. Have the registered user-mode sync provider issue a placeholder-update operation whose size / valid-data-length field is negative (a signed 64-bit value with the sign bit set), reaching HsmFltProcessUpdatePlaceholder and then HsmiOpUpdatePlaceholderFile.
  3. In the unpatched driver, if the staging feature g_Feature_2333116728_58628732 is disabled, the *a9 < 0 rejection is skipped and the negative size proceeds to FltSetInformationFile(FileEndOfFileInformation) / HsmpSetFileVDL. In the patched driver the negative size is rejected with STATUS 0xC000CF0B unconditionally.

Finding 2 (no security-relevant behavior)

To exercise the divergent legacy path in the unpatched driver: 1. Ensure the target volume is attached to the Cloud Files filter. 2. Have a user-mode component acting as a cloud sync provider send a connect-sync-root service command over the filter communication port, reaching CldiPortProcessServiceCommands (sub_1C002A7E8) and then CldSyncConnectRoot (sub_1C0033950). 3. Arrange for an existing AVL sync-root entry to be present so RtlLookupElementGenericTableAvl returns a match. 4. With the feature flag in the legacy (FALSE) state, an entry whose connected id (+0x60) is 0 returns STATUS 0xC000CF09 instead of being recreated as in the patched path. 5. Both paths still require refcount (+0x30) > 0 before returning an existing entry, so no stale/refcount-exhausted entry is returned in either binary.

6. Exploit Primitive & Development Notes

  • Finding 1 primitive: No memory-corruption primitive is demonstrated. The change consistently rejects a caller-supplied negative file size / valid-data-length that would otherwise reach FltSetInformationFile(FileEndOfFileInformation) and HsmpSetFileVDL. Any follow-on impact (for example, exposing uninitialized data by extending valid-data-length) would depend on the file-system layer's own handling of the value and is not demonstrated here.
  • Finding 2 primitive: No memory-safety primitive is confirmed. Both the legacy and unified paths gate reuse on refcount > 0, so a released entry is not returned to the caller. The observable difference is a control-flow divergence (error vs recreate) for a disconnected AVL slot.

7. Debugger PoC Playbook

Finding 1 — HsmiOpUpdatePlaceholderFile (unpatched)

bp cldflt_unpatched!HsmiOpUpdatePlaceholderFile                 ; sub_1C006BC60
bp 0x1c006bd4a "printf \"Feature Eval\\n\"; g"                  ; g_Feature_2333116728_58628732 gate
bp 0x1c006bd60 "printf \"*a9 = %I64x\\n\", poi(@r12); g"        ; negative-size check operand
  • At 0x1C006BD4A: EvaluateCurrentState return in EAX. 0 (FALSE, feature off) takes the jz at 0x1C006BD51 and skips the negative-size rejection entirely.
  • At 0x1C006BD60: [r12] is *a9; the jge at 0x1C006BD64 skips the rejection when *a9 >= 0. In the patched build (0x1C006AA9E) the equivalent check runs with no preceding feature test.

Finding 2 — CldSyncConnectRoot (unpatched)

bp cldflt_unpatched!CldSyncConnectRoot                     ; sub_1C0033950
bp 0x1c00339be "printf \"Feature Flag Eval\\n\"; g"        ; EvaluateCurrentState call
bp 0x1c0033a79 "printf \"Legacy branch refcount: %x\\n\", poi(@rsi+30); g"
  • At 0x1C00339BE: EvaluateCurrentState return in EAX. 0 (FALSE) selects the legacy branch (loc_1C0033A79); non-zero selects the retained branch.
  • At 0x1C0033A79 (legacy branch): dword ptr [rsi+30h] is the refcount; the jle at 0x1C0033A7E diverts to the create-new path when it is <= 0. The entry is returned only when refcount > 0.
  • Expected observation: In the legacy branch, an entry with refcount <= 0 diverts to create-new (loc_1C0033B05); an entry with refcount > 0 and connected id 0 returns STATUS 0xC000CF09. No freed entry is handed back. The patched path recreates the slot instead of erroring.

8. Changed Functions — Full Triage

Function Similarity Change Type Security Note
HsmiOpUpdatePlaceholderFile (sub_1C006BC60)(sub_1C006A9B8) 0.8861 Security Relevant Removed the g_Feature_2333116728_58628732 gate around the *a9 < 0 negative file-size / valid-data-length rejection (STATUS 0xC000CF0B), making it unconditional in the patched build. The value feeds FltSetInformationFile(FileEndOfFileInformation), HsmpSetFileVDL, and the placeholder size field. Delivered input-validation hardening (CWE-1284).
CldSyncConnectRoot (sub_1C0033950)(sub_1C0032880) 0.8192 No security impact Removed the Feature_Servicing_PostRelOutlookHangIssue_60816934 flag divergence in sync-root entry reuse; unified to the branch that recreates a disconnected slot and gates reuse on refcount. Both branches already gated refcount > 0, so no use-after-free difference.
CldiPortProcessServiceCommands (sub_1C002A7E8)(sub_1C00297E4) 0.9691 No security impact Removed the flag selecting the insert method; patched always uses CldiPortInsertSyncRootNoLock. Both flag paths already inserted the entry, so no tracking bypass.
EvaluateCurrentState (sub_1C0001D74) 0.6686 Behavioral Feature-evaluation helper specialized: unpatched takes a feature-descriptor pointer arg; patched at this address resolves Feature_Servicing_PostRelOutlookHangIssue_60816934 directly (no argument). Signature change only.
HsmiOpDehydrateNotificationCallback (sub_1C006ADB0)(sub_1C0069B10) 0.9918 Behavioral EvaluateCurrentState call-signature change and memset wrapper relocation (sub_1C0018440sub_1C0018400). The PostRelOutlookHangIssue gate around the range check is retained (still evaluated) in both builds.
CldiPortProcessTransfer (sub_1C002E5E0)(sub_1C002D508) 0.9929 Behavioral Feature-evaluation call-signature change and logging relocation.
CldiPortInsertSyncRootNoLock (sub_1C002A6C8)(sub_1C00296C8) 0.9019 Behavioral Removed a HsmLogSystemEvent (sub_1C000D524) call from an error path (present at 0x1C002A775 in unpatched); global/address relocations. Now the sole insert path used by Finding 3.
HsmiGrantLockRequest (sub_1C005DC10)(sub_1C005C990) 0.9590 Cosmetic HsmDbgBreakOnStatus relocation (sub_1C0006820sub_1C0006830) and address shifts.
CldSyncSendHydrationRequest (sub_1C00352F0)(sub_1C003406C) 0.9927 Cosmetic HsmDbgBreakOnStatus relocation and address shifts.

9. Unmatched Functions

There were no added or removed functions. The patch is a pure binary diff altering logic in existing functions.

10. Confidence & Caveats

  • Confidence: High on the mechanisms.
  • Finding 1: The g_Feature_2333116728_58628732 gate around the *a9 < 0 rejection is removed in the patched build (the feature symbol is absent from the patched binary), and the negative-size rejection is enforced unconditionally. The patched build is stricter. No memory-corruption primitive is demonstrated; the rejected quantity is a file size / valid-data-length that the file-system layer further validates, hence Low severity. Whether the unpatched behavior was reachable in the field depends on the runtime state of the staging feature, which is governed by feature configuration and is not determinable from the binary.
  • Findings 2 and 3: The Feature_Servicing_PostRelOutlookHangIssue_60816934 flag removals in CldSyncConnectRoot and CldiPortProcessServiceCommands unify two already-equivalent code paths (both gate refcount before reuse; both insert the entry). No memory-safety difference exists between the two branches in either function.
  • Note on the feature: Feature_Servicing_PostRelOutlookHangIssue_60816934 is still evaluated in the patched binary (for example in HsmiOpDehydrateNotificationCallback and a second guard inside HsmiOpUpdatePlaceholderFile); only its evaluation call signature changed and, in CldSyncConnectRoot / CldiPortProcessServiceCommands, its branch was collapsed to a single equivalent path.