From 26bcc07b316cadabf5486e7a96605d7aebd25e07 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Tue, 3 Mar 2026 13:44:48 -0600 Subject: [PATCH] [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. --- src/core/mac/mac_frame.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/mac/mac_frame.cpp b/src/core/mac/mac_frame.cpp index 05805ae82..17d2a1bdd 100644 --- a/src/core/mac/mac_frame.cpp +++ b/src/core/mac/mac_frame.cpp @@ -1121,7 +1121,7 @@ uint8_t Frame::FindPayloadIndex(void) const } exit: - return static_cast(index); + return (index <= kMaxPsduSize) ? static_cast(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(&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(&mPsdu[index]);