[mle] reject `ChildIdResponse` if included dataset TLV is ill-formed (#7599)
This commit contains the following changes:
- The `Dataset` method which reads the dataset TLVs from a message
is renamed to `ReadFromMessage()` and after reading the TLVs, it
also checks that the TLVs in the Dataset are valid (well-formed).
- The `Active/PendingDataset::Save()` methods are updated to return
error in the case the parsed dataset is not well-formed.
- The `Mle::HandleChildIdRequest()` rejects the response if the
included dataset is not well-formed. This ensures that device
stays detached if it cannot accept and save the dataset it gets
from the parent candidate.
diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp
index b2fea0d..b6496f2 100644
--- a/src/core/meshcop/dataset.cpp
+++ b/src/core/meshcop/dataset.cpp
@@ -435,13 +435,15 @@
return SetTlv(aTlv.GetType(), aTlv.GetValue(), aTlv.GetLength());
}
-Error Dataset::Set(const Message &aMessage, uint16_t aOffset, uint8_t aLength)
+Error Dataset::ReadFromMessage(const Message &aMessage, uint16_t aOffset, uint8_t aLength)
{
- Error error = kErrorInvalidArgs;
+ Error error = kErrorParse;
SuccessOrExit(aMessage.Read(aOffset, mTlvs, aLength));
mLength = aLength;
+ VerifyOrExit(IsValid(), error = kErrorParse);
+
mUpdateTime = TimerMilli::GetNow();
error = kErrorNone;
diff --git a/src/core/meshcop/dataset.hpp b/src/core/meshcop/dataset.hpp
index 0e2f080..353f1af 100644
--- a/src/core/meshcop/dataset.hpp
+++ b/src/core/meshcop/dataset.hpp
@@ -782,17 +782,17 @@
}
/**
- * This method sets the Dataset using TLVs stored in a message buffer.
+ * This method reads the Dataset from a given message and checks that it is well-formed and valid.
*
- * @param[in] aMessage The message buffer.
- * @param[in] aOffset The message buffer offset where the dataset starts.
- * @param[in] aLength The TLVs length in the message buffer in bytes.
+ * @param[in] aMessage The message to read from.
+ * @param[in] aOffset The offset in @p aMessage to start reading the Dataset TLVs.
+ * @param[in] aLength The dataset length in bytes.
*
- * @retval kErrorNone Successfully set the Dataset.
- * @retval kErrorInvalidArgs The values of @p aOffset and @p aLength are not valid for @p aMessage.
+ * @retval kErrorNone Successfully read and validated the Dataset.
+ * @retval kErrorParse Could not read or parse the dataset from @p aMessage.
*
*/
- Error Set(const Message &aMessage, uint16_t aOffset, uint8_t aLength);
+ Error ReadFromMessage(const Message &aMessage, uint16_t aOffset, uint8_t aLength);
/**
* This method sets the Dataset using an existing Dataset.
diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp
index b1e46eb..1c00ea8 100644
--- a/src/core/meshcop/dataset_manager.cpp
+++ b/src/core/meshcop/dataset_manager.cpp
@@ -140,7 +140,7 @@
if (isNetworkkeyUpdated || compare > 0)
{
- IgnoreError(mLocal.Save(aDataset));
+ SuccessOrExit(error = mLocal.Save(aDataset));
#if OPENTHREAD_FTD
Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
@@ -690,9 +690,9 @@
Error error = kErrorNone;
Dataset dataset;
- SuccessOrExit(error = dataset.Set(aMessage, aOffset, aLength));
+ SuccessOrExit(error = dataset.ReadFromMessage(aMessage, aOffset, aLength));
dataset.SetTimestamp(Dataset::kActive, aTimestamp);
- IgnoreError(DatasetManager::Save(dataset));
+ error = DatasetManager::Save(dataset);
exit:
return error;
@@ -777,9 +777,9 @@
Error error = kErrorNone;
Dataset dataset;
- SuccessOrExit(error = dataset.Set(aMessage, aOffset, aLength));
+ SuccessOrExit(error = dataset.ReadFromMessage(aMessage, aOffset, aLength));
dataset.SetTimestamp(Dataset::kPending, aTimestamp);
- IgnoreError(DatasetManager::Save(dataset));
+ SuccessOrExit(error = DatasetManager::Save(dataset));
StartDelayTimer();
exit:
diff --git a/src/core/meshcop/dataset_manager.hpp b/src/core/meshcop/dataset_manager.hpp
index 75ee9f7..ec7c316 100644
--- a/src/core/meshcop/dataset_manager.hpp
+++ b/src/core/meshcop/dataset_manager.hpp
@@ -272,6 +272,9 @@
* @param[in] aOffset The offset where the Operational Dataset begins.
* @param[in] aLength The length of the Operational Dataset.
*
+ * @retval kErrorNone Successfully parsed the Dataset from the @p aMessage and saved it.
+ * @retval kErrorParse Could not parse the Dataset from @p aMessage.
+ *
*/
Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength);
@@ -419,6 +422,9 @@
* @param[in] aOffset The offset where the Operational Dataset begins.
* @param[in] aLength The length of the Operational Dataset.
*
+ * @retval kErrorNone Successfully parsed the Dataset from the @p aMessage and saved it.
+ * @retval kErrorParse Could not parse the Dataset from @p aMessage.
+ *
*/
Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength);
diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp
index cff7228..467328e 100644
--- a/src/core/thread/mle.cpp
+++ b/src/core/thread/mle.cpp
@@ -3696,7 +3696,8 @@
if (Tlv::FindTlvOffset(aMessage, Tlv::kActiveDataset, offset) == kErrorNone)
{
IgnoreError(aMessage.Read(offset, tlv));
- IgnoreError(Get<MeshCoP::ActiveDataset>().Save(timestamp, aMessage, offset + sizeof(tlv), tlv.GetLength()));
+ SuccessOrExit(
+ error = Get<MeshCoP::ActiveDataset>().Save(timestamp, aMessage, offset + sizeof(tlv), tlv.GetLength()));
}
break;