mrxsmb10.sys — WIL feature-staging rollout of server-transport reference validation
KB5075912
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
MRxSmbHandOverSrvCalla 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 toSmbCeUpdateTransportDispatchVectors; 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 pointerPfrom the argument slot, validates it (P != NULLand the state field[P+0x0C] == 0, else returns0xC000020C), takes a temporary reference (lock xadd [P+8], 1), and returnsPinout.Pis then stored into the SrvCall object at+0x140. - Feature disabled: the same transport pointer
Pis 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
+0x140and passed toSmbCeUpdateTransportDispatchVectorsis the same server-transport object pointer in both builds and both feature paths.SmbCeUpdateTransportDispatchVectorsreceives a valid transport object, not a mis-typed structure. - No reference-count imbalance / use-after-free at finalization. The temporary reference taken by
SmbCepReferenceServerTransportis released bySmbCepDereferenceServerTransportwithin 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+0xFFD0—MRxSmbHandOverSrvCallentry.rcx=arg1 (server-entry context),rdx=arg2,r8=arg3,r9=arg4 (SrvCall output),[rsp+0x28]=arg5 (server-transport pointer slot).mrxsmb10+0x1002F—call Feature_84197691__private_IsEnabledDeviceUsage.eax==0selects the direct-load path,eax!=0selects theSmbCepReferenceServerTransportpath.mrxsmb10+0x10067—mov r15, [rbp+0x1E0]: loads the transport pointerPfrom the arg5 slot on the feature-disabled path.mrxsmb10+0x102FE—mov [rbx+0x140], r15: storesPinto SrvCall+0x140on the feature-disabled path. Comparer15here withrsion the enabled path at+0x102F5: both hold the sameP.mrxsmb10+0x10318—call SmbCeUpdateTransportDispatchVectors:rcxholdsP(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(unpatched0x1C000FFD0→ patched0x1C000EFE0): Feature-staging rollout, no security impact. TheFeature_84197691__private_IsEnabledDeviceUsagegate is removed;SmbCepReferenceServerTransport(validate + transient reference) andSmbCepDereferenceServerTransportare now unconditional. Same transport pointer stored/used in both builds.SmbExtSecuritySessionSetupExchangeFinalize(unpatched0x1C0002F00→ patched0x1C0002780): Telemetry gate removal. Removed theFeature_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(unpatched0x1C0041098→ patched0x1C003FEF8): Telemetry gate removal. Removed theFeature_Servicing_EnableSMBHardeningTelemetrygate before the ETW logging block; register/relocation adjustments. Not security-relevant.DriverEntry(unpatched0x1C00247D0→ patched0x1C0023700): Telemetry gate removal + relocations. Removed theFeature_Servicing_EnableSMBHardeningTelemetrytelemetry gate; WPP trace GUID and address relocations.wil_InitializeFeatureStaging/wil_UninitializeFeatureStagingremain 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
Pin 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.