fix: Refuse to walk an invalid SHAMap in getMissingNodes

A walk that reaches a position only a leaf may occupy now marks the map
Invalid and abandons the descent instead of continuing:
SHAMapNodeID::getChildNodeID() throws past kLeafDepth, uncaught, all the
way to std::terminate(). It's reachable without going through
addKnownNode() at all - InboundLedgers::gotStaleData() stores any
parseable node from an unsolicited liAS_NODE reply into the fetch pack by
its own hash with no relatedness check - making this a conditioned remote
denial of service, not just a single bad packet.

As in addKnownNode(), the depth check runs before the full-below cache
lookup, for the same cache-doesn't-cover-depth reason. Callers must
re-check isValid() before reading an empty result as nothing left to
fetch, which getMissingNodes()'s docstring now says.
This commit is contained in:
Bart
2026-08-22 22:33:19 -04:00
parent 3ee3f3740c
commit 114ecf73d2
6 changed files with 367 additions and 12 deletions

View File

@@ -143,10 +143,10 @@ private:
/**
* The map's state.
*
* A getMissingNodes() walk writes it, through clearSynching(), while whatever
* drives the acquisition reads it. Nothing here requires the caller to hold a
* lock across the walk, and the acquisition code does not, so this is atomic
* rather than guarded.
* A getMissingNodes() walk writes it, through setInvalid() and
* clearSynching(), while whatever drives the acquisition reads it.
* Nothing here requires the caller to hold a lock across the walk, and
* the acquisition code does not, so this is atomic rather than guarded.
*/
std::atomic<SHAMapState> state_;
SHAMapType const type_;
@@ -339,9 +339,14 @@ public:
* concurrency, to discover nodes referenced in the
* SHAMap but not available locally.
*
* Marks the map Invalid and abandons the traversal on meeting an inner
* node at or beyond kLeafDepth, a shape no valid tree can have, so
* callers must re-check isValid() before reading an empty result as
* "nothing left to fetch".
*
* @param maxNodes The maximum number of found nodes to return
* @param filter The filter to use when retrieving nodes
* @param return The nodes known to be missing
* @return The nodes known to be missing, or empty if the map is Invalid
*/
std::vector<std::pair<SHAMapNodeID, uint256>>
getMissingNodes(int maxNodes, SHAMapSyncFilter const* filter);