1. Overview

  • Unpatched Binary: mrxsmb10_unpatched.sys
  • Patched Binary: mrxsmb10_patched.sys
  • Common (matched) functions: 592. Of these, 588 are byte/semantics-identical and 4 changed.
  • Removed in patched: 21 functions, all Windows Implementation Library (WIL) feature-staging / usage-reporting helpers (Feature_84197691__*, Feature_Servicing_EnableSMBHardeningTelemetry__*, wil_details_*, wil_QueryFeatureState, wil_RtlStagingConfig_QueryFeatureState). No functions were added.
  • Verdict: No security-relevant change. The diff is a feature-staging rollout. In MRxSmbHandOverSrvCall a WIL feature gate (Feature_84197691__private_IsEnabledDeviceUsage) that selected between two code paths is removed, so the server-transport reference/validation path (SmbCepReferenceServerTransport) is now taken unconditionally. Both the gated and ungated paths store the same transport pointer into the SrvCall object and pass that same pointer to SmbCeUpdateTransportDispatchVectors; there is no type confusion and no pointer-indirection difference. The three other changed functions differ only by removal of a telemetry feature gate before ETW logging.

2. Change Summary

Finding 1: WIL feature gate removed in MRxSmbHandOverSrvCall (no security impact)

  • Severity: None (informational)
  • Class: Feature-staging rollout / defense-in-depth hardening. No demonstrable reachable primitive; no CWE assigned.
  • Affected Function: MRxSmbHandOverSrvCall (unpatched @ 0x1C000FFD0, patched @ 0x1C000EFE0)

What actually changed: The unpatched function branches on a WIL feature flag, Feature_84197691__private_IsEnabledDeviceUsage (checked at 0x1C001002F and again at 0x1C00102EC). It is not an "SMB2 availability check." Depending on the flag:

  • Feature enabled: SmbCepReferenceServerTransport(&arg5_slot, &out) is called (0x1C0010044). That routine reads the transport pointer P from the argument slot, validates it (P != NULL and the state field [P+0x0C] == 0, else returns 0xC000020C), takes a temporary reference (lock xadd [P+8], 1), and returns P in out. P is then stored into the SrvCall object at +0x140.
  • Feature disabled: the same transport pointer P is loaded directly from the argument slot (0x1C0010067: mov r15, [rbp+1B0h+arg_20]) without validation and without taking a temporary reference, then stored into SrvCall +0x140.

In both paths the value written to SrvCall +0x140 and later passed to SmbCeUpdateTransportDispatchVectors is the same pointer P (the server-transport object). SmbCepReferenceServerTransport returns the value of the argument slot, which is identical to what the feature-disabled path loads directly. There is no arg5-vs-*arg5 indirection difference and no type confusion.

The temporary reference taken on the enabled path is released within the same function by SmbCepDereferenceServerTransport (0x1C0010184), so it is net-zero across the call; it does not add a persistent reference held by the SrvCall. Consequently there is no reference-count imbalance at SrvCall finalization.

The patch removes the feature gate entirely and always calls SmbCepReferenceServerTransport (patched 0x1C000F04C) and always calls the matching SmbCepDereferenceServerTransport (patched 0x1C000F16B). The net effect is that the transport validation (non-null and not-torn-down) and the temporary reference over the handover window are now always performed instead of being feature-gated. This is a hardening improvement (it rejects a torn-down transport and guards against a concurrent free during the handover window), but no reachable trigger for such a condition is demonstrated, and the stored/used pointer is unchanged.

3. Pseudocode Comparison

// --- UNPATCHED (MRxSmbHandOverSrvCall @ 0x1C000FFD0) ---
if (Feature_84197691__private_IsEnabledDeviceUsage())   // WIL feature flag
{
    // validated path: P = *arg5_slot, check P!=NULL && P->state==0, refcount++
    status = SmbCepReferenceServerTransport(&arg5_slot, &transport);  // transport == P
    arg5_slot = 0;
    if (transport == NULL) { status = 0xC000020C; goto cleanup; }
    P = transport;
}
else
{
    P = arg5_slot;   // same pointer value P, no validation, no refcount
}

// ... common SrvCall setup ...

if (Feature_84197691__private_IsEnabledDeviceUsage())
    SrvCall->TransportDispatch = transport;   // == P
else
    SrvCall->TransportDispatch = P;           // == P (identical value)

if (SrvCall->TransportDispatch)
    SmbCeUpdateTransportDispatchVectors(SrvCall->TransportDispatch, &MRxSmbVctConnectionEventHandler);

cleanup:
if (Feature_84197691__private_IsEnabledDeviceUsage() && transport)
    SmbCepDereferenceServerTransport(&transport);   // releases the temporary ref

// --- PATCHED (MRxSmbHandOverSrvCall @ 0x1C000EFE0) ---
// feature gate removed; validated path is unconditional
status = SmbCepReferenceServerTransport(&arg5_slot, &transport);  // transport == P
arg5_slot = 0;
if (transport == NULL) { status = 0xC000020C; goto cleanup; }

// ... common SrvCall setup ...

