mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-21 22:30:57 +00:00
A SHAMap has 65 levels, and nibbles run out at level 64: `selectBranch` indexes the key byte at `depth / 2`, so at depth 64 it reads byte 32 of a 32-byte key. Only the leaf terminating a path may sit at that depth, but proof path nodes come off the wire, so a peer could send 65 hash-chained inner nodes and drive that read past the end of the buffer. The existing length bound cannot be tightened to catch this: a path for two keys sharing all 63 leading nibbles legitimately holds 64 inner nodes plus a leaf, so 65 elements is valid. The claimed node type at the final depth is the thing to reject, using `>=` rather than `==` to match the convention every other `kLeafDepth` comparison in this codebase already follows. Reachable from `TMProofPathResponse` via `LedgerReplayMsgHandler`; confirmed under ASan with asserts compiled out that the unguarded read lands one byte past a 32-byte heap allocation. Also closes a second gap: nothing checked the terminal leaf's own key against `key`, so the hash chain alone let a peer substitute any leaf whose subtree hashes matched at every level above it. Pinned by tests: the 65-element path that must verify for both keys sharing the deep prefix, and the forged all-inner path that must not. Also guards `visitDifferences` against an inner node claimed at leaf depth: `hasLeafNode` only checked the comparison map, not the map being walked, so a corrupt node in the map under `visitDifferences` itself could still throw uncaught. Skip such a node's children instead.