From 768f6af14869f5e868d7f7b6d34e4b871cac2ada Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Wed, 6 Sep 2017 12:04:59 -0700 Subject: [PATCH] [pending-dataset] fix handling of large Delay Timer values (#2158) The Delay Timer value has a 32-bit range. However, the current Timer implementation does not support the full 32-bit range. This commit fixes the handling of large Delay Timer values by splitting the delay across multiple timer triggers. Credit to OSS-Fuzz. --- src/core/meshcop/dataset_manager.cpp | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index a143feb96..3455415ce 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -1112,7 +1112,15 @@ void PendingDatasetBase::StartDelayTimer(void) if ((delayTimer = static_cast(mNetwork.Get(Tlv::kDelayTimer))) != NULL) { - mDelayTimer.StartAt(mNetwork.GetUpdateTime(), delayTimer->GetDelayTimer()); + uint32_t delay = delayTimer->GetDelayTimer(); + + // the Timer implementation does not support the full 32 bit range + if (delay > Timer::kMaxDt) + { + delay = Timer::kMaxDt; + } + + mDelayTimer.StartAt(mNetwork.GetUpdateTime(), delay); otLogInfoMeshCoP(GetInstance(), "delay timer started"); } } @@ -1124,11 +1132,30 @@ void PendingDatasetBase::HandleDelayTimer(Timer &aTimer) void PendingDatasetBase::HandleDelayTimer(void) { + DelayTimerTlv *delayTimer; + + // if the Delay Timer value is larger than what our Timer implementation can handle, we have to compute + // the remainder and wait some more. + if ((delayTimer = static_cast(mNetwork.Get(Tlv::kDelayTimer))) != NULL) + { + uint32_t elapsed = mDelayTimer.GetFireTime() - mNetwork.GetUpdateTime(); + uint32_t delay = delayTimer->GetDelayTimer(); + + if (elapsed < delay) + { + mDelayTimer.StartAt(mDelayTimer.GetFireTime(), delay - elapsed); + ExitNow(); + } + } + otLogInfoMeshCoP(GetInstance(), "pending delay timer expired"); GetNetif().GetActiveDataset().Set(mNetwork); Clear(); + +exit: + return; } void PendingDatasetBase::HandleGet(void *aContext, otCoapHeader *aHeader, otMessage *aMessage,