diff --git a/src/common/network/PacketBuffer.cpp b/src/common/network/PacketBuffer.cpp index 95f5e35b..52b44317 100644 --- a/src/common/network/PacketBuffer.cpp +++ b/src/common/network/PacketBuffer.cpp @@ -60,6 +60,11 @@ bool PacketBuffer::decode(const uint8_t* data, uint8_t** message, uint32_t* outL uint8_t blockCnt = data[9U]; Fragment* frag = new Fragment(); + frag->compressedSize = 0U; + frag->size = 0U; + frag->blockSize = 0U; + frag->blockId = 0U; + frag->data = nullptr; // if this is the first block store sizes and initialize temp buffer if (curBlock == 0U) { @@ -81,10 +86,7 @@ bool PacketBuffer::decode(const uint8_t* data, uint8_t** message, uint32_t* outL // scope is intentional { frag->blockId = curBlock; - if (frag->size < FRAG_BLOCK_SIZE) - frag->data = new uint8_t[FRAG_BLOCK_SIZE + 1U]; - else - frag->data = new uint8_t[frag->size + 1U]; + frag->data = new uint8_t[FRAG_BLOCK_SIZE + 1U]; ::memcpy(frag->data, data + FRAG_HDR_SIZE, FRAG_BLOCK_SIZE); // Utils::dump(1U, "PacketBuffer::decode(), Block Payload", frag->data, FRAG_BLOCK_SIZE); @@ -96,37 +98,66 @@ bool PacketBuffer::decode(const uint8_t* data, uint8_t** message, uint32_t* outL // do we have all the blocks? if (fragments.size() == blockCnt + 1U) { fragments.lock(false); - if (fragments[0] == nullptr) { + auto firstIt = fragments.find(0U); + if (firstIt == fragments.end() || firstIt->second == nullptr) { LogError(LOG_NET, "%s, Packet Fragment, error missing block 0? Packet dropped.", m_name); fragments.unlock(); clear(); return false; } - if (fragments[0]->size == 0U) { + Fragment* firstFrag = firstIt->second; + + if (firstFrag->size == 0U) { LogError(LOG_NET, "%s, Packet Fragment, error missing size information", m_name); fragments.unlock(); clear(); return false; } - if (fragments[0]->compressedSize == 0U) { + if (firstFrag->compressedSize == 0U) { LogError(LOG_NET, "%s, Packet Fragment, error missing compressed size information", m_name); fragments.unlock(); clear(); return false; } - uint32_t compressedLen = fragments[0]->compressedSize; - uint32_t len = fragments[0]->size; + uint32_t compressedLen = firstFrag->compressedSize; + uint32_t len = firstFrag->size; + + if (compressedLen > MAX_FRAGMENT_SIZE || len > MAX_FRAGMENT_SIZE) { + LogError(LOG_NET, "%s, Packet Fragment, error invalid packet length metadata", m_name); + fragments.unlock(); + clear(); + return false; + } + + // Reassembly buffer must be compressed length, not uncompressed length. + DECLARE_UINT8_ARRAY(buffer, compressedLen + 1U); + ::memset(buffer, 0x00U, compressedLen + 1U); - DECLARE_UINT8_ARRAY(buffer, len + 1U); if (fragments.size() == 1U) { - ::memcpy(buffer, fragments[0U]->data, len); + uint32_t copyLen = (compressedLen > FRAG_BLOCK_SIZE) ? FRAG_BLOCK_SIZE : compressedLen; + ::memcpy(buffer, firstFrag->data, copyLen); } else { - for (uint8_t i = 0U; i < fragments.size(); i++) { + for (uint8_t i = 0U; i <= blockCnt; i++) { + auto it = fragments.find(i); + if (it == fragments.end() || it->second == nullptr || it->second->data == nullptr) { + LogError(LOG_NET, "%s, Packet Fragment, error missing block %u, packet dropped", m_name, i); + fragments.unlock(); + clear(); + return false; + } + uint32_t offs = i * FRAG_BLOCK_SIZE; - ::memcpy(buffer + offs, fragments[i]->data, FRAG_BLOCK_SIZE); + if (offs >= compressedLen) + break; + + uint32_t copyLen = FRAG_BLOCK_SIZE; + if (offs + FRAG_BLOCK_SIZE > compressedLen) + copyLen = compressedLen - offs; + + ::memcpy(buffer + offs, it->second->data, copyLen); } } diff --git a/src/fne/network/MetadataNetwork.cpp b/src/fne/network/MetadataNetwork.cpp index a5fdf5a6..a64b82ea 100644 --- a/src/fne/network/MetadataNetwork.cpp +++ b/src/fne/network/MetadataNetwork.cpp @@ -1042,6 +1042,11 @@ void MetadataNetwork::taskNetworkRx(NetPacketRequest* req) // scope intentional { + if (req->length < FRAG_SIZE) { + LogWarning(LOG_REPL, "PEER %u Remote EKC, Key Update, ignoring short data phase frame (%u bytes)", peerId, req->length); + break; + } + DECLARE_UINT8_ARRAY(rawPayload, req->length); ::memcpy(rawPayload, req->buffer, req->length);