SrvCall->TransportDispatch = transport;   // == P
SmbCeUpdateTransportDispatchVectors(transport, &MRxSmbVctConnectionEventHandler);

cleanup:
SmbCepDereferenceServerTransport(&transport);   // always

4. Assembly Analysis

Unpatched path (MRxSmbHandOverSrvCall @ 0x1C000FFD0)

; WIL feature gate (not an SMB2 check)
00000001C001002F  call    Feature_84197691__private_IsEnabledDeviceUsage
00000001C0010034  test    eax, eax
00000001C0010036  jz      loc_1C0010067          ; feature disabled -> raw-pointer path

; feature enabled: validated + reference-counted path
00000001C0010038  lea     rdx, [rsp+2B0h+var_260]
00000001C001003D  lea     rcx, [rbp+1B0h+arg_20] ; &arg5_slot
00000001C0010044  call    SmbCepReferenceServerTransport
00000001C0010049  mov     rsi, [rsp+2B0h+var_260]; rsi = P (value of arg5_slot)
00000001C001004E  mov     r15d, edi              ; r15 = 0

; feature disabled: same pointer P, loaded directly, unvalidated
00000001C0010067  mov     r15, [rbp+1B0h+arg_20] ; r15 = P (value of arg5_slot)

; store into SrvCall+0x140 (second feature check selects register, same value)
00000001C00102EC  call    Feature_84197691__private_IsEnabledDeviceUsage
00000001C00102F1  test    eax, eax
00000001C00102F3  jz      short loc_1C00102FE
00000001C00102F5  mov     [rbx+140h], rsi        ; enabled path stores P (rsi)
00000001C00102FC  jmp     short loc_1C0010305
00000001C00102FE  mov     [rbx+140h], r15        ; disabled path stores P (r15) - same value

; read back and use
00000001C0010305  mov     rcx, [rbx+140h]        ; rcx = P
00000001C001030C  test    rcx, rcx
00000001C001030F  jz      short loc_1C0010324
00000001C0010311  lea     rdx, MRxSmbVctConnectionEventHandler
00000001C0010318  call    cs:__imp_SmbCeUpdateTransportDispatchVectors ; called with P

; cleanup: dereference only on the feature-enabled path (releases the temp ref)
00000001C0010171  call    Feature_84197691__private_IsEnabledDeviceUsage
00000001C0010176  test    eax, eax
00000001C0010178  jz      short loc_1C0010189    ; disabled -> nothing to release (none taken)
00000001C001017A  test    rsi, rsi
00000001C001017D  jz      short loc_1C0010189
00000001C001017F  lea     rcx, [rsp+2B0h+var_260]
00000001C0010184  call    SmbCepDereferenceServerTransport

Patched path (MRxSmbHandOverSrvCall @ 0x1C000EFE0)

; no feature gate: validated + reference-counted path always taken
00000001C000F027  lea     rdx, [rsp+2B0h+var_260]
00000001C000F02C  lea     rcx, [rbp+1B0h+arg_20]
00000001C000F04C  call    SmbCepReferenceServerTransport
00000001C000F051  mov     r12, [rsp+2B0h+var_260]; r12 = P
00000001C000F05D  test    r12, r12
00000001C000F060  jnz     short loc_1C000F06C    ; NULL -> 0xC000020C error
...
00000001C000F2C5  lea     rdx, MRxSmbVctConnectionEventHandler
00000001C000F2CC  mov     rcx, r12               ; P
00000001C000F2DC  mov     [rbx+140h], r12        ; store P (unconditional)
00000001C000F2E3  call    cs:__imp_SmbCeUpdateTransportDispatchVectors ; called with P
...
00000001C000F166  lea     rcx, [rsp+2B0h+var_260]
00000001C000F16B  call    SmbCepDereferenceServerTransport   ; always

5. Trigger / Path Conditions

MRxSmbHandOverSrvCall is reached during SMB server-call handover when a client (via NtCreateFile / WNetAddConnection2 on \\server\share) establishes a connection through the RDBSS minirdr dispatch. Which of the two unpatched paths runs is decided solely by the runtime state of the WIL feature flag Feature_84197691__private_IsEnabledDeviceUsage, not by any attacker input or SMB2 registration state. In both paths the same transport pointer is stored and used, so reaching either path does not produce a different observable memory operation on the stored pointer. No attacker-controlled condition selects a distinct, corruptible pointer.

6. Impact Assessment

  • No memory-corruption primitive. The pointer stored at SrvCall +0x140 and passed to SmbCeUpdateTransportDispatchVectors is the same server-transport object pointer in both builds and both feature paths. SmbCeUpdateTransportDispatchVectors receives a valid transport object, not a mis-typed structure.
  • No reference-count imbalance / use-after-free at finalization. The temporary reference taken by SmbCepReferenceServerTransport is released by SmbCepDereferenceServerTransport within the same function, so it is net-zero and no persistent reference is added to (or missing from) the SrvCall in either build.
  • Hardening only. The delivered change makes the transport validation (reject NULL / torn-down transport) and the short-lived reference over the handover window unconditional instead of feature-gated. This narrows a potential window in which a concurrently torn-down transport could be touched, but no reachable trigger for such a race is demonstrated, so no severity is assigned.

