diff --git a/Packet++/header/BgpLayer.h b/Packet++/header/BgpLayer.h index 00ced23bfe..22767e0ad4 100644 --- a/Packet++/header/BgpLayer.h +++ b/Packet++/header/BgpLayer.h @@ -113,6 +113,10 @@ namespace pcpp } void setBgpFields(size_t messageLen = 0); + + bool isValidExtendRange(int offsetInLayer, size_t numOfBytesToExtend) const; + + bool isValidShortenRange(int offsetInLayer, size_t numOfBytesToShorten) const; }; /// @class BgpOpenMessageLayer diff --git a/Packet++/src/BgpLayer.cpp b/Packet++/src/BgpLayer.cpp index 003dfb44ac..6485ad3d99 100644 --- a/Packet++/src/BgpLayer.cpp +++ b/Packet++/src/BgpLayer.cpp @@ -2,6 +2,7 @@ #include "Logger.h" #include "BgpLayer.h" +#include "Packet.h" #include "EndianPortable.h" #include "GeneralUtils.h" @@ -117,6 +118,50 @@ namespace pcpp } } + bool BgpLayer::isValidExtendRange(int offsetInLayer, size_t numOfBytesToExtend) const + { + int rawPacketLen = m_Packet->getRawPacket()->getRawDataLen(); + const uint8_t* rawPacketPtr = m_Packet->getRawPacket()->getRawData(); + + if (m_Data - rawPacketPtr + static_cast(offsetInLayer) > static_cast(rawPacketLen)) + { + PCPP_LOG_ERROR("Requested offset is larger than total packet length"); + return false; + } + + if (m_NextLayer != nullptr && static_cast(offsetInLayer) > m_NextLayer->getData() - m_Data) + { + PCPP_LOG_ERROR("Requested offset exceeds current layer's boundary"); + return false; + } + + return true; + } + + bool BgpLayer::isValidShortenRange(int offsetInLayer, size_t numOfBytesToShorten) const + { + int rawPacketLen = m_Packet->getRawPacket()->getRawDataLen(); + const uint8_t* rawPacketPtr = m_Packet->getRawPacket()->getRawData(); + + if (m_Data - rawPacketPtr + static_cast(offsetInLayer) + + static_cast(numOfBytesToShorten) > + static_cast(rawPacketLen)) + { + PCPP_LOG_ERROR("Requested number of bytes to shorten is larger than total packet length"); + return false; + } + + if (m_NextLayer != nullptr && + static_cast(offsetInLayer) + static_cast(numOfBytesToShorten) > + m_NextLayer->getData() - m_Data) + { + PCPP_LOG_ERROR("Requested number of bytes to shorten exceeds current layer's boundary"); + return false; + } + + return true; + } + // ~~~~~~~~~~~~~~~~~~~~ // BgpOpenMessageLayer // ~~~~~~~~~~~~~~~~~~~~ @@ -261,29 +306,34 @@ namespace pcpp uint8_t newOptionalParamsData[1500]; size_t newOptionalParamsDataLen = optionalParamsToByteArray(optionalParameters, newOptionalParamsData, 1500); size_t curOptionalParamsDataLen = getOptionalParametersLength(); + int offsetInLayer = sizeof(bgp_open_message); if (newOptionalParamsDataLen > curOptionalParamsDataLen) { - bool res = extendLayer(sizeof(bgp_open_message), newOptionalParamsDataLen - curOptionalParamsDataLen); - if (!res) + size_t numOfBytesToExtend = newOptionalParamsDataLen - curOptionalParamsDataLen; + + if (!isValidExtendRange(offsetInLayer, numOfBytesToExtend) || + !extendLayer(offsetInLayer, numOfBytesToExtend)) { PCPP_LOG_ERROR("Couldn't extend BGP open layer to include the additional optional parameters"); - return res; + return false; } } else if (newOptionalParamsDataLen < curOptionalParamsDataLen) { - bool res = shortenLayer(sizeof(bgp_open_message), curOptionalParamsDataLen - newOptionalParamsDataLen); - if (!res) + size_t numOfBytesToShorten = curOptionalParamsDataLen - newOptionalParamsDataLen; + + if (!isValidShortenRange(offsetInLayer, numOfBytesToShorten) || + !shortenLayer(offsetInLayer, numOfBytesToShorten)) { PCPP_LOG_ERROR("Couldn't shorten BGP open layer to set the right size of the optional parameters data"); - return res; + return false; } } if (newOptionalParamsDataLen > 0) { - memcpy(m_Data + sizeof(bgp_open_message), newOptionalParamsData, newOptionalParamsDataLen); + memcpy(m_Data + offsetInLayer, newOptionalParamsData, newOptionalParamsDataLen); } getOpenMsgHeader()->optionalParameterLength = (uint8_t)newOptionalParamsDataLen; @@ -565,32 +615,34 @@ namespace pcpp uint8_t newWithdrawnRoutesData[1500]; size_t newWithdrawnRoutesDataLen = prefixAndIPDataToByteArray(withdrawnRoutes, newWithdrawnRoutesData, 1500); size_t curWithdrawnRoutesDataLen = getWithdrawnRoutesLength(); + int offsetInLayer = sizeof(bgp_common_header) + sizeof(uint16_t); if (newWithdrawnRoutesDataLen > curWithdrawnRoutesDataLen) { - bool res = extendLayer(sizeof(bgp_common_header) + sizeof(uint16_t), - newWithdrawnRoutesDataLen - curWithdrawnRoutesDataLen); - if (!res) + size_t numOfBytesToExtend = newWithdrawnRoutesDataLen - curWithdrawnRoutesDataLen; + + if (!isValidExtendRange(offsetInLayer, numOfBytesToExtend) || + !extendLayer(offsetInLayer, numOfBytesToExtend)) { PCPP_LOG_ERROR("Couldn't extend BGP update layer to include the additional withdrawn routes"); - return res; + return false; } } else if (newWithdrawnRoutesDataLen < curWithdrawnRoutesDataLen) { - bool res = shortenLayer(sizeof(bgp_common_header) + sizeof(uint16_t), - curWithdrawnRoutesDataLen - newWithdrawnRoutesDataLen); - if (!res) + size_t numOfBytesToShorten = curWithdrawnRoutesDataLen - newWithdrawnRoutesDataLen; + + if (!isValidShortenRange(offsetInLayer, numOfBytesToShorten) || + !shortenLayer(offsetInLayer, numOfBytesToShorten)) { PCPP_LOG_ERROR("Couldn't shorten BGP update layer to set the right size of the withdrawn routes data"); - return res; + return false; } } if (newWithdrawnRoutesDataLen > 0) { - memcpy(m_Data + sizeof(bgp_common_header) + sizeof(uint16_t), newWithdrawnRoutesData, - newWithdrawnRoutesDataLen); + memcpy(m_Data + offsetInLayer, newWithdrawnRoutesData, newWithdrawnRoutesDataLen); } getBasicHeader()->length = @@ -642,32 +694,34 @@ namespace pcpp size_t newPathAttributesDataLen = pathAttributesToByteArray(pathAttributes, newPathAttributesData, 1500); size_t curPathAttributesDataLen = getPathAttributesLength(); size_t curWithdrawnRoutesDataLen = getWithdrawnRoutesLength(); + int offsetInLayer = sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + curWithdrawnRoutesDataLen; if (newPathAttributesDataLen > curPathAttributesDataLen) { - bool res = extendLayer(sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + curWithdrawnRoutesDataLen, - newPathAttributesDataLen - curPathAttributesDataLen); - if (!res) + size_t numOfBytesToExtend = newPathAttributesDataLen - curPathAttributesDataLen; + + if (!isValidExtendRange(offsetInLayer, numOfBytesToExtend) || + !extendLayer(offsetInLayer, numOfBytesToExtend)) { PCPP_LOG_ERROR("Couldn't extend BGP update layer to include the additional path attributes"); - return res; + return false; } } else if (newPathAttributesDataLen < curPathAttributesDataLen) { - bool res = shortenLayer(sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + curWithdrawnRoutesDataLen, - curPathAttributesDataLen - newPathAttributesDataLen); - if (!res) + size_t numOfBytesToShorten = curPathAttributesDataLen - newPathAttributesDataLen; + + if (!isValidShortenRange(offsetInLayer, numOfBytesToShorten) || + !shortenLayer(offsetInLayer, numOfBytesToShorten)) { PCPP_LOG_ERROR("Couldn't shorten BGP update layer to set the right size of the path attributes data"); - return res; + return false; } } if (newPathAttributesDataLen > 0) { - memcpy(m_Data + sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + curWithdrawnRoutesDataLen, - newPathAttributesData, newPathAttributesDataLen); + memcpy(m_Data + offsetInLayer, newPathAttributesData, newPathAttributesDataLen); } getBasicHeader()->length = @@ -741,35 +795,35 @@ namespace pcpp size_t curNlriDataLen = getNetworkLayerReachabilityInfoLength(); size_t curPathAttributesDataLen = getPathAttributesLength(); size_t curWithdrawnRoutesDataLen = getWithdrawnRoutesLength(); + int offsetInLayer = + sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + curWithdrawnRoutesDataLen + curPathAttributesDataLen; if (newNlriDataLen > curNlriDataLen) { - bool res = extendLayer(sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + curWithdrawnRoutesDataLen + - curPathAttributesDataLen, - newNlriDataLen - curNlriDataLen); - if (!res) + size_t numOfBytesToExtend = newNlriDataLen - curNlriDataLen; + + if (!isValidExtendRange(offsetInLayer, numOfBytesToExtend) || + !extendLayer(offsetInLayer, numOfBytesToExtend)) { PCPP_LOG_ERROR("Couldn't extend BGP update layer to include the additional NLRI data"); - return res; + return false; } } else if (newNlriDataLen < curNlriDataLen) { - bool res = shortenLayer(sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + curWithdrawnRoutesDataLen + - curPathAttributesDataLen, - curNlriDataLen - newNlriDataLen); - if (!res) + size_t numOfBytesToShorten = curNlriDataLen - newNlriDataLen; + + if (!isValidShortenRange(offsetInLayer, numOfBytesToShorten) || + !shortenLayer(offsetInLayer, numOfBytesToShorten)) { PCPP_LOG_ERROR("Couldn't shorten BGP update layer to set the right size of the NLRI data"); - return res; + return false; } } if (newNlriDataLen > 0) { - memcpy(m_Data + sizeof(bgp_common_header) + 2 * sizeof(uint16_t) + curWithdrawnRoutesDataLen + - curPathAttributesDataLen, - newNlriData, newNlriDataLen); + memcpy(m_Data + offsetInLayer, newNlriData, newNlriDataLen); } getBasicHeader()->length = htobe16(be16toh(getBasicHeader()->length) + newNlriDataLen - curNlriDataLen); @@ -866,30 +920,35 @@ namespace pcpp } size_t curNotificationDataLen = getNotificationDataLen(); + int offsetInLayer = sizeof(bgp_notification_message); if (newNotificationDataLen > curNotificationDataLen) { - bool res = extendLayer(sizeof(bgp_notification_message), newNotificationDataLen - curNotificationDataLen); - if (!res) + size_t numOfBytesToExtend = newNotificationDataLen - curNotificationDataLen; + + if (!isValidExtendRange(offsetInLayer, numOfBytesToExtend) || + !extendLayer(offsetInLayer, numOfBytesToExtend)) { PCPP_LOG_ERROR("Couldn't extend BGP notification layer to include the additional notification data"); - return res; + return false; } } else if (newNotificationDataLen < curNotificationDataLen) { - bool res = shortenLayer(sizeof(bgp_notification_message), curNotificationDataLen - newNotificationDataLen); - if (!res) + size_t numOfBytesToShorten = curNotificationDataLen - newNotificationDataLen; + + if (!isValidShortenRange(offsetInLayer, numOfBytesToShorten) || + !shortenLayer(offsetInLayer, numOfBytesToShorten)) { PCPP_LOG_ERROR( "Couldn't shorten BGP notification layer to set the right size of the notification data"); - return res; + return false; } } if (newNotificationDataLen > 0) { - memcpy(m_Data + sizeof(bgp_notification_message), newNotificationData, newNotificationDataLen); + memcpy(m_Data + offsetInLayer, newNotificationData, newNotificationDataLen); } getNotificationMsgHeader()->length = htobe16(sizeof(bgp_notification_message) + newNotificationDataLen); diff --git a/Packet++/src/Layer.cpp b/Packet++/src/Layer.cpp index ced53ab4ba..8e049b494a 100644 --- a/Packet++/src/Layer.cpp +++ b/Packet++/src/Layer.cpp @@ -63,12 +63,11 @@ namespace pcpp if (m_Packet == nullptr) { - if ((size_t)offsetInLayer > m_DataLen) + if (static_cast(offsetInLayer) > m_DataLen) { PCPP_LOG_ERROR("Requested offset is larger than data length"); return false; } - uint8_t* newData = new uint8_t[m_DataLen + numOfBytesToExtend]; memcpy(newData, m_Data, offsetInLayer); memcpy(newData + offsetInLayer + numOfBytesToExtend, m_Data + offsetInLayer, m_DataLen - offsetInLayer); @@ -91,12 +90,11 @@ namespace pcpp if (m_Packet == nullptr) { - if ((size_t)offsetInLayer >= m_DataLen) + if (static_cast(offsetInLayer) >= m_DataLen) { PCPP_LOG_ERROR("Requested offset is larger than data length"); return false; } - uint8_t* newData = new uint8_t[m_DataLen - numOfBytesToShorten]; memcpy(newData, m_Data, offsetInLayer); memcpy(newData + offsetInLayer, m_Data + offsetInLayer + numOfBytesToShorten, @@ -107,6 +105,12 @@ namespace pcpp return true; } + if (static_cast(offsetInLayer) + numOfBytesToShorten > m_DataLen) + { + PCPP_LOG_ERROR("Requested number of bytes to shorten is larger than data length"); + return false; + } + return m_Packet->shortenLayer(this, offsetInLayer, numOfBytesToShorten); } diff --git a/Packet++/src/Packet.cpp b/Packet++/src/Packet.cpp index a60ea2ce78..a837c18363 100644 --- a/Packet++/src/Packet.cpp +++ b/Packet++/src/Packet.cpp @@ -605,6 +605,12 @@ namespace pcpp bool passedExtendedLayer = false; for (Layer* curLayer = m_FirstLayer; curLayer != nullptr; curLayer = curLayer->getNextLayer()) { + if (dataPtr > m_RawPacket->getRawData() + m_RawPacket->getRawDataLen()) + { + PCPP_LOG_ERROR("Layer data pointer exceeds packet's boundary"); + return false; + } + // set the data ptr curLayer->m_Data = const_cast(dataPtr); @@ -656,6 +662,12 @@ namespace pcpp bool passedExtendedLayer = false; while (curLayer != nullptr) { + if (dataPtr > m_RawPacket->getRawData() + m_RawPacket->getRawDataLen()) + { + PCPP_LOG_ERROR("Layer data pointer exceeds packet's boundary"); + return false; + } + // set the data ptr curLayer->m_Data = const_cast(dataPtr); @@ -663,13 +675,16 @@ namespace pcpp if (curLayer->getPrevLayer() == layer) passedExtendedLayer = true; + size_t headerLen = curLayer->getHeaderLen(); + // change the data length only for layers who come before the shortened layer. For layers who come after, // data length isn't changed if (!passedExtendedLayer) curLayer->m_DataLen -= numOfBytesToShorten; // assuming header length of the layer that requested to be extended hasn't been enlarged yet - size_t headerLen = curLayer->getHeaderLen() - (curLayer == layer ? numOfBytesToShorten : 0); + // size_t headerLen = curLayer->getHeaderLen() - (curLayer == layer ? numOfBytesToShorten : 0); + headerLen -= (curLayer == layer ? numOfBytesToShorten : 0); dataPtr += headerLen; curLayer = curLayer->getNextLayer(); } diff --git a/Tests/Fuzzers/RegressionTests/regression_samples/047c56c3504ad04232497c903af06c0bc4b5c6f73927ad07cde79cfa28d94f8b b/Tests/Fuzzers/RegressionTests/regression_samples/047c56c3504ad04232497c903af06c0bc4b5c6f73927ad07cde79cfa28d94f8b new file mode 100644 index 0000000000..847818881e Binary files /dev/null and b/Tests/Fuzzers/RegressionTests/regression_samples/047c56c3504ad04232497c903af06c0bc4b5c6f73927ad07cde79cfa28d94f8b differ diff --git a/Tests/Fuzzers/RegressionTests/regression_samples/1eb005b8d62599b6561acf7e778f51603ccbc5ddf948c0b081617668bb56cee4 b/Tests/Fuzzers/RegressionTests/regression_samples/1eb005b8d62599b6561acf7e778f51603ccbc5ddf948c0b081617668bb56cee4 new file mode 100644 index 0000000000..56d868d1da Binary files /dev/null and b/Tests/Fuzzers/RegressionTests/regression_samples/1eb005b8d62599b6561acf7e778f51603ccbc5ddf948c0b081617668bb56cee4 differ diff --git a/Tests/Fuzzers/RegressionTests/regression_samples/39d92632b6a92f1c682c052febfbc74b0561536687be3b7ce7b9508e8b9726d6 b/Tests/Fuzzers/RegressionTests/regression_samples/39d92632b6a92f1c682c052febfbc74b0561536687be3b7ce7b9508e8b9726d6 new file mode 100644 index 0000000000..27eda11ae5 Binary files /dev/null and b/Tests/Fuzzers/RegressionTests/regression_samples/39d92632b6a92f1c682c052febfbc74b0561536687be3b7ce7b9508e8b9726d6 differ diff --git a/Tests/Fuzzers/RegressionTests/regression_samples/6f6fd63a9a6d8dd1a206eff00c915ed4b643034dad7e9986fd89a43244d6be97 b/Tests/Fuzzers/RegressionTests/regression_samples/6f6fd63a9a6d8dd1a206eff00c915ed4b643034dad7e9986fd89a43244d6be97 new file mode 100644 index 0000000000..b441d60d58 Binary files /dev/null and b/Tests/Fuzzers/RegressionTests/regression_samples/6f6fd63a9a6d8dd1a206eff00c915ed4b643034dad7e9986fd89a43244d6be97 differ diff --git a/Tests/Fuzzers/RegressionTests/regression_samples/6fda21d7ebaa0391434f17eecf25b1d7c58633f96b6906183c626cbdfc35b325 b/Tests/Fuzzers/RegressionTests/regression_samples/6fda21d7ebaa0391434f17eecf25b1d7c58633f96b6906183c626cbdfc35b325 new file mode 100644 index 0000000000..5386b26243 Binary files /dev/null and b/Tests/Fuzzers/RegressionTests/regression_samples/6fda21d7ebaa0391434f17eecf25b1d7c58633f96b6906183c626cbdfc35b325 differ diff --git a/Tests/Fuzzers/RegressionTests/regression_samples/a7a658b6e51576eafe7990dbc35c5bfff991d914c9ead914e26e3bfc3e88221c b/Tests/Fuzzers/RegressionTests/regression_samples/a7a658b6e51576eafe7990dbc35c5bfff991d914c9ead914e26e3bfc3e88221c new file mode 100644 index 0000000000..9cb865d467 Binary files /dev/null and b/Tests/Fuzzers/RegressionTests/regression_samples/a7a658b6e51576eafe7990dbc35c5bfff991d914c9ead914e26e3bfc3e88221c differ diff --git a/Tests/Fuzzers/RegressionTests/regression_samples/adb739b5829aacedbec6cf3969413997d23b6f2e3350ddf0b1cc3b4d1c335a95 b/Tests/Fuzzers/RegressionTests/regression_samples/adb739b5829aacedbec6cf3969413997d23b6f2e3350ddf0b1cc3b4d1c335a95 new file mode 100644 index 0000000000..b181304e86 Binary files /dev/null and b/Tests/Fuzzers/RegressionTests/regression_samples/adb739b5829aacedbec6cf3969413997d23b6f2e3350ddf0b1cc3b4d1c335a95 differ diff --git a/Tests/Fuzzers/RegressionTests/regression_samples/e0c0f8fea6e931d9671384a66f4e1ab02d84e27a5f091e9c7b1fce89d9c18837 b/Tests/Fuzzers/RegressionTests/regression_samples/e0c0f8fea6e931d9671384a66f4e1ab02d84e27a5f091e9c7b1fce89d9c18837 new file mode 100644 index 0000000000..eb6c488d74 Binary files /dev/null and b/Tests/Fuzzers/RegressionTests/regression_samples/e0c0f8fea6e931d9671384a66f4e1ab02d84e27a5f091e9c7b1fce89d9c18837 differ diff --git a/Tests/Fuzzers/RegressionTests/regression_samples/ec4b17a4e7b994548f03ae05d8d8924a515a236892959f3300e1c9e8a9c56ba7 b/Tests/Fuzzers/RegressionTests/regression_samples/ec4b17a4e7b994548f03ae05d8d8924a515a236892959f3300e1c9e8a9c56ba7 new file mode 100644 index 0000000000..3af4bececc Binary files /dev/null and b/Tests/Fuzzers/RegressionTests/regression_samples/ec4b17a4e7b994548f03ae05d8d8924a515a236892959f3300e1c9e8a9c56ba7 differ