Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 59 additions & 12 deletions Packet++/src/Layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,20 @@ namespace pcpp
return false;
}

if (m_Packet == nullptr)
if (offsetInLayer < 0)
{
PCPP_LOG_ERROR("Requested offset is negative");
return false;
}

if (static_cast<size_t>(offsetInLayer) > m_DataLen)
{
if ((size_t)offsetInLayer > m_DataLen)
{
PCPP_LOG_ERROR("Requested offset is larger than data length");
return false;
}
PCPP_LOG_ERROR("Requested offset is larger than data length");
return false;
}

if (m_Packet == nullptr)
{
uint8_t* newData = new uint8_t[m_DataLen + numOfBytesToExtend];
memcpy(newData, m_Data, offsetInLayer);
memcpy(newData + offsetInLayer + numOfBytesToExtend, m_Data + offsetInLayer, m_DataLen - offsetInLayer);
Expand All @@ -78,6 +84,19 @@ namespace pcpp
return true;
}

if (m_Data - m_Packet->m_RawPacket->getRawData() + static_cast<ptrdiff_t>(offsetInLayer) >
static_cast<ptrdiff_t>(m_Packet->m_RawPacket->getRawDataLen()))
{
PCPP_LOG_ERROR("Requested offset is larger than total packet length");
return false;
}

if (m_NextLayer != nullptr && static_cast<ptrdiff_t>(offsetInLayer) > m_NextLayer->m_Data - m_Data)
{
PCPP_LOG_ERROR("Requested offset exceeds current layer's boundary");
return false;
}
Comment on lines +87 to +98
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these checks needed? All we need to check is that offsetInLayer is within the layer's boundary, which means it is smaller than or equal to m_DataLen. Why do we need to compare it to the whole packet or involve m_NextLayer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Length-related errors introduced during layer shortening can result in the same sanitizer issues when the layer is later extended


return m_Packet->extendLayer(this, offsetInLayer, numOfBytesToExtend);
}

Expand All @@ -89,14 +108,20 @@ namespace pcpp
return false;
}

if (m_Packet == nullptr)
if (offsetInLayer < 0)
{
PCPP_LOG_ERROR("Requested offset is negative");
return false;
}

if (static_cast<size_t>(offsetInLayer) >= m_DataLen)
{
if ((size_t)offsetInLayer >= m_DataLen)
{
PCPP_LOG_ERROR("Requested offset is larger than data length");
return false;
}
PCPP_LOG_ERROR("Requested offset is larger than data length");
return false;
}

if (m_Packet == nullptr)
{
uint8_t* newData = new uint8_t[m_DataLen - numOfBytesToShorten];
memcpy(newData, m_Data, offsetInLayer);
memcpy(newData + offsetInLayer, m_Data + offsetInLayer + numOfBytesToShorten,
Expand All @@ -107,6 +132,28 @@ namespace pcpp
return true;
}

if (static_cast<size_t>(offsetInLayer) + numOfBytesToShorten > m_DataLen)
{
PCPP_LOG_ERROR("Requested number of bytes to shorten is larger than data length");
return false;
}

if (m_Data - m_Packet->m_RawPacket->getRawData() + static_cast<ptrdiff_t>(offsetInLayer) +
static_cast<ptrdiff_t>(numOfBytesToShorten) >
static_cast<ptrdiff_t>(m_Packet->m_RawPacket->getRawDataLen()))
{
PCPP_LOG_ERROR("Requested number of bytes to shorten is larger than total packet length");
return false;
}

if (m_NextLayer != nullptr &&
static_cast<ptrdiff_t>(offsetInLayer) + static_cast<ptrdiff_t>(numOfBytesToShorten) >
m_NextLayer->m_Data - m_Data)
{
PCPP_LOG_ERROR("Requested number of bytes to shorten exceeds current layer's boundary");
return false;
}
Comment on lines +141 to +155
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I analyzed several malformed packets that triggered sanitizer errors, and identified some of the root causes.

When iterating over layers during recalculation after shortening a layer, the pointer to the next layer is computed as dataPtr (current layer pointer) + headerLen. For BGP, headerLen corresponds either to the length field of the bgp_common_header structure or to the actual layer length m_DataLen — whichever is smaller. In malformed packets, the header length may not match the actual layer length, or may contain arbitrary values (possibly due to previous incorrect shortening or extension), which can lead to several issues

  • numOfBytesToShorten is subtracted from the m_DataLen of all layers preceding the shortened one. If numOfBytesToShorten is greater than m_DataLen, this causes m_DataLen to wrap around, resulting in an extremely large value. In such cases, when calculating headerLen, the header field is selected, which may be invalid, leading to out-of-bounds memory access.

  • In the shortened layer, numOfBytesToShorten is first subtracted from m_DataLen, then again from headerLen. BgpLayer::getHeaderLen() returns new m_DataLen as the smallest, which results in numOfBytesToShorten being subtracted twice, potentially producing a negative value.

I believe headerLen calculation could be moved before updating the current layer’s m_DataLen. However, this would not resolve the issue described in the next point.

  • Malformed packets may also contain nested BGP layers, which is inherently invalid and can trigger the errors described earlier.


return m_Packet->shortenLayer(this, offsetInLayer, numOfBytesToShorten);
}

Expand Down
5 changes: 5 additions & 0 deletions Packet++/src/Packet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,9 @@ namespace pcpp
// assuming header length of the layer that requested to be extended hasn't been enlarged yet
size_t headerLen = curLayer->getHeaderLen() + (curLayer == layer ? numOfBytesToExtend : 0);
dataPtr += headerLen;

if (dataPtr > m_RawPacket->getRawData() + m_RawPacket->getRawDataLen())
break;
Comment on lines +613 to +614
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can such a thing happen? curLayer->getHeaderLen() should never exceed the packet data, unless we have a bug in one of the layers

}

return true;
Expand Down Expand Up @@ -660,6 +663,8 @@ namespace pcpp
// 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);
dataPtr += headerLen;
if (dataPtr > m_RawPacket->getRawData() + m_RawPacket->getRawDataLen())
break;
Comment on lines +666 to +667
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

curLayer = curLayer->getNextLayer();
}

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading