Skip to content

6.5.0: Fix crafted hive and log bounds

Choose a tag to compare

@mkorman90 mkorman90 released this 12 Oct 00:15
· 9 commits to master since this release
c272cb0

regipy 6.5.0

Security release. Crafted registry hives and transaction logs no longer
trigger unbounded memory allocation or infinite loops in the Python backend.
Output on valid hives and transaction logs is byte-identical to 6.4.0 — the
full suite passes unchanged, including exact recovered-page counts on real
transaction logs.

⚠️ Security - bounds when parsing untrusted input

Reported by Zhang Yan (credited in the commit trailer with permission),
plus two further issues of the same class found in the same code paths during
validation. All are availability issues (DoS); no code-execution path was
identified.

  • Unbounded memory in NKRecord._parse_indirect_block — reassembly of
    big-data (db) values was bounded only by the value's declared
    data_size (u32, attacker-controlled, up to 0x7FFFFFFF). A crafted hive
    could amplify a small file into unbounded memory (a 40 KB hive declaring
    64 MiB consumed ~179 MiB RSS; worst case ~2 GiB per value). The reassembly
    is now bounded by the db header's number_of_segments and the result is
    clamped to the hive file size. The Rust backend (regipy-rs) already
    enforced the equivalent bounds; the Python backend is now at parity.
  • Infinite loop in apply_transaction_logs — an HvLE block whose
    log_size is smaller than the 40-byte block header (e.g. 0) used to be
    re-parsed forever at 100% CPU (552-byte log, never returns). Such blocks
    now raise RegistryRecoveryException.
  • Restored-buffer ballooning — dirty-page entries in the same HvLE block
    carried unvalidated u32 offsets written via seek() into the in-memory
    restored-hive buffer, which is then written to disk. A 576-byte log could
    balloon it to ~4 GiB. Out-of-hive entries now raise
    RegistryRecoveryException.
  • DIRT dirty-page vector length — derived from the hive header's
    hbins_data_size; a mismatching log previously died with a raw
    IndexError. It now raises RegistryRecoveryException.

Behavior note: valid hives and transaction logs parse byte-identically.
Only malformed input changes behavior — where 6.4.0 hung, OOM'd, or died
with a raw IndexError, 6.5.0 raises a clear RegistryRecoveryException.

Operational guidance: registry hives and transaction logs are untrusted
input!!! Process them inside sandboxes and well-isolated environments
(resource-capped containers/VMs, memory/CPU limits, timeouts). These bounds
are defense in depth, not a substitute for isolation.

regipy-rs: no Rust release is required for these fixes — the Rust backend
already enforced the big-data bounds, and recovery is Python-only.

Fixed

  • Shimcache (AppCompatCache) parsing of NT 5.2 entries (Windows
    2003 / Vista / 2008) — @aissablk1 in #347

Packaging & infrastructure

  • regipy-rs: port to PyO3 0.29 (fixes #334) — #346
  • CI: Python publish workflow is skipped on regipy-rs-* releases — #345

Tests

57/57 tests pass, including 4 new regression tests covering the crafted-input
vectors (each verified to fail or hang on the unfixed code). ruff and mypy
clean. Before/after verified against the reporter's stdlib-only PoC
generator.

New contributors: @aissablk1 made their first contribution in #347 —
welcome!

Full Changelog: 6.4.0...6.5.0