mirror of
https://github.com/espressif/openthread.git
synced 2026-09-25 02:17:39 +00:00
[mle] validate router ID bounds in router-id lookups (#13539)
Two router-id lookups indexed their backing array by a Router ID from a received message before checking it against `kMaxRouterId`: 1. `RouterIdMask::IsAllocated(aRouterId)` read `mMask[aRouterId / 8]` (an 8-byte array). When `HandleAddressSolicitResponse()` passed `GetLeaderId()`, the Leader Router ID copied verbatim from a received Leader Data TLV, router IDs 64-255 read up to 24 bytes past `mMask`. 2. `RouterTable::RouterIdMap::IsAllocated(aRouterId)` read `mIndexes[aRouterId]` (a 63-byte array for IDs 0..62). When an MLE Advertisement had a Source Address decoding to router ID 63 (e.g. `0xFC00`), `RoleTransitioner::DecideWhetherToDowngrade()` checked allocation of the neighbor ID and read 1 byte past `mIndexes`. This commit updates both `RouterIdMask::IsAllocated()` and `RouterTable::RouterIdMap::IsAllocated()` to verify that the router ID is within `[0, kMaxRouterId]` before indexing the array. It also adds unit tests in `test_mle.cpp` validating bounds handling.
This commit is contained in:
@@ -666,7 +666,10 @@ public:
|
||||
* @retval TRUE If the Router ID bit is set in the mask.
|
||||
* @retval FALSE If the Router ID bit is not set in the mask.
|
||||
*/
|
||||
bool IsAllocated(uint8_t aRouterId) const { return (mMask[aRouterId / 8] & MaskFor(aRouterId)) != 0; }
|
||||
bool IsAllocated(uint8_t aRouterId) const
|
||||
{
|
||||
return (aRouterId <= kMaxRouterId) && ((mMask[aRouterId / 8] & MaskFor(aRouterId)) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a given Router ID in the mask.
|
||||
|
||||
@@ -465,7 +465,10 @@ private:
|
||||
// remaining reuse delay time (in seconds).
|
||||
|
||||
RouterIdMap(void) { Clear(); }
|
||||
bool IsAllocated(uint8_t aRouterId) const { return (mIndexes[aRouterId] & kAllocatedFlag); }
|
||||
bool IsAllocated(uint8_t aRouterId) const
|
||||
{
|
||||
return (aRouterId <= Mle::kMaxRouterId) && ((mIndexes[aRouterId] & kAllocatedFlag) != 0);
|
||||
}
|
||||
uint8_t GetIndex(uint8_t aRouterId) const { return (mIndexes[aRouterId] & kIndexMask); }
|
||||
void SetIndex(uint8_t aRouterId, uint8_t aIndex) { mIndexes[aRouterId] = kAllocatedFlag | aIndex; }
|
||||
bool CanAllocate(uint8_t aRouterId) const { return (mIndexes[aRouterId] == 0); }
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "thread/mle_tlvs.hpp"
|
||||
#include "thread/mle_types.hpp"
|
||||
#include "thread/network_data_leader.hpp"
|
||||
#include "thread/router_table.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
@@ -849,15 +850,67 @@ void TestLeaderWeightCalculation(void)
|
||||
|
||||
#endif // #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
|
||||
|
||||
void TestRouterIdMask(void)
|
||||
{
|
||||
Mle::RouterIdMask mask;
|
||||
|
||||
mask.Clear();
|
||||
VerifyOrQuit(mask.IsValid());
|
||||
VerifyOrQuit(mask.DetermineAllocatedCount() == 0);
|
||||
|
||||
for (uint16_t routerId = 0; routerId <= 255; routerId++)
|
||||
{
|
||||
VerifyOrQuit(!mask.IsAllocated(static_cast<uint8_t>(routerId)));
|
||||
}
|
||||
|
||||
mask.Add(0);
|
||||
mask.Add(10);
|
||||
mask.Add(Mle::kMaxRouterId);
|
||||
|
||||
VerifyOrQuit(mask.IsAllocated(0));
|
||||
VerifyOrQuit(mask.IsAllocated(10));
|
||||
VerifyOrQuit(mask.IsAllocated(Mle::kMaxRouterId));
|
||||
VerifyOrQuit(!mask.IsAllocated(1));
|
||||
VerifyOrQuit(!mask.IsAllocated(61));
|
||||
|
||||
for (uint16_t routerId = Mle::kMaxRouterId + 1; routerId <= 255; routerId++)
|
||||
{
|
||||
VerifyOrQuit(!mask.IsAllocated(static_cast<uint8_t>(routerId)));
|
||||
}
|
||||
|
||||
mask.Remove(10);
|
||||
VerifyOrQuit(!mask.IsAllocated(10));
|
||||
|
||||
printf("TestRouterIdMask passed\n");
|
||||
}
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
void TestRouterTableRouterIdBounds(void)
|
||||
{
|
||||
Instance *instance = static_cast<Instance *>(testInitInstance());
|
||||
RouterTable &routerTable = instance->Get<RouterTable>();
|
||||
|
||||
for (uint16_t routerId = 0; routerId <= 255; routerId++)
|
||||
{
|
||||
VerifyOrQuit(!routerTable.IsAllocated(static_cast<uint8_t>(routerId)));
|
||||
}
|
||||
|
||||
testFreeInstance(instance);
|
||||
printf("TestRouterTableRouterIdBounds passed\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::TestDeviceMode();
|
||||
ot::TestRouterIdMask();
|
||||
ot::UnitTester::TestChildIdResponseNetworkDataHandling();
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
ot::UnitTester::TestTxChallengeTable();
|
||||
ot::TestRouterTableRouterIdBounds();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
|
||||
|
||||
Reference in New Issue
Block a user