Merge pull request #2490 from jpk68/size-checks

libi2pd: add missing size checks
This commit is contained in:
orignal
2026-08-17 20:11:27 -04:00
committed by GitHub
6 changed files with 69 additions and 9 deletions
+10
View File
@@ -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)
{
+10
View File
@@ -465,7 +465,17 @@ namespace garlic
void ECIESX25519AEADRatchetSession::HandleNextKey (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& 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;
+15
View File
@@ -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
+5
View File
@@ -944,6 +944,11 @@ namespace data
void NetDb::HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> 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 ())
{
+22 -9
View File
@@ -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 ())
+7
View File
@@ -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)
{