mup.sys — WIL feature-staging library churn
KB5079466
1. Overview
| Field | Value |
|---|---|
| Unpatched binary | mup_unpatched.sys |
| Patched binary | mup_patched.sys |
| Overall similarity | 0.9862 (very high) |
| Matched functions | 361 |
| Changed functions | 5 (plus relocation-only churn) |
| Identical functions | 356 |
| Unmatched (unpatched) | 0 |
| Unmatched (patched) | 2 added (both WIL helpers) |
Verdict: There is no security-relevant change between the two builds. The functions that actually changed are all part of the statically-linked Windows Implementation Library (WIL) feature-staging runtime — wil_details_GetCurrentFeatureEnabledState, wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState, and wil_details_EvaluateFeatureDependencies_ReevaluateCachedFeatureEnabledState. The patch is a WIL library version bump that adds feature-dependency evaluation (a new helper wil_details_AreDependenciesEnabled) and a new feature-state cache marker bit (0x40000). None of these routines are the Multiple UNC Provider network path. Every real Mup* function is byte-for-byte identical between the two builds apart from jump-target relocation (caused by the WIL functions growing) and one benign compiler refactor of pointer arithmetic in MupCallSurrogatePrePost. The 0xc00 and 0x40000 bit values are WIL feature-state cache encodings, not "Hardened UNC Paths" mutual-authentication / message-integrity flags.
The remainder of this report documents the changed functions accurately, shows why the WIL-encoding bits are not security policy flags, and records the independent full-diff triage that confirms no omitted fix.
2. Changed-Function Analysis
Finding 1 — wil_details_GetCurrentFeatureEnabledState (WIL feature state, not UNC flags)
| Field | Value |
|---|---|
| Severity | None (informational) |
| Change class | WIL feature-staging library churn |
| Affected function | wil_details_GetCurrentFeatureEnabledState (unpatched 0x1400032CC, patched 0x140003384) |
| Reachability | WIL internal; called from wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState and wil_details_IsEnabledFallback, not from an IRP dispatch path |
What this function is:
wil_details_GetCurrentFeatureEnabledState reads a WIL feature descriptor and computes the current enabled state for that feature. Near the top it calls wil_RtlStagingConfig_QueryFeatureState (0x1400113C0) to read the staged configuration, then builds a WIL state word out of the query result. The bytes it reads at descriptor offsets +0x1c–+0x1f and the list pointer at +0x20 are WIL feature-descriptor fields (feature kind, change-time flags, and the feature-dependency list), not UNC provider capability bytes.
What actually changed:
The patched build adds WIL feature-dependency evaluation. After computing the state word (ebx), the patched code does:
0x14000342c mov edx, 0C00h ; two WIL state bits
0x140003435 and eax, edx
0x140003437 cmp eax, edx ; both bits set?
0x140003439 jnz ...
0x140003450 mov rcx, rbp
0x140003453 call wil_details_AreDependenciesEnabled ; NEW WIL helper
0x140003469 btr eax, 0Ah ; clear WIL state bit 0x400 if deps not enabled
wil_details_AreDependenciesEnabled (0x140002CA8) is a newly added WIL helper that walks the feature's dependency list (the +0x20 pointer) and returns whether the dependencies are currently enabled. When they are not, WIL clears the 0x400 state bit. This is standard WIL feature-dependency gating introduced by a newer WIL revision. It is not a "provider capability" check and it has no bearing on UNC authentication.
The 0x400 / 0x800 masks are produced from the two 32-bit halves of the wil_RtlStagingConfig_QueryFeatureState output via the neg/sbb/and idiom; they encode the queried WIL feature state, not "mutual authentication required" / "message integrity required."
Finding 2 — wil_details_EvaluateFeatureDependencies_ReevaluateCachedFeatureEnabledState
| Field | Value |
|---|---|
| Severity | None (informational) |
| Change class | WIL feature-staging library churn |
| Affected function | wil_details_EvaluateFeatureDependencies_ReevaluateCachedFeatureEnabledState (0x140012D90, same address in both builds) |
| Reachability | WIL internal; reached from wil_details_EvaluateFeatureDependencies (0x140012C9C) and wil_details_EvaluateFeatureDependencies_GetCachedFeatureEnabledState (0x140012D54) |
What this function is:
This is the dependency-aware counterpart to Finding 1. It re-evaluates a cached WIL feature-enabled state and atomically writes the recomputed state word back into the WIL feature cache via lock cmpxchg. The list it walks at arg+0x20 is the WIL feature-dependency list; the byte checks at +0x1d/+0x1e distinguish dependency-descriptor kinds.
What actually changed:
The patched build adds the same WIL dependency gate as Finding 1: it masks the state word with 0xc00, and when both bits are set it treats the result of the dependency check as a condition to clear WIL state bit 0x400 (btr edx, 0Ah) before the atomic write. This mirrors the wil_details_AreDependenciesEnabled behavior added to GetCurrentFeatureEnabledState. The btr ecx, 9 that clears bit 0x200 is present in both builds and is unrelated to the change. This is WIL cache-encoding churn, not a security fix.
Finding 3 — wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState
| Field | Value |
|---|---|
| Severity | None (informational) |
| Change class | WIL feature-staging library churn |
| Affected function | wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState (unpatched 0x14000317C, patched 0x14000321C) |
What actually changed:
This function recomputes a feature's cached state and commits it with lock cmpxchg. The patched build adds a new WIL cache-marker bit: bts eax, 12h sets bit 0x40000 in the value written to the cache. The surrounding state-encoding masks (0x9C1, 0xFFFFF63E, 0x400, and the btr ...,0Ah clear) already exist in the unpatched build; the patch only adds the 0x40000 marker and reshuffles register allocation (adds r12, moves rbp→r14/r15). Bit 0x40000 is a WIL feature-state cache encoding flag; nothing here touches UNC providers or authentication.
3. Why the changed bits are not security policy flags
The report's original thesis rested on reading 0x400/0x800/0x40000 as "mutual authentication required," "message integrity required," and an "enforcement-tracking flag." That reading is not supported by the binaries:
- The three changed routines are named, in both
.asmlistings,wil_details_GetCurrentFeatureEnabledState,wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState, andwil_details_EvaluateFeatureDependencies_ReevaluateCachedFeatureEnabledState. These are Windows Implementation Library feature-staging routines. - The
0x400/0x800masks are derived from the two halves ofwil_RtlStagingConfig_QueryFeatureState's output — a WIL staged-configuration query — not from any registry-backed Hardened UNC Paths policy word. - The "new provider-validation helper" is
wil_details_AreDependenciesEnabled, a WIL feature-dependency evaluator, and the+0x20list it walks is the feature-dependency list. - Bit
0x40000is set bybts ...,12hinside a WIL state-cache commit and is a cache encoding marker.
There is no code path in either build that maps these bits to SMB/UNC mutual authentication, message integrity, or provider enforcement.
4. Pseudocode Diff
wil_details_GetCurrentFeatureEnabledState
// UNPATCHED (0x1400032CC): compute WIL state word, gate list walk on bit 6 (0x40)
int32_t merged = base | flags; // 0x14000336b: or ecx, edx
int32_t bit6 = (merged >> 6) & 1; // 0x14000336f: shr eax,6; and eax,1
int32_t state = bit6 | merged;
// walk feature-descriptor list at [desc+0x20] when bit6 set
// PATCHED (0x140003384): add WIL feature-dependency gate
int32_t merged = base | flags; // 0x14000342a: or ebx, ecx
if ((merged & 0xc00) == 0xc00) { // 0x14000342c..0x140003437
int32_t deps = (desc[0x20] == 0) ? 1
: wil_details_AreDependenciesEnabled(desc); // 0x140003453
if (!deps)
state = merged & ~0x400; // 0x140003469: btr eax,0Ah
}
wil_details_EvaluateFeatureDependencies_ReevaluateCachedFeatureEnabledState
// UNPATCHED (0x140012D90): atomic commit, clears WIL bit 0x200 only
new = (old & ~1) | dep_bit;
new &= ~0x200; // 0x140012e2e: btr ecx,9 (both builds)
lock cmpxchg [cache], new;
// PATCHED: add WIL dependency gate before the same commit
bool both = (arg2 & 0xc00) == 0xc00;
new = (old & ~1) | dep_bit;
if (both && !dep_ok) new &= ~0x400; // 0x140012e56: btr edx,0Ah
new &= ~0x200; // btr ecx,9 (unchanged)
lock cmpxchg [cache], new;
wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState
// UNPATCHED (0x14000317C): commit WIL state without 0x40000 marker
// PATCHED (0x14000321C): eax |= 0x40000 (bts eax,12h) before lock cmpxchg
5. Assembly Analysis
wil_details_GetCurrentFeatureEnabledState — unpatched (0x1400032CC)
00000001400032CC mov [rsp+arg_10], rbx
00000001400032D2 sub rsp, 40h
00000001400032D6 mov al, [rcx+1Ch] ; WIL feature-descriptor kind
00000001400032F8 mov edx, [rcx+18h] ; WIL descriptor change-time field
000000014000330C call wil_RtlStagingConfig_QueryFeatureState
0000000140003326 and edx, 400h ; WIL state bit from query hi/lo halves
0000000140003331 and r8d, 800h ; WIL state bit
0000000140003338 or r8d, edx
000000014000336B or ecx, edx ; merge WIL state word
000000014000336F shr eax, 6 ; gate list walk on bit 6
000000014000337F jz loc_14000340D
0000000140003385 mov rdi, [rdi+20h] ; WIL feature-dependency list
00000001400033CD call wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState
000000014000341C retn
wil_details_GetCurrentFeatureEnabledState — patched (0x140003384), new dependency gate
000000014000342A or ebx, ecx ; merge WIL state word
000000014000342C mov edx, 0C00h ; two WIL state bits
0000000140003435 and eax, edx
0000000140003437 cmp eax, edx ; both set?
0000000140003439 jnz short loc_140003440
0000000140003453 call wil_details_AreDependenciesEnabled ; NEW WIL helper
0000000140003460 test r14d, r14d
0000000140003469 btr eax, 0Ah ; clear WIL bit 0x400 if deps disabled
0000000140003498 retn
wil_details_AreDependenciesEnabled (0x140002CA8) is present only in the patched build. At the same address in the unpatched build sits an unrelated function (wil_details_FeatureReporting_IncrementOpportunityInCache) — an example of address reuse across builds; the helper is genuinely new, added by the WIL revision.
wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState — the 0x40000 marker
In the patched build the state value written by lock cmpxchg [r12], esi has bit 0x40000 set via bts eax, 12h. The unpatched build commits the same state word without that bit. All other encoding masks (0x9C1, 0xFFFFF63E, 0x400, btr ...,0Ah) are identical in both builds.
6. Real Mup* Attack Surface — Unchanged
The Multiple UNC Provider network-facing functions did not change in logic. The following Mup* functions show differences only because the WIL functions grew and pushed later code down, shifting jump/return-target addresses:
MupGetIoStatus, MupPostAcquireForSectionSynchronisation, MupStateMachine, MupSurrogateGetUncProviderDeviceObject, MupiGetNextUncHardeningConfigurationEntry, MupiGetNextUncProvider, MupiSetProviderFlags — each differs only in relocated locret_/jump-table target addresses; instruction streams are otherwise identical.
MupCallSurrogatePrePost (unpatched 0x14001D3F0, patched 0x14001D4C0) is the one Mup function with a real code difference, and it is a compiler refactor of linked-list pointer arithmetic: manual add/dereference sequences were replaced with scaled indexing ([rbx+rax*8+...], [rsi+rax*8+8]). The control flow and the STATUS_MORE_PROCESSING_REQUIRED (0x103) comparison are preserved. Semantics are unchanged; not security-relevant.
7. Exploit Primitive
None. There is no security bug here to exploit. The changed code is WIL feature-staging bookkeeping; it does not alter any UNC authentication, integrity, provider-selection, or hardening decision. There is no memory-corruption primitive, no policy bypass, and no attacker-reachable behavioral difference between the two builds.
8. Trigger / Reachability
The changed WIL routines run during feature-state evaluation inside the driver's own WIL runtime (feature descriptor queries and cache re-evaluation). They are not gated behind, and do not implement, the Hardened UNC Paths policy. No user-mode UNC operation produces a security-relevant difference in behavior between the unpatched and patched builds.
9. Changed Functions — Full Triage
| Function | Address (unpatched → patched) | Similarity | Nature |
|---|---|---|---|
wil_details_GetCurrentFeatureEnabledState |
0x1400032CC → 0x140003384 |
0.748 | WIL feature-dependency evaluation added (calls new wil_details_AreDependenciesEnabled). Not security-relevant. |
wil_details_EvaluateFeatureDependencies_ReevaluateCachedFeatureEnabledState |
0x140012D90 (same) |
0.754 | Same WIL dependency gate before the state-cache lock cmpxchg. Not security-relevant. |
wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState |
0x14000317C → 0x14000321C |
0.973 | Adds WIL cache-marker bit 0x40000 (bts eax,12h) plus register reallocation. Not security-relevant. |
MupCallSurrogatePrePost |
0x14001D3F0 → 0x14001D4C0 |
0.926 | Compiler refactor of linked-list pointer arithmetic (manual add → scaled rax*8). Semantics identical. Not security-relevant. |
wil_InitializeFeatureStaging |
0x1400230F4 (same) |
0.983 | Call-target relocations; RtlRegisterFeatureUsageProvider call moved into new wrapper wil_details_RegisterFeatureUsageProvider (0x140012F2C). Not security-relevant. |
All remaining Mup* differences are jump-target relocation only (no logic change).
10. Independent Full-Diff Triage
An independent function-by-function comparison of both builds (matching by content across relocations, not by reused address) was performed to confirm nothing security-relevant was omitted:
- Added in patched (2):
wil_details_AreDependenciesEnabled(0x140002CA8) andwil_details_RegisterFeatureUsageProvider(0x140012F2C). Both are WIL library helpers introduced by the WIL revision; neither touches UNC provider selection or authentication. - Removed in unpatched: none.
- Content-changed: the five functions in Section 9 plus a set of
Mup*/library functions whose only differences are relocated jump/return targets (normalizing address operands: instruction streams match). - No omitted security fix was found. In particular, no
Mup*routine that participates in UNC path handling, provider registration, hardening-configuration parsing, or authentication changed in logic.
11. Unmatched Functions
| Direction | Functions |
|---|---|
| Removed (unpatched-only) | None |
| Added (patched-only) | wil_details_AreDependenciesEnabled (0x140002CA8), wil_details_RegisterFeatureUsageProvider (0x140012F2C) — both WIL helpers |
12. Confidence & Caveats
Confidence: High. The changed functions are named as WIL feature-staging routines in both disassembly listings, the new helper is wil_details_AreDependenciesEnabled, and the flag-source call is wil_RtlStagingConfig_QueryFeatureState. The 0xc00 and 0x40000 bits are WIL feature-state cache encodings. Every UNC-facing Mup* function is identical except for relocation and one semantics-preserving compiler refactor.
Conclusion: This patch is a WIL feature-staging library version bump. It contains no security-relevant change to the Multiple UNC Provider driver.