[dataset] validate TLVs when applying configuration (#2680)

Credit to OSS-Fuzz.
This commit is contained in:
Jonathan Hui
2018-05-06 19:13:57 -07:00
committed by GitHub
parent 664d9832e5
commit 3af0bda8b7
7 changed files with 96 additions and 6 deletions
+18
View File
@@ -60,6 +60,21 @@ void Dataset::Clear(void)
mLength = 0;
}
bool Dataset::IsValid(void) const
{
bool rval = true;
const Tlv *cur = reinterpret_cast<const Tlv *>(mTlvs);
const Tlv *end = reinterpret_cast<const Tlv *>(mTlvs + mLength);
for (; cur < end; cur = cur->GetNext())
{
VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end && Tlv::IsValid(*cur), rval = false);
}
exit:
return rval;
}
Tlv *Dataset::Get(Tlv::Type aType)
{
Tlv *cur = reinterpret_cast<Tlv *>(mTlvs);
@@ -523,6 +538,8 @@ otError Dataset::ApplyConfiguration(Instance &aInstance) const
const Tlv * cur = reinterpret_cast<const Tlv *>(mTlvs);
const Tlv * end = reinterpret_cast<const Tlv *>(mTlvs + mLength);
VerifyOrExit(IsValid(), error = OT_ERROR_PARSE);
while (cur < end)
{
switch (cur->GetType())
@@ -578,6 +595,7 @@ otError Dataset::ApplyConfiguration(Instance &aInstance) const
{
const NetworkNameTlv *name = static_cast<const NetworkNameTlv *>(cur);
otNetworkName networkName;
memcpy(networkName.m8, name->GetNetworkName(), name->GetLength());
networkName.m8[name->GetLength()] = '\0';
+10 -1
View File
@@ -69,6 +69,14 @@ public:
*/
void Clear(void);
/**
* This method indicates whether or not the dataset appears to be well-formed.
*
* @returns TRUE if the dataset appears to be well-formed, FALSE otherwise.
*
*/
bool IsValid(void) const;
/**
* This method returns a pointer to the TLV.
*
@@ -216,7 +224,8 @@ public:
*
* @param[in] aInstance A reference to the OpenThread instance.
*
* @retval OT_ERROR_NONE Successfully applied configuration.
* @retval OT_ERROR_NONE Successfully applied configuration.
* @retval OT_ERROR_PARSE The dataset has at least one TLV with invalid format.
*
*/
otError ApplyConfiguration(Instance &aInstance) const;
+6 -2
View File
@@ -146,8 +146,9 @@ void DatasetManager::HandleDetach(void)
Restore();
}
void DatasetManager::Set(const Dataset &aDataset)
otError DatasetManager::Set(const Dataset &aDataset)
{
otError error = OT_ERROR_NONE;
const Timestamp *timestamp;
int compare;
@@ -160,7 +161,7 @@ void DatasetManager::Set(const Dataset &aDataset)
if (mLocal.GetType() == Tlv::kActiveTimestamp)
{
aDataset.ApplyConfiguration(GetInstance());
SuccessOrExit(error = aDataset.ApplyConfiguration(GetInstance()));
}
}
@@ -182,6 +183,9 @@ void DatasetManager::Set(const Dataset &aDataset)
{
mTimer.Start(1000);
}
exit:
return error;
}
void DatasetManager::HandleTimer(void)
+6 -2
View File
@@ -116,7 +116,8 @@ public:
/**
* This method applies the Active or Pending Dataset to the Thread interface.
*
* @retval OT_ERROR_NONE Successfully applied configuration.
* @retval OT_ERROR_NONE Successfully applied configuration.
* @retval OT_ERROR_PARSE The dataset has at least one TLV with invalid format.
*
*/
otError ApplyConfiguration(void) const;
@@ -157,8 +158,11 @@ protected:
*
* @param[in] aDataset The Operational Dataset.
*
* @retval OT_ERROR_NONE Successfully applied configuration.
* @retval OT_ERROR_PARSE The dataset has at least one TLV with invalid format.
*
*/
void Set(const Dataset &aDataset);
otError Set(const Dataset &aDataset);
/**
* This method sets the Operational Dataset for the partition.
+1 -1
View File
@@ -300,7 +300,7 @@ otError DatasetManager::Set(Coap::Header &aHeader, Message &aMessage, const Ip6:
offset += sizeof(Tlv) + data.tlv.GetLength();
}
Set(dataset);
VerifyOrExit(Set(dataset) == OT_ERROR_NONE, state = StateTlv::kReject);
netif.GetNetworkDataLeader().IncrementVersion();
netif.GetNetworkDataLeader().IncrementStableVersion();
}
+45
View File
@@ -36,6 +36,51 @@
namespace ot {
namespace MeshCoP {
bool Tlv::IsValid(const Tlv &aTlv)
{
bool rval = true;
switch (aTlv.GetType())
{
case Tlv::kChannel:
rval = static_cast<const ChannelTlv &>(aTlv).IsValid();
break;
case Tlv::kPanId:
rval = static_cast<const PanIdTlv &>(aTlv).IsValid();
break;
case Tlv::kExtendedPanId:
rval = static_cast<const ExtendedPanIdTlv &>(aTlv).IsValid();
break;
case Tlv::kNetworkName:
rval = static_cast<const NetworkNameTlv &>(aTlv).IsValid();
break;
case Tlv::kNetworkMasterKey:
rval = static_cast<const NetworkMasterKeyTlv &>(aTlv).IsValid();
break;
case Tlv::kPSKc:
rval = static_cast<const PSKcTlv &>(aTlv).IsValid();
break;
case Tlv::kMeshLocalPrefix:
rval = static_cast<const MeshLocalPrefixTlv &>(aTlv).IsValid();
break;
case Tlv::kSecurityPolicy:
rval = static_cast<const SecurityPolicyTlv &>(aTlv).IsValid();
break;
default:
break;
}
return rval;
}
bool SteeringDataTlv::IsCleared(void) const
{
bool rval = true;
+10
View File
@@ -166,6 +166,16 @@ public:
return ot::Tlv::GetValueOffset(aMessage, static_cast<uint8_t>(aType), aOffset, aLength);
}
/**
* This static method indicates whether a TLV appears to be well-formed.
*
* @param[in] aTlv A reference to the TLV.
*
* @returns TRUE if the TLV appears to be well-formed, FALSE otherwise.
*
*/
static bool IsValid(const Tlv &aTlv);
} OT_TOOL_PACKED_END;
/**