diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.cpp | 10 | ||||
| -rw-r--r-- | src/main.h | 1 | ||||
| -rw-r--r-- | src/rpc.cpp | 27 | ||||
| -rw-r--r-- | src/serialize.h | 8 |
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)); |
| @@ -14,7 +14,6 @@ class CBlockIndex; | |||
| 14 | class CWalletTx; | 14 | class CWalletTx; |
| 15 | class CKeyItem; | 15 | class CKeyItem; |
| 16 | 16 | ||
| 17 | static 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. |
| 20 | static const unsigned int MAX_ORPHAN_TRANSACTIONS = 100; | 19 | static 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; | |||
| 20 | class CAutoFile; | 20 | class CAutoFile; |
| 21 | 21 | ||
| 22 | static const int VERSION = 101; | 22 | static const int VERSION = 101; |
| 23 | 23 | static 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) |