From 3af0bda8b79ed775d3b243bfb794ebdeb51378e2 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Sun, 6 May 2018 19:13:57 -0700 Subject: [PATCH] [dataset] validate TLVs when applying configuration (#2680) Credit to OSS-Fuzz. --- src/core/meshcop/dataset.cpp | 18 ++++++++++ src/core/meshcop/dataset.hpp | 11 +++++- src/core/meshcop/dataset_manager.cpp | 8 +++-- src/core/meshcop/dataset_manager.hpp | 8 +++-- src/core/meshcop/dataset_manager_ftd.cpp | 2 +- src/core/meshcop/meshcop_tlvs.cpp | 45 ++++++++++++++++++++++++ src/core/meshcop/meshcop_tlvs.hpp | 10 ++++++ 7 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp index 5c7888de0..df02c5cd5 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -60,6 +60,21 @@ void Dataset::Clear(void) mLength = 0; } +bool Dataset::IsValid(void) const +{ + bool rval = true; + const Tlv *cur = reinterpret_cast(mTlvs); + const Tlv *end = reinterpret_cast(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(mTlvs); @@ -523,6 +538,8 @@ otError Dataset::ApplyConfiguration(Instance &aInstance) const const Tlv * cur = reinterpret_cast(mTlvs); const Tlv * end = reinterpret_cast(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(cur); otNetworkName networkName; + memcpy(networkName.m8, name->GetNetworkName(), name->GetLength()); networkName.m8[name->GetLength()] = '\0'; diff --git a/src/core/meshcop/dataset.hpp b/src/core/meshcop/dataset.hpp index 7c937307c..f2c1c903e 100644 --- a/src/core/meshcop/dataset.hpp +++ b/src/core/meshcop/dataset.hpp @@ -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; diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index 8560217f6..b2fb3bb3a 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -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) diff --git a/src/core/meshcop/dataset_manager.hpp b/src/core/meshcop/dataset_manager.hpp index d136aeec3..b5e096d29 100644 --- a/src/core/meshcop/dataset_manager.hpp +++ b/src/core/meshcop/dataset_manager.hpp @@ -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. diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp index 38d42f676..64ca6077c 100644 --- a/src/core/meshcop/dataset_manager_ftd.cpp +++ b/src/core/meshcop/dataset_manager_ftd.cpp @@ -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(); } diff --git a/src/core/meshcop/meshcop_tlvs.cpp b/src/core/meshcop/meshcop_tlvs.cpp index 515b1aa08..46d095db8 100644 --- a/src/core/meshcop/meshcop_tlvs.cpp +++ b/src/core/meshcop/meshcop_tlvs.cpp @@ -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(aTlv).IsValid(); + break; + + case Tlv::kPanId: + rval = static_cast(aTlv).IsValid(); + break; + + case Tlv::kExtendedPanId: + rval = static_cast(aTlv).IsValid(); + break; + + case Tlv::kNetworkName: + rval = static_cast(aTlv).IsValid(); + break; + + case Tlv::kNetworkMasterKey: + rval = static_cast(aTlv).IsValid(); + break; + + case Tlv::kPSKc: + rval = static_cast(aTlv).IsValid(); + break; + + case Tlv::kMeshLocalPrefix: + rval = static_cast(aTlv).IsValid(); + break; + + case Tlv::kSecurityPolicy: + rval = static_cast(aTlv).IsValid(); + break; + + default: + break; + } + + return rval; +} + bool SteeringDataTlv::IsCleared(void) const { bool rval = true; diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index d41ca829a..508d58373 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -166,6 +166,16 @@ public: return ot::Tlv::GetValueOffset(aMessage, static_cast(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; /**