Skip to content

registry: harden hive parser against malformed inputs#27

Merged
psycep merged 2 commits into
mainfrom
fix-hive-resident-bounds
May 12, 2026
Merged

registry: harden hive parser against malformed inputs#27
psycep merged 2 commits into
mainfrom
fix-hive-resident-bounds

Conversation

@psycep
Copy link
Copy Markdown
Collaborator

@psycep psycep commented May 12, 2026

Summary

Closes #25 plus three structurally similar bugs in pkg/registry/hive.go surfaced while patching. All four are panic-or-silent-corruption paths reachable from attacker-controlled hive bytes; all four are fixed by single-condition guards that match the cell-header invariant the existing code already implicitly assumes.

Site Before After
GetValueData resident (issue #25) data[:dataLen] on a 4-byte buffer guard dataLen > 4, return error
SetValueData resident inline copy past DataOffset field same guard
SetValueData non-resident blind copy(h.data[off:off+dataLen],...) route through readCell, verify dataLen <= len(cell)
enumSubKeys riSig branch subCell[0:2] / subCell[2:4] without length check if len(subCell) < 4 { continue }

Issue #25 reports the read-path bug (found by kajaaz via Zorya). The other three are the same bug class one file over, caught during review.

Test plan

  • go build ./..., go vet ./..., go test ./... all clean
  • New unit tests for the read-path guard (TestGetValueDataResidentLengthRejected covers dataLen ∈ {5, 8, 0xFF, 0x7FFFFFFF} with the resident flag; TestGetValueDataResidentLengthAllowed covers the happy path 1..4 bytes)
  • Lab regression: secretsdump -k against a GOAD DC decoded SAM and LSA Secrets correctly through the modified read AND write paths
  • Both rounds of augur review (post-fix-1 + post-fix-2) reached "ship it"

The SetValueData (resident + non-resident) and enumSubKeys riSig guards aren't covered by unit tests in this PR; exercising them requires building a full NK/VK/sub-list hive synthesis helper. Left as a follow-up; the fixes themselves are structurally identical to the read-path guard which is tested.

psycep added 2 commits May 11, 2026 23:48
Four parser-panic / silent-corruption bugs in pkg/registry/hive.go,
all reachable from attacker-controlled hive bytes:

1. GetValueData resident branch: VKRecord.DataLen lower 31 bits are
   read verbatim and used to slice a 4-byte buffer at [:dataLen]. A
   DataLen of 0x80000005 panics with "slice bounds out of range".
   Found by kajaaz using Zorya (issue #25); fix matches her suggested
   one-line bounds check.

2. SetValueData resident branch (structurally identical to #1): the
   existing len(newData) == dataLen check doesn't enforce the 4-byte
   cap, so a hostile dataLen=5 with a matching 5-byte newData slices
   one byte past the DataOffset field into the adjacent cell. Same
   guard.

3. SetValueData non-resident branch: vk.DataOffset is attacker-
   controlled and the code does copy(h.data[dataPos:dataPos+dataLen],
   newData) without ever validating the destination. Hostile offsets
   either panic on out-of-bounds or silently scribble over arbitrary
   hive bytes (a value of 0xFFFFF000 lands near the regf header). Route
   through readCell (which validates the cell header and bounds) and
   verify dataLen fits before mutating.

4. enumSubKeys riSig branch: readCell can return a slice shorter than
   the 4-byte cell header (minimum-size cell with no usable bytes), so
   the immediate subCell[0:2] / subCell[2:4] reads can panic on a
   malformed sub-list. The sibling code at line 397/437 already guards
   the analogous index; mirror it here.

Fixes #25 plus three structurally similar bugs surfaced while patching.
Cover the GetValueData guard added in the previous commit with two
table-driven tests: the rejection path (dataLen ∈ {5, 8, 0xFF,
0x7FFFFFFF} with resident bit set) confirms the guard fires without
panicking and surfaces a helpful error; the happy path (dataLen ∈
{1, 2, 3, 4}) confirms the inline DataOffset bytes are returned
correctly so the guard didn't regress valid hives.

The matching guards in SetValueData (resident + non-resident write
paths) and enumSubKeys (riSig branch) require full NK/VK/sub-list
hive synthesis to exercise end-to-end; they're structurally identical
to the read-path guard and are validated by build/vet plus the lab
regression check on secretsdump. Worth a follow-up to extend the
synth helpers and cover them directly.
@psycep psycep merged commit ae12780 into main May 12, 2026
2 checks passed
@psycep psycep deleted the fix-hive-resident-bounds branch May 12, 2026 04:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

panic: runtime error: slice bounds out of range in (*Hive).GetValueData, resident data length not validated

1 participant