# tcpip.sys Patch Diff — CVE-2026-58532

| | |
|---|---|
| Binary | tcpip.sys (TCP/IP Driver) |
| Pre-patch version | 10.0.26100.8737 (Windows 11 24H2, June 2026) |
| Post-patch version | 10.0.26100.8875 (Windows 11 24H2, KB5101650, July 2026) |
| KB | KB5101650 |
| CVE | CVE-2026-58532 — Windows TCP/IP Elevation of Privilege (ALE redirect-records integer overflow) |
| Diff tool | ghidriff (Ghidra VersionTrackingDiff, Ghidra 12.1.2, full tcpip.pdb symbols) |
| Functions | 14,712 matched; 12 unmatched (10 added, 2 deleted); **11 modified with code changes** |
| Vulnerable function | `tcpip!AleRedirectRecordsDeserializeFromBuffer` @ `0x14011eff4 → 0x14013f8bc` |
| Fix | Checked multiply via `WfpSizeTMultiply` behind WIL flag `Feature_1204007226` |
| Bug class | CWE-190 (Integer Overflow) — Microsoft's classification per NVD; CWE-787 (OOB write) / CWE-125 (OOB read) downstream are analyst inference |

## Summary

`AleRedirectRecordsDeserializeFromBuffer` — the kernel deserializer for WFP
ALE connection redirect records — bounds-checked its input with an
**unchecked 64-bit multiplication** (pre-patch, verified by the ghidriff
decompilation):

```c
// PRE-PATCH (10.0.26100.8737)
param_2 -= 8;                                  // remaining after u64 count
if ((count != 0) && (count * 0x228 <= param_2)) {   // ← unchecked multiply
    for (i = 0; i < count; i++) {
        WfpPoolAllocNonPaged(0x228, 'AlcR', &rec);
        /* copy 0x228-byte record from input ... */
        param_2 -= 0x228;                      // underflows once OOB
        if (rec->varLen) {
            if (param_2 < rec->varLen) goto FAIL;      // useless after wrap
            WfpPoolAllocNonPaged(rec->varLen, 'AlcR', ...);
            memmove(...);                                 // variable copy
        }
    }
}
```

With `recordCount = 0x2000000000000000`, `count * 0x228 = 0x45 * 2^64 ≡ 0`,
so a 16-byte buffer passes. The first `0x228`-byte copy reads OOB,
`remaining` underflows, and subsequent checks operate on ~`ULONGLONG_MAX`.

The **post-patch** function (length 578 → 685 bytes, ratio 0.33) gates a
checked multiply behind the WIL CFR flag **`Feature_1204007226`** and adds a
per-iteration remaining-length check — actual diff-verified decompilation:

```c
// POST-PATCH (10.0.26100.8875)
if (param_2 < 8) goto REPORT_ERROR;                    // new min-length gate
count = *param_1; remaining = param_2 - 8;
if (Feature_1204007226__private_IsEnabledDeviceUsageNoInline()) {
    if (WfpSizeTMultiply(count, 0x228, &total) != 0)   // ← checked multiply
        goto FAIL;
    if ((count != 0) && (total <= remaining)) goto OK;
    goto REPORT_ERROR;
}
if ((count == 0) || (remaining < count * 0x228))       // legacy path (flag off)
    goto REPORT_ERROR;
OK:
for (i = 0; i < count; i++) {
    if (flag_on && remaining < 0x228) goto REPORT_ERROR;   // per-iter check
    WfpPoolAllocNonPaged(0x228, 'AlcR', &rec);
    ...
    remaining -= 0x228;
    if (rec->varLen) {
        if (remaining < rec->varLen) goto REPORT_ERROR;
        WfpPoolAllocNonPaged(rec->varLen, 'AlcR', ...);
        memcpy(...);                                       // memmove → memcpy
        remaining -= rec->varLen;
    }
}
```

Error handling also changed: `WfpReportSysErrorAsNtStatus` →
`WfpReportAppErrorAsNtStatus` + `WfpReportError`, and the inner copy is now
`memcpy`.

## Functions changed (ghidriff-verified)

### tcpip!AleRedirectRecordsDeserializeFromBuffer

| | |
|---|---|
| Address | `0x14011eff4 → 0x14013f8bc` |
| Length | 578 → 685 bytes |
| Similarity | ratio 0.33 / b_ratio 0.63 |
| New called | `WfpSizeTMultiply`, `WfpReportError`, `WfpReportAppErrorAsNtStatus`, `Feature_1204007226__private_IsEnabledDeviceUsageNoInline`, `memcpy` |
| Removed called | `WfpReportSysErrorAsNtStatus`, `memmove`, `FUN_1401dad8a` |
| Callers (unchanged) | `WfpAleProcessSocketOption`, `TlShimQueryNonTcpRedirectRecords` |
| Crash frame | `+0x18d` (aprilpet's PoC crash; cleanup later faults in `WfpAleDecrementWaitRef`) |

### Other code-changed functions (same KB, likely other fixes)

`InetWakeAcquirePortAf`, `InetWakeReleasePortAf`,
`PktMonClientComponentUnregister`, `Ipv6pHandleNeighborSolicitation`,
`RawBindEndpointInspectComplete`, `Fl8AddGroup`, `FlpDeleteGroupUnderLock`,
`IpGetAllSortedAddressParameters`, `FUN_1401cd7da`, `FUN_1401cceb6` — plus 2
deleted (`FUN_1401ccede`, `FUN_1401dad8a`) and 16 modified with non-code
changes. These belong to other July-2026 fixes sharing KB5101650, not to
CVE-2026-58532.

### Added (feature-flag plumbing)

10 new WIL accessors for five flags: **`Feature_1204007226`** (the
CVE-2026-58532 fix flag — called from the patched deserializer), plus
`Feature_4272399675`, `Feature_3999242553`, `Feature_3131548987`,
`Feature_4005012793` (gating other changes in the same update).

---

<sub>Source: ghidriff diff (VersionTrackingDiff, full MSDL tcpip.pdb symbols)
of tcpip-10.0.26100.8737.sys (pre-patch) vs tcpip-10.0.26100.8875.sys
(KB5101650, post-patch), Windows 11 24H2 — 14,712/14,724 functions matched;
11 code-changed, 10 added, 2 deleted. Fix mechanism verified against the
ghidriff decompilation; root cause per aprilpet's public analysis
([writeup](https://aprl.pet/writing/cve-2026-58532)). Raw report:
`ghidriff/CVE-2026-58532/ghidriffs/`.</sub>
