Skip to content

read/macho: bound exports trie traversal to avoid exponential blowup#953

Open
scadastrangelove wants to merge 1 commit into
gimli-rs:mainfrom
scadastrangelove:fix/exports-trie-shared-subtree-budget
Open

read/macho: bound exports trie traversal to avoid exponential blowup#953
scadastrangelove wants to merge 1 commit into
gimli-rs:mainfrom
scadastrangelove:fix/exports-trie-shared-subtree-budget

Conversation

@scadastrangelove

Copy link
Copy Markdown

Fixes #952.

The cycle check added in #940 rejects a child offset equal to an ancestor, but not shared subtrees: a node reached by multiple non-ancestor paths is re-traversed each time. A trie whose every node has two edges to the same next node therefore has 2^depth root-to-leaf paths and the DFS runs in exponential time (a ~330-byte Mach-O hangs the exports_trie() iterator).

A well-formed exports trie is a prefix tree with at most data.len() nodes, so a valid DFS needs at most ~2 * data.len() steps. This bounds the traversal to that and stops cleanly when exceeded, covering shared-subtree (and any residual cyclic) inputs.

Verified against main: cargo test passes (25 lib incl the exports_trie tests, integration, and --features all), valid tries still traverse, and the crafted exponential trie (#952) now terminates instead of hanging.

Discovered by the rust-in-peace security pipeline.

The cycle check added in gimli-rs#940 rejects a child offset equal to an ancestor,
but not shared subtrees: a node reached by multiple non-ancestor paths is
re-traversed each time. A small crafted trie whose every node has two edges
to the same next node has 2^depth root-to-leaf paths, so the DFS runs in
exponential time (a ~330-byte Mach-O hangs the exports_trie iterator).

A well-formed exports trie is a prefix tree with at most data.len() nodes, so
a valid DFS needs at most ~2 * data.len() steps. Bound the traversal to that
and stop cleanly when exceeded, which covers shared-subtree (and any residual
cyclic) inputs. Verified: cargo test passes (lib incl exports_trie + integration),
valid tries still traverse, and the crafted exponential trie now terminates.

Discovered by the rust-in-peace security pipeline
(https://github.com/scadastrangelove/rust-in-peace/).
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.

Exports trie: shared subtrees cause exponential-time traversal (DoS)

1 participant