diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 7bd332e3..2dee646c 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -355,6 +355,11 @@ namespace client void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len) { + if (len < I2NP_HEADER_SIZE) + { + LogPrint (eLogWarning, "Destination: I2NP message is too short ", len); + return; + } I2NPMessageType typeID = (I2NPMessageType)(buf[I2NP_HEADER_TYPEID_OFFSET]); uint32_t msgID = bufbe32toh (buf + I2NP_HEADER_MSGID_OFFSET); LeaseSetDestination::HandleCloveI2NPMessage (typeID, buf + I2NP_HEADER_SIZE, @@ -1205,6 +1210,11 @@ namespace client void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len, i2p::garlic::ECIESX25519AEADRatchetSession * from) { + if (len < 14) // 4-byte length prefix, then fromPort/toPort/protocol read at offsets up to 9 past it + { + LogPrint (eLogWarning, "Destination: Data message is too short ", len); + return; + } uint32_t length = bufbe32toh (buf); if(length > len - 4) { diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index c582f86f..7f3b0cfc 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -465,7 +465,17 @@ namespace garlic void ECIESX25519AEADRatchetSession::HandleNextKey (const uint8_t * buf, size_t len, const std::shared_ptr& receiveTagset) { + if (len < 3) + { + LogPrint (eLogWarning, "Garlic: Next key block is too short ", len); + return; + } uint8_t flag = buf[0]; buf++; // flag + if ((flag & ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG) && len < 35) + { + LogPrint (eLogWarning, "Garlic: Next key block with key is too short ", len); + return; + } if (flag & ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG) { if (!m_SendForwardKey || !m_NextSendRatchet) return; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index a0963c94..c36cca5a 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -1007,6 +1007,11 @@ namespace garlic void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len, ECIESX25519AEADRatchetSession * from) { + if (!len) + { + LogPrint (eLogError, "Garlic: Clove is empty"); + return; + } const uint8_t * buf1 = buf; uint8_t flag = buf[0]; buf++; // flag GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); @@ -1014,12 +1019,22 @@ namespace garlic { case eGarlicDeliveryTypeDestination: LogPrint (eLogDebug, "Garlic: Type destination"); + if (len < 33) // flag + 32-byte destination hash + { + LogPrint (eLogError, "Garlic: Message is too short"); + break; + } buf += 32; // TODO: check destination [[fallthrough]]; // no break here case eGarlicDeliveryTypeLocal: { LogPrint (eLogDebug, "Garlic: Type local"); + if ((size_t)(buf - buf1) + 9 > len) // typeid(1) + msgID(4) + expiration(4) + { + LogPrint (eLogError, "Garlic: Message is too short"); + break; + } I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid uint32_t msgID = bufbe32toh (buf); buf += 4; // msgID buf += 4; // expiration diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 48ad68c1..db60b19f 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -944,6 +944,11 @@ namespace data void NetDb::HandleDatabaseLookupMsg (std::shared_ptr msg) { const uint8_t * buf = msg->GetPayload (); + if (msg->GetPayloadLength () < 65) + { + LogPrint (eLogWarning, "NetDb: DatabaseLookup message is too short ", msg->GetPayloadLength ()); + return; + } IdentHash ident (buf); if (ident.IsZero ()) { diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index f535ec07..61014dd9 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -1865,9 +1865,12 @@ namespace transport m_IsDataReceived = true; break; case eSSU2BlkPeerTest: - LogPrint (eLogDebug, "SSU2: PeerTest msg=", (int)buf[offset], " code=", (int)buf[offset+1]); + if (size >= 2) + LogPrint (eLogDebug, "SSU2: PeerTest msg=", (int)buf[offset], " code=", (int)buf[offset+1]); + else + LogPrint (eLogWarning, "SSU2: PeerTest block is too short ", size); HandlePeerTest (buf + offset, size); - if (buf[offset] < 5) + if (size >= 1 && buf[offset] < 5) m_IsDataReceived = true; break; case eSSU2BlkNextNonce: @@ -1899,14 +1902,22 @@ namespace transport break; case eSSU2BlkRelayTag: LogPrint (eLogDebug, "SSU2: RelayTag"); - m_RelayTag = bufbe32toh (buf + offset); + if (size >= 4) + m_RelayTag = bufbe32toh (buf + offset); + else + LogPrint (eLogWarning, "SSU2: RelayTag block is too short ", size); break; case eSSU2BlkNewToken: { LogPrint (eLogDebug, "SSU2: New token"); - uint64_t token; - memcpy (&token, buf + offset + 4, 8); - m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, bufbe32toh (buf + offset)); + if (size >= 12) + { + uint64_t token; + memcpy (&token, buf + offset + 4, 8); + m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, bufbe32toh (buf + offset)); + } + else + LogPrint (eLogWarning, "SSU2: NewToken block is too short ", size); break; } case eSSU2BlkPathChallenge: @@ -1916,7 +1927,7 @@ namespace transport case eSSU2BlkPathResponse: { LogPrint (eLogDebug, "SSU2: Path response"); - if (m_PathChallenge) + if (size >= 8 && m_PathChallenge) { if (buf64toh (buf + offset) == m_PathChallenge->first) { @@ -1940,6 +1951,7 @@ namespace transport void SSU2Session::HandleDateTime (const uint8_t * buf, size_t len) { + if (len < 4) return; int64_t offset = (int64_t)i2p::util::GetSecondsSinceEpoch () - (int64_t)bufbe32toh (buf); switch (m_State) { @@ -2503,6 +2515,7 @@ namespace transport { case 1: // Bob from Alice { + if (len < 13) return; auto session = m_Server.GetRandomPeerTestSession ((buf[12] == 6) ? i2p::data::RouterInfo::eSSU2V4 : i2p::data::RouterInfo::eSSU2V6, GetRemoteIdentity ()->GetIdentHash ()); if (session) // session with Charlie @@ -2552,7 +2565,7 @@ namespace transport case 2: // Charlie from Bob { // sign with Charlie's key - if (len < offset + 9) return; + if (len < offset + 10) return; uint8_t asz = buf[offset + 9]; size_t l = asz + 10 + i2p::context.GetIdentity ()->GetSignatureLen (); if (len < offset + l) return; @@ -2666,7 +2679,7 @@ namespace transport if (GetRouterStatus () == eRouterStatusUnknown) SetTestingState (true); auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie - if (r && len >= offset + 9) + if (r && len >= offset + 10) { uint8_t asz = buf[offset + 9]; if (len < offset + asz + 10 + r->GetIdentity ()->GetSignatureLen ()) diff --git a/libi2pd/TunnelEndpoint.cpp b/libi2pd/TunnelEndpoint.cpp index 22b62984..c8b31343 100644 --- a/libi2pd/TunnelEndpoint.cpp +++ b/libi2pd/TunnelEndpoint.cpp @@ -95,6 +95,13 @@ namespace tunnel uint16_t size = bufbe16toh (fragment); fragment += 2; + if (fragment + size > decrypted + TUNNEL_DATA_ENCRYPTED_SIZE) + { + LogPrint (eLogError, "TunnelMessage: Fragment size ", size, " exceeds tunnel data message, message dropped"); + m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr; + return; + } + // handle fragment if (isFollowOnFragment) {