From 1635bc34f40c76ac2943dbe6ff15dd0180b62ea6 Mon Sep 17 00:00:00 2001 From: Bitflash Date: Tue, 28 Jul 2026 15:25:15 -0300 Subject: serialize: grow strings as data arrives, not to the declared length (#18) The vector unserializer grows in 5 MB steps so a bogus length cannot make it allocate more than has actually been received. The string one resized straight to whatever ReadCompactSize returned, and ReadCompactSize has no ceiling -- nine bytes on the wire can name four gigabytes. Not reachable from the network today: the only string on a serialized type is CWalletTx::mapValue, and RelayMessage casts to CTransaction before sending, so it never leaves disk. This is a guard against the next network message that carries a string -- Bitcoin's own version message carries strSubVer -- rather than a fix for a live hole. --- src/serialize.h | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'src/serialize.h') diff --git a/src/serialize.h b/src/serialize.h index 0e03cf7..ce72c60 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -390,10 +390,26 @@ void Serialize(Stream& os, const basic_string& str, int, int) template void Unserialize(Stream& is, basic_string& str, int, int) { + // Grow in steps as the bytes actually arrive, the same way the vector + // unserializer below does. Resizing straight to the declared length lets + // nine bytes on the wire ask for a four-gigabyte allocation, and + // ReadCompactSize has no ceiling of its own. + // + // No network message carries a string today -- CWalletTx::mapValue is the + // only string field on a serialized type and RelayMessage casts it away -- + // so this is a guard against the next one that does, not a live hole. unsigned int nSize = ReadCompactSize(is); - str.resize(nSize); - if (nSize != 0) - is.read((char*)&str[0], nSize * sizeof(str[0])); + str.clear(); + unsigned int nMid = 0; + while (nMid < nSize) + { + nMid += 5000000 / sizeof(C); + if (nMid > nSize) + nMid = nSize; + unsigned int nOld = str.size(); + str.resize(nMid); + is.read((char*)&str[nOld], (nMid - nOld) * sizeof(C)); + } } -- cgit v1.2.3