Merge pull request #2499 from jpk68/checks-2

libi2pd: add missing checks and limits
This commit is contained in:
orignal
2026-08-19 21:33:57 -04:00
committed by GitHub
8 changed files with 68 additions and 14 deletions
+1
View File
@@ -654,6 +654,7 @@ namespace datagram
}
}
if (!m_RoutingSession) return nullptr;
auto path = m_RoutingSession->GetSharedRoutingPath();
if (path && m_RoutingSession->IsRatchets () && m_RoutingSession->CleanupUnconfirmedTags ())
{
+11
View File
@@ -557,8 +557,19 @@ namespace client
void LeaseSetDestination::HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len)
{
if (len < 33)
{
LogPrint (eLogWarning, "Destination: Database search reply is too short, ", len);
return;
}
i2p::data::IdentHash key (buf);
int num = buf[32]; // num
size_t maxNum = (len - 33)/32;
if ((size_t)num > maxNum)
{
LogPrint (eLogWarning, "Destination: Declared number of peer hashes ", num, " exceeds message size, reduced to ", maxNum);
num = maxNum;
}
LogPrint (eLogDebug, "Destination: DatabaseSearchReply for ", key.ToBase64 (), " num=", num);
auto it = m_LeaseSetRequests.find (key);
if (it != m_LeaseSetRequests.end ())
+1 -1
View File
@@ -992,7 +992,7 @@ namespace transport
return;
}
auto size = bufbe16toh (buf->data () + 1);
if (size + 3 > (int)buf->size () || size > i2p::data::MAX_RI_BUFFER_SIZE + 1)
if (size < 1 || size + 3 > (int)buf->size () || size > i2p::data::MAX_RI_BUFFER_SIZE + 1)
{
LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed");
boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
+13 -1
View File
@@ -360,6 +360,12 @@ namespace data
void NetDbRequests::HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
{
const uint8_t * buf = msg->GetPayload ();
size_t payloadLen = msg->GetPayloadLength ();
if (payloadLen < 33)
{
LogPrint (eLogWarning, "NetDbReq: Database search reply is too short, ", payloadLen);
return;
}
std::string key;
size_t num = buf[32]; // num
if (CheckLogLevel (eLogInfo))
@@ -393,7 +399,13 @@ namespace data
{
LogPrint (eLogWarning, "NetDbReq: Too many peer hashes ", num, " in database search reply, Reduced to ", NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES);
num = NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES;
}
}
size_t maxNum = (payloadLen - 33)/32;
if (num > maxNum)
{
LogPrint (eLogWarning, "NetDbReq: Declared number of peer hashes ", num, " exceeds message size, reduced to ", maxNum);
num = maxNum;
}
if (isExploratory && !m_DiscoveredRouterHashes.empty ())
{
// request outstanding routers
+12
View File
@@ -36,6 +36,8 @@ namespace i2p
{
namespace data
{
const uint64_t MAX_RESEED_CONTENT_LENGTH = 128*1024*1024; // 128 MB, sanity cap for SU3 content length
const uint32_t MAX_RESEED_FILE_SIZE = 64*1024*1024; // 64 MB, sanity cap for a single file inside the SU3 zip
Reseeder::Reseeder()
{
@@ -231,6 +233,11 @@ namespace data
uint64_t contentLength;
s.read ((char *)&contentLength, 8); // content length
contentLength = be64toh (contentLength);
if (contentLength > MAX_RESEED_CONTENT_LENGTH)
{
LogPrint (eLogError, "Reseed: SU3 content length too large: ", contentLength);
return 0;
}
s.seekg (1, std::ios::cur); // unused
uint8_t fileType;
s.read ((char *)&fileType, 1); // file type
@@ -387,6 +394,11 @@ namespace data
LogPrint (eLogWarning, "Reseed: Unexpected size 0. Skipped");
continue;
}
if (compressedSize > MAX_RESEED_FILE_SIZE || uncompressedSize > MAX_RESEED_FILE_SIZE)
{
LogPrint (eLogError, "Reseed: SU3 file size too large, compressed=", compressedSize, " uncompressed=", uncompressedSize);
return numFiles;
}
uint8_t * compressed = new uint8_t[compressedSize];
s.read ((char *)compressed, compressedSize);
+9 -2
View File
@@ -450,8 +450,9 @@ namespace stream
bool Stream::ProcessOptions (uint16_t flags, Packet * packet)
{
const uint8_t * optionData = packet->GetOptionData ();
size_t optionOffset = optionData - packet->buf;
size_t optionSize = packet->GetOptionSize ();
if (optionSize > packet->len)
if (optionOffset > packet->len || optionSize > packet->len - optionOffset)
{
LogPrint (eLogInfo, "Streaming: Invalid option size ", optionSize, " Discarded");
return false;
@@ -626,8 +627,14 @@ namespace stream
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
{
if (!m_TransientVerifier && !m_RemoteIdentity)
{
LogPrint (eLogError, "Streaming: Signature included without remote identity");
return false;
}
auto signatureLen = m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : m_RemoteIdentity->GetSignatureLen ();
if (signatureLen > packet->GetLength ())
size_t optionOffset2 = optionData - packet->buf;
if (optionOffset2 > packet->len || signatureLen > packet->len - optionOffset2)
{
LogPrint (eLogError, "Streaming: Signature too big, ", signatureLen, " bytes");
return false;
+10 -7
View File
@@ -628,13 +628,16 @@ namespace client
if (!pos) // start of line
{
pos = line.find (" ");
pos++;
pos = line.find (" ", pos);
pos++;
auto nextpos = line.find (" ", pos);
m_OutPacket << line.substr (0, pos);
m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ());
m_OutPacket << line.substr (nextpos) << '\n';
if (pos != std::string::npos) pos = line.find (" ", pos + 1);
auto nextpos = (pos != std::string::npos) ? line.find (" ", pos + 1) : std::string::npos;
if (pos == std::string::npos || nextpos == std::string::npos)
m_OutPacket << line << '\n'; // malformed USER line, pass through unmodified
else
{
m_OutPacket << line.substr (0, pos + 1);
m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ());
m_OutPacket << line.substr (nextpos) << '\n';
}
}
else
m_OutPacket << line << '\n';
+11 -3
View File
@@ -1310,9 +1310,17 @@ namespace client
{
// get remote peer address
auto dest = stream->GetRemoteIdentity()->ToBase64 ();
memcpy (newSocket->m_StreamBuffer, dest.c_str (), dest.length ());
newSocket->m_StreamBuffer[dest.length ()] = '\n';
newSocket->HandleI2PReceive (boost::system::error_code (),dest.length () + 1); // we send identity like it has been received from stream
if (dest.length () + 1 > SAM_STREAM_BUFFER_SIZE)
{
LogPrint (eLogError, "SAM: Remote identity is too long ", dest.length ());
newSocket->TerminateClose ();
}
else
{
memcpy (newSocket->m_StreamBuffer, dest.c_str (), dest.length ());
newSocket->m_StreamBuffer[dest.length ()] = '\n';
newSocket->HandleI2PReceive (boost::system::error_code (),dest.length () + 1); // we send identity like it has been received from stream
}
}
else
newSocket->I2PReceive ();