From 59777ee34a5ab6297684b7ab8d5d93facd4ad6f3 Mon Sep 17 00:00:00 2001 From: mtg0001 <106211915+mtg0001@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:05:35 -0300 Subject: net: bound what a peer can make the node allocate (#73) Three independent bounds on what an untrusted peer can make this node allocate: - serialize.h: reject a compact size above MAX_SIZE before reading a string or a vector, instead of discovering it read by read. MAX_SIZE moves from main.h to serialize.h, where the checks live; headers_core.h includes serialize.h first, so every existing user still sees it. - main.cpp: cap an orphan transaction at 10,000 inputs. Orphans are stored and never validated, so mapOrphanTransactionsByPrev grew with one entry per input of every orphan a peer cared to send. - rpc.cpp: drop a Stratum line nested deeper than 20 before json::parse recurses into it. The scan tracks string state, so a worker name containing { or [ is no longer mistaken for nesting. Verified: builds clean on UCRT64; the depth scanner passes a table of legitimate Stratum lines and nesting attacks; a node built from this branch synced the chain from genesis to 4462 with no deserialization failure and no rejected block. --- src/rpc.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'src/rpc.cpp') diff --git a/src/rpc.cpp b/src/rpc.cpp index 285f11b..3db8b94 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -681,7 +681,32 @@ static bool HandleLine(Miner* m, const std::string& rawLine, int& blocksFoundThisSession) { json req; - try { req = json::parse(rawLine); } + try { + // Fast pre-parse depth check to prevent stack overflow in json::parse. + // Legitimate Stratum requests have a depth of at most 4. + int depth = 0; + bool in_string = false; + bool escape = false; + for (char c : rawLine) { + if (in_string) { + if (escape) escape = false; + else if (c == '\\') escape = true; + else if (c == '"') in_string = false; + } else { + if (c == '"') in_string = true; + else if (c == '{' || c == '[') { + if (++depth > 20) { + LogPrint("worker", "[worker] JSON too deeply nested from %s\n", + m->address.empty() ? "(unauth)" : m->address.c_str()); + return true; + } + } else if (c == '}' || c == ']') { + depth--; + } + } + } + req = json::parse(rawLine); + } catch (...) { LogPrint("worker", "[worker] JSON parse error from %s: %.80s\n", m->address.empty() ? "(unauth)" : m->address.c_str(), -- cgit v1.2.3