[mac] fix infinite loop in GetHeaderIe() and GetThreadIe() (#12598)

This commit addresses a timeout issue reported by a fuzzer when
processing MAC frames with malformed Header IEs.

Specifically:
- In `FindPayloadIndex()`, added validation to ensure the returned
  index does not exceed `kMaxPsduSize` (254). If the index exceeds
  this value, it now returns `kInvalidIndex` (255). This prevents
  callers from experiencing wrap-around issues when they cast the
  result to `uint8_t`.
- In `GetHeaderIe()` and `GetThreadIe()`, changed the `index` and
  `payloadIndex` variables from `uint8_t` to `uint16_t`. This
  ensures that any increment during the loop does not wrap around,
  which was a primary cause of the infinite loop.
- Updated the loop condition from `index <= payloadIndex` to
  `index < payloadIndex`. Since `payloadIndex` points to the start
  of the payload (the byte after the last Header IE), a strict
  less-than comparison is correct and prevents the loop from
  attempting to parse the payload itself as a Header IE.

These changes ensure robust parsing of IEEE 802.15.4 frames, even
when they contain unexpected or malformed Information Elements.
This commit is contained in:
Jonathan Hui
2026-03-03 13:44:48 -06:00
committed by GitHub
parent 43d0022bd8
commit 26bcc07b31
+7 -7
View File
@@ -1121,7 +1121,7 @@ uint8_t Frame::FindPayloadIndex(void) const
}
exit:
return static_cast<uint8_t>(index);
return (index <= kMaxPsduSize) ? static_cast<uint8_t>(index) : kInvalidIndex;
}
const uint8_t *Frame::GetPayload(void) const
@@ -1153,8 +1153,8 @@ exit:
const uint8_t *Frame::GetHeaderIe(uint8_t aIeId) const
{
uint8_t index = FindHeaderIeIndex();
uint8_t payloadIndex = FindPayloadIndex();
uint16_t index = FindHeaderIeIndex();
uint16_t payloadIndex = FindPayloadIndex();
const uint8_t *header = nullptr;
// `FindPayloadIndex()` verifies that Header IE(s) in frame (if present)
@@ -1162,7 +1162,7 @@ const uint8_t *Frame::GetHeaderIe(uint8_t aIeId) const
VerifyOrExit((index != kInvalidIndex) && (payloadIndex != kInvalidIndex));
while (index <= payloadIndex)
while (index < payloadIndex)
{
const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);
@@ -1183,15 +1183,15 @@ exit:
OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
const uint8_t *Frame::GetThreadIe(uint8_t aSubType) const
{
uint8_t index = FindHeaderIeIndex();
uint8_t payloadIndex = FindPayloadIndex();
uint16_t index = FindHeaderIeIndex();
uint16_t payloadIndex = FindPayloadIndex();
const uint8_t *header = nullptr;
// `FindPayloadIndex()` verifies that Header IE(s) in frame (if present)
// are well-formed.
VerifyOrExit((index != kInvalidIndex) && (payloadIndex != kInvalidIndex));
while (index <= payloadIndex)
while (index < payloadIndex)
{
const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);