7. Debugging Notes

The following are real instruction addresses (relative to the default image base 0x1C0000000) useful to observe the two unpatched code paths. They confirm behavior; they are not a vulnerability trigger.

  • mrxsmb10+0xFFD0MRxSmbHandOverSrvCall entry. rcx=arg1 (server-entry context), rdx=arg2, r8=arg3, r9=arg4 (SrvCall output), [rsp+0x28]=arg5 (server-transport pointer slot).
  • mrxsmb10+0x1002Fcall Feature_84197691__private_IsEnabledDeviceUsage. eax==0 selects the direct-load path, eax!=0 selects the SmbCepReferenceServerTransport path.
  • mrxsmb10+0x10067mov r15, [rbp+0x1E0]: loads the transport pointer P from the arg5 slot on the feature-disabled path.
  • mrxsmb10+0x102FEmov [rbx+0x140], r15: stores P into SrvCall +0x140 on the feature-disabled path. Compare r15 here with rsi on the enabled path at +0x102F5: both hold the same P.
  • mrxsmb10+0x10318call SmbCeUpdateTransportDispatchVectors: rcx holds P (the same in either path).

What to expect: stepping the disabled path shows the identical pointer value in r15, [rbx+0x140], and rcx as the enabled path shows in rsi. No corruption, page fault, or type-confused pointer arises from this code; the difference between paths is the presence/absence of the validation check and the transient reference count on [P+8].

8. Changed Functions — Full Triage

  • MRxSmbHandOverSrvCall (unpatched 0x1C000FFD0 → patched 0x1C000EFE0): Feature-staging rollout, no security impact. The Feature_84197691__private_IsEnabledDeviceUsage gate is removed; SmbCepReferenceServerTransport (validate + transient reference) and SmbCepDereferenceServerTransport are now unconditional. Same transport pointer stored/used in both builds.
  • SmbExtSecuritySessionSetupExchangeFinalize (unpatched 0x1C0002F00 → patched 0x1C0002780): Telemetry gate removal. Removed the Feature_Servicing_EnableSMBHardeningTelemetry__private_IsEnabledDeviceUsage-gated ETW telemetry block (_tlgWriteTransfer_EtwWriteTransfer), which accounts for the drop from 199 to 127 instructions. WPP trace GUID relocation. Not security-relevant.
  • SmbCeCompleteSessionEntryInitialization (unpatched 0x1C0041098 → patched 0x1C003FEF8): Telemetry gate removal. Removed the Feature_Servicing_EnableSMBHardeningTelemetry gate before the ETW logging block; register/relocation adjustments. Not security-relevant.
  • DriverEntry (unpatched 0x1C00247D0 → patched 0x1C0023700): Telemetry gate removal + relocations. Removed the Feature_Servicing_EnableSMBHardeningTelemetry telemetry gate; WPP trace GUID and address relocations. wil_InitializeFeatureStaging / wil_UninitializeFeatureStaging remain in both builds. No semantic security change.

9. Unmatched Functions

There are no added functions. 21 functions present in the unpatched build are absent from the patched build; all are WIL feature-staging and usage-reporting helpers: Feature_84197691__private_IsEnabledDeviceUsage, Feature_84197691__private_IsEnabledFallback, Feature_Servicing_EnableSMBHardeningTelemetry__private_IsEnabledDeviceUsage, Feature_Servicing_EnableSMBHardeningTelemetry__private_IsEnabledFallback, wil_details_FeatureReporting_IncrementOpportunityInCache, wil_details_FeatureReporting_IncrementUsageInCache, wil_details_FeatureReporting_RecordUsageInCache, wil_details_FeatureReporting_ReportUsageToService, wil_details_FeatureReporting_ReportUsageToServiceDirect, wil_details_FeatureStateCache_GetCachedFeatureEnabledState, wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState, wil_details_FeatureStateCache_TryEnableDeviceUsageFastPath, wil_details_GetCurrentFeatureEnabledState, wil_details_IsEnabledFallback, wil_details_MapReportingKind, wil_details_StagingConfigFeature_HasUniqueState, wil_details_StagingConfig_Free, wil_details_StagingConfig_Load, wil_details_StagingConfig_QueryFeatureState, wil_QueryFeatureState, wil_RtlStagingConfig_QueryFeatureState. Their removal reflects the feature gates being resolved to a fixed state and the associated staging plumbing being dropped.

10. Confidence & Caveats

  • Confidence: High. Both functions were read at their exact addresses in both builds. The two unpatched code paths and the single patched path were traced instruction by instruction; the stored/used pointer is the same server-transport object pointer P in every case, and the transient reference is released in the same function.
  • Nature of the change: A WIL feature-staging rollout. The gated path (validate + transient reference on the server transport) becomes unconditional, and the staging/telemetry helpers are removed. This is a hardening/servicing change, not a fix for a demonstrable, reachable vulnerability.
  • No exploit primitive: There is no type confusion, no incorrect pointer indirection, no attacker-controlled corruption, and no reference-count imbalance introduced or removed by this diff.