Fix infinite loop / duplicate rows on cyclic ESE leaf-page chain#2208
Open
uziel110 wants to merge 1 commit into
Open
Fix infinite loop / duplicate rows on cyclic ESE leaf-page chain#2208uziel110 wants to merge 1 commit into
uziel110 wants to merge 1 commit into
Conversation
A dirty-shutdown or inconsistent ESE database (e.g. an ntds.dit whose B-tree pointers were never committed) can contain a leaf-page chain whose NextPageNumber links back to an already-visited page. getNextRow() would follow that back-edge forever, re-emitting every row once per lap and hanging secretsdump's LOCAL parsing. Track visited leaf pages per cursor and stop the table walk when NextPageNumber points to a page already seen, logging an error that the database may be in a dirty-shutdown / inconsistent state. A healthy ESE leaf chain is acyclic and terminates at NextPageNumber == 0, so this only triggers on corrupt input and never affects valid databases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ESENT_DB.getNextRow()walks an ESE table's leaf pages by following each page'sNextPageNumber. A healthy leaf chain is acyclic and terminates atNextPageNumber == 0.However, a database in a dirty-shutdown / inconsistent state (e.g. an
ntds.ditwhose B-tree pointers were never committed) can contain a leaf chain whoseNextPageNumberlinks back to an already-visited page. The current code follows that back-edge unconditionally, so it loops forever — re-emitting every row once per lap. In practice this hangssecretsdump.pyLOCAL parsing and produces endless duplicate hashes.Fix
Track the set of leaf pages already visited for each cursor (
VisitedPages, plusCurrentPageNumberfor accurate logging). WhenNextPageNumberpoints to a page that has already been walked, stop the table read and log an error noting the database may be inconsistent.Because a valid ESE leaf chain never revisits a page, this only triggers on corrupt input and is a no-op for healthy databases. At the point the cycle is detected, every reachable page has already been read exactly once, so the table walk is complete.
Testing
ntds.ditthat previously causedsecretsdump.py -ntds ... LOCALto loop and emit duplicate machine/user hashes — it now completes cleanly with the cycle-detection error logged.🤖 Generated with Claude Code