[lowpan] validate received fragment headers (#2038)

Credit to OSS-Fuzz.
This commit is contained in:
Jonathan Hui
2017-07-27 21:43:36 -07:00
committed by GitHub
parent 7a37d079d5
commit 0d356d11bd
3 changed files with 63 additions and 27 deletions
+21
View File
@@ -1175,5 +1175,26 @@ exit:
return error;
}
otError FragmentHeader::Init(const uint8_t *aFrame, uint8_t aFrameLength)
{
otError error = OT_ERROR_PARSE;
VerifyOrExit(aFrameLength >= sizeof(mDispatchSize) + sizeof(mTag));
memcpy(&mDispatchSize, aFrame, sizeof(mDispatchSize) + sizeof(mTag));
aFrame += sizeof(mDispatchSize) + sizeof(mTag);
aFrameLength -= sizeof(mDispatchSize) + sizeof(mTag);
if (IsOffsetPresent())
{
VerifyOrExit(aFrameLength >= sizeof(mOffset));
mOffset = *aFrame++;
}
error = OT_ERROR_NONE;
exit:
return error;
}
} // namespace Lowpan
} // namespace ot
+24 -6
View File
@@ -397,6 +397,18 @@ public:
*/
void Init(void) { mDispatchSize = HostSwap16(kDispatch); }
/**
* This method initializes the fragment header from a frame @p aFrame.
*
* @param[in] aFrame The pointer to the frame.
* @param[in] aFrameLength The length of the frame.
*
* @retval OT_ERROR_NONE Fragment Header initialized successfully.
* @retval OT_ERROR_PARSE Fragment header could not be initialized from @p aFrame (e.g., frame not long enough).
*
*/
otError Init(const uint8_t *aFrame, uint8_t aFrameLength);
/**
* This method indicates whether or not the header is a Fragment Header.
*
@@ -412,9 +424,15 @@ public:
* @returns The Fragment Header length in bytes.
*
*/
uint8_t GetHeaderLength(void) {
return (HostSwap16(mDispatchSize) & kOffset) ? sizeof(*this) : sizeof(*this) - sizeof(mOffset);
}
uint8_t GetHeaderLength(void) const { return IsOffsetPresent() ? sizeof(*this) : sizeof(*this) - sizeof(mOffset); }
/**
* This method indicates whether or not the Offset field is present.
*
* @returns TRUE if the Offset field is present, FALSE otherwise.
*
*/
bool IsOffsetPresent(void) const { return (HostSwap16(mDispatchSize) & kOffset) != 0; }
/**
* This method returns the Datagram Size value.
@@ -422,7 +440,7 @@ public:
* @returns The Datagram Size value.
*
*/
uint16_t GetDatagramSize(void) { return HostSwap16(mDispatchSize) & kSizeMask; }
uint16_t GetDatagramSize(void) const { return HostSwap16(mDispatchSize) & kSizeMask; }
/**
* This method sets the Datagram Size value.
@@ -440,7 +458,7 @@ public:
* @returns The Datagram Tag value.
*
*/
uint16_t GetDatagramTag(void) { return HostSwap16(mTag); }
uint16_t GetDatagramTag(void) const { return HostSwap16(mTag); }
/**
* This method sets the Datagram Tag value.
@@ -456,7 +474,7 @@ public:
* @returns The Datagram Offset value.
*
*/
uint16_t GetDatagramOffset(void) { return (HostSwap16(mDispatchSize) & kOffset) ? static_cast<uint16_t>(mOffset) * 8 : 0; }
uint16_t GetDatagramOffset(void) const { return IsOffsetPresent() ? static_cast<uint16_t>(mOffset) * 8 : 0; }
/**
* This method sets the Datagram Offset value.
+18 -21
View File
@@ -1998,34 +1998,34 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
{
ThreadNetif &netif = GetNetif();
otError error = OT_ERROR_NONE;
Lowpan::FragmentHeader *fragmentHeader = reinterpret_cast<Lowpan::FragmentHeader *>(aFrame);
uint16_t datagramLength = fragmentHeader->GetDatagramSize();
uint16_t datagramTag = fragmentHeader->GetDatagramTag();
Lowpan::FragmentHeader fragmentHeader;
Message *message = NULL;
int headerLength;
if (fragmentHeader->GetDatagramOffset() == 0)
{
aFrame += fragmentHeader->GetHeaderLength();
aFrameLength -= fragmentHeader->GetHeaderLength();
// Check the fragment header
VerifyOrExit(fragmentHeader.Init(aFrame, aFrameLength) == OT_ERROR_NONE, error = OT_ERROR_DROP);
aFrame += fragmentHeader.GetHeaderLength();
aFrameLength -= fragmentHeader.GetHeaderLength();
if (fragmentHeader.GetDatagramOffset() == 0)
{
VerifyOrExit((message = GetInstance().mMessagePool.New(Message::kTypeIp6, 0)) != NULL,
error = OT_ERROR_NO_BUFS);
message->SetLinkSecurityEnabled(aMessageInfo.mLinkSecurity);
message->SetPanId(aMessageInfo.mPanId);
message->AddRss(aMessageInfo.mRss);
headerLength = netif.GetLowpan().Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength,
datagramLength);
fragmentHeader.GetDatagramSize());
VerifyOrExit(headerLength > 0, error = OT_ERROR_PARSE);
aFrame += headerLength;
aFrameLength -= static_cast<uint8_t>(headerLength);
VerifyOrExit(datagramLength >= message->GetOffset() + aFrameLength, error = OT_ERROR_PARSE);
VerifyOrExit(fragmentHeader.GetDatagramSize() >= message->GetOffset() + aFrameLength, error = OT_ERROR_PARSE);
SuccessOrExit(error = message->SetLength(datagramLength));
SuccessOrExit(error = message->SetLength(fragmentHeader.GetDatagramSize()));
message->SetDatagramTag(datagramTag);
message->SetDatagramTag(fragmentHeader.GetDatagramTag());
message->SetTimeout(kReassemblyTimeout);
// copy Fragment
@@ -2053,16 +2053,13 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
}
else
{
aFrame += fragmentHeader->GetHeaderLength();
aFrameLength -= fragmentHeader->GetHeaderLength();
for (message = mReassemblyList.GetHead(); message; message = message->GetNext())
{
// Security Check: only consider reassembly buffers that had the same Security Enabled setting.
if (message->GetLength() == datagramLength &&
message->GetDatagramTag() == datagramTag &&
message->GetOffset() == fragmentHeader->GetDatagramOffset() &&
message->GetOffset() + aFrameLength <= datagramLength &&
if (message->GetLength() == fragmentHeader.GetDatagramSize() &&
message->GetDatagramTag() == fragmentHeader.GetDatagramTag() &&
message->GetOffset() == fragmentHeader.GetDatagramOffset() &&
message->GetOffset() + aFrameLength <= fragmentHeader.GetDatagramSize() &&
message->IsLinkSecurityEnabled() == aMessageInfo.mLinkSecurity)
{
break;
@@ -2116,9 +2113,9 @@ exit:
aFrameLength,
aMacSource.ToString(srcStringBuffer, sizeof(srcStringBuffer)),
aMacDest.ToString(dstStringBuffer, sizeof(dstStringBuffer)),
datagramTag,
fragmentHeader->GetDatagramOffset(),
datagramLength,
fragmentHeader.GetDatagramTag(),
fragmentHeader.GetDatagramOffset(),
fragmentHeader.GetDatagramSize(),
aMessageInfo.mLinkSecurity ? "yes" : "no"
);