upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp10
-rw-r--r--src/main.h1
-rw-r--r--src/rpc.cpp27
-rw-r--r--src/serialize.h8
4 files changed, 43 insertions, 3 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 4bc9c4d..c3fb33b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -282,6 +282,16 @@ void AddOrphanTx(const CDataStream& vMsg)
282 uint256 hash = tx.GetHash(); 282 uint256 hash = tx.GetHash();
283 if (mapOrphanTransactions.count(hash)) 283 if (mapOrphanTransactions.count(hash))
284 return; 284 return;
285
286 // Do not allow an orphan to have an unbounded number of inputs.
287 // 10,000 inputs is enough for massive legitimate sweeps, but bounds the total
288 // memory in mapOrphanTransactionsByPrev to ~10,000 * MAX_ORPHAN_TRANSACTIONS.
289 if (tx.vin.size() > 10000)
290 {
291 if (LogAcceptsCategory("net")) printf("AddOrphanTx() : orphan with %d inputs rejected\n", (int)tx.vin.size());
292 return;
293 }
294
285 CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg); 295 CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);
286 foreach(const CTxIn& txin, tx.vin) 296 foreach(const CTxIn& txin, tx.vin)
287 mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg)); 297 mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
diff --git a/src/main.h b/src/main.h
index 3bc1219..7266e3d 100644
--- a/src/main.h
+++ b/src/main.h
@@ -14,7 +14,6 @@ class CBlockIndex;
14class CWalletTx; 14class CWalletTx;
15class CKeyItem; 15class CKeyItem;
16 16
17static const unsigned int MAX_SIZE = 0x02000000;
18// Ceiling on transactions held waiting for a parent that has not arrived. 17// Ceiling on transactions held waiting for a parent that has not arrived.
19// They cost a peer nothing to send and are never validated, only stored. 18// They cost a peer nothing to send and are never validated, only stored.
20static const unsigned int MAX_ORPHAN_TRANSACTIONS = 100; 19static const unsigned int MAX_ORPHAN_TRANSACTIONS = 100;
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,
681 int& blocksFoundThisSession) 681 int& blocksFoundThisSession)
682{ 682{
683 json req; 683 json req;
684 try { req = json::parse(rawLine); } 684 try {
685 // Fast pre-parse depth check to prevent stack overflow in json::parse.
686 // Legitimate Stratum requests have a depth of at most 4.
687 int depth = 0;
688 bool in_string = false;
689 bool escape = false;
690 for (char c : rawLine) {
691 if (in_string) {
692 if (escape) escape = false;
693 else if (c == '\\') escape = true;
694 else if (c == '"') in_string = false;
695 } else {
696 if (c == '"') in_string = true;
697 else if (c == '{' || c == '[') {
698 if (++depth > 20) {
699 LogPrint("worker", "[worker] JSON too deeply nested from %s\n",
700 m->address.empty() ? "(unauth)" : m->address.c_str());
701 return true;
702 }
703 } else if (c == '}' || c == ']') {
704 depth--;
705 }
706 }
707 }
708 req = json::parse(rawLine);
709 }
685 catch (...) { 710 catch (...) {
686 LogPrint("worker", "[worker] JSON parse error from %s: %.80s\n", 711 LogPrint("worker", "[worker] JSON parse error from %s: %.80s\n",
687 m->address.empty() ? "(unauth)" : m->address.c_str(), 712 m->address.empty() ? "(unauth)" : m->address.c_str(),
diff --git a/src/serialize.h b/src/serialize.h
index ce72c60..fa77074 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -20,7 +20,7 @@ class CDataStream;
20class CAutoFile; 20class CAutoFile;
21 21
22static const int VERSION = 101; 22static const int VERSION = 101;
23 23static const unsigned int MAX_SIZE = 0x02000000;
24 24
25 25
26 26
@@ -399,6 +399,8 @@ void Unserialize(Stream& is, basic_string<C>& str, int, int)
399 // only string field on a serialized type and RelayMessage casts it away -- 399 // only string field on a serialized type and RelayMessage casts it away --
400 // so this is a guard against the next one that does, not a live hole. 400 // so this is a guard against the next one that does, not a live hole.
401 unsigned int nSize = ReadCompactSize(is); 401 unsigned int nSize = ReadCompactSize(is);
402 if (nSize > MAX_SIZE)
403 throw std::ios_base::failure("String size too large");
402 str.clear(); 404 str.clear();
403 unsigned int nMid = 0; 405 unsigned int nMid = 0;
404 while (nMid < nSize) 406 while (nMid < nSize)
@@ -472,6 +474,8 @@ void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion,
472 // Limit size per read so bogus size value won't cause out of memory 474 // Limit size per read so bogus size value won't cause out of memory
473 v.clear(); 475 v.clear();
474 unsigned int nSize = ReadCompactSize(is); 476 unsigned int nSize = ReadCompactSize(is);
477 if (nSize > MAX_SIZE)
478 throw std::ios_base::failure("Vector size too large");
475 unsigned int i = 0; 479 unsigned int i = 0;
476 while (i < nSize) 480 while (i < nSize)
477 { 481 {
@@ -492,6 +496,8 @@ void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion,
492 496
493 v.clear(); 497 v.clear();
494 unsigned int nSize = ReadCompactSize(is); 498 unsigned int nSize = ReadCompactSize(is);
499 if (nSize > MAX_SIZE)
500 throw std::ios_base::failure("Vector size too large");
495 unsigned int i = 0; 501 unsigned int i = 0;
496 unsigned int nMid = 0; 502 unsigned int nMid = 0;
497 while (nMid < nSize) 503 while (nMid < nSize)