aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.cpp1
-rw-r--r--src/serialize.h6
-rw-r--r--src/test/serialize_tests.cpp60
3 files changed, 66 insertions, 1 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 9de895374e..71815fc2a2 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -3584,7 +3584,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
vector<uint256> vWorkQueue;
vector<uint256> vEraseQueue;
- CDataStream vMsg(vRecv);
CTransaction tx;
vRecv >> tx;
diff --git a/src/serialize.h b/src/serialize.h
index e3d9939bcc..ca3c962240 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -216,18 +216,24 @@ uint64 ReadCompactSize(Stream& is)
unsigned short xSize;
READDATA(is, xSize);
nSizeRet = xSize;
+ if (nSizeRet < 253)
+ throw std::ios_base::failure("non-canonical ReadCompactSize()");
}
else if (chSize == 254)
{
unsigned int xSize;
READDATA(is, xSize);
nSizeRet = xSize;
+ if (nSizeRet < 0x10000u)
+ throw std::ios_base::failure("non-canonical ReadCompactSize()");
}
else
{
uint64 xSize;
READDATA(is, xSize);
nSizeRet = xSize;
+ if (nSizeRet < 0x100000000LLu)
+ throw std::ios_base::failure("non-canonical ReadCompactSize()");
}
if (nSizeRet > (uint64)MAX_SIZE)
throw std::ios_base::failure("ReadCompactSize() : size too large");
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 19ffdcab66..50139df09e 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -39,7 +39,67 @@ BOOST_AUTO_TEST_CASE(varints)
ss >> VARINT(j);
BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
}
+}
+
+BOOST_AUTO_TEST_CASE(compactsize)
+{
+ CDataStream ss(SER_DISK, 0);
+ vector<char>::size_type i, j;
+
+ for (i = 1; i <= MAX_SIZE; i *= 2)
+ {
+ WriteCompactSize(ss, i-1);
+ WriteCompactSize(ss, i);
+ }
+ for (i = 1; i <= MAX_SIZE; i *= 2)
+ {
+ j = ReadCompactSize(ss);
+ BOOST_CHECK_MESSAGE((i-1) == j, "decoded:" << j << " expected:" << (i-1));
+ j = ReadCompactSize(ss);
+ BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
+ }
+}
+
+static bool isCanonicalException(const std::ios_base::failure& ex)
+{
+ return std::string("non-canonical ReadCompactSize()") == ex.what();
+}
+
+BOOST_AUTO_TEST_CASE(noncanonical)
+{
+ // Write some non-canonical CompactSize encodings, and
+ // make sure an exception is thrown when read back.
+ CDataStream ss(SER_DISK, 0);
+ vector<char>::size_type n;
+
+ // zero encoded with three bytes:
+ ss.write("\xfd\x00\x00", 3);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+
+ // 0xfc encoded with three bytes:
+ ss.write("\xfd\xfc\x00", 3);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+
+ // 0xfd encoded with three bytes is OK:
+ ss.write("\xfd\xfd\x00", 3);
+ n = ReadCompactSize(ss);
+ BOOST_CHECK(n == 0xfd);
+
+ // zero encoded with five bytes:
+ ss.write("\xfe\x00\x00\x00\x00", 5);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+
+ // 0xffff encoded with five bytes:
+ ss.write("\xfe\xff\xff\x00\x00", 5);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+
+ // zero encoded with nine bytes:
+ ss.write("\xff\x00\x00\x00\x00\x00\x00\x00\x00", 9);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
+ // 0x01ffffff encoded with nine bytes:
+ ss.write("\xff\xff\xff\xff\x01\x00\x00\x00\x00", 9);
+ BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
}
BOOST_AUTO_TEST_SUITE_END()