Repository navigation
6.5.0: Fix crafted hive and log bounds
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 to0x7FFFFFFF). 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'snumber_of_segmentsand 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_sizeis 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 raiseRegistryRecoveryException. - Restored-buffer ballooning — dirty-page entries in the same HvLE block
carried unvalidated u32 offsets written viaseek()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 raisesRegistryRecoveryException.
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