mirror of
https://github.com/espressif/openthread.git
synced 2026-09-05 16:50:05 +00:00
[mac] enhance command ID validation and parsing for 2015-spec frames (#11787)
The treatment of the Command ID field in a MAC command frame is dependent on the IEEE 802.15.4 version. In the 2015 specification, it is part of the encrypted payload, while in earlier versions, it is part of the unencrypted MAC header. The `FindPayloadIndex()` method correctly accounts for both cases. This commit enhances the frame parsing and validation logic to account for this difference. - `ValidatePsdu()` is updated to ensure the frame is long enough to contain the Command ID when validating a 2015-version frame. - `GetCommandId()` is updated to validate the presence of the Command ID field before access, fixing a potential out-of-bounds read. - A new `IsMacCommand()` helper method is introduced to improve code clarity and replace direct frame type checks.
This commit is contained in:
@@ -274,6 +274,22 @@ Error Frame::ValidatePsdu(void) const
|
||||
uint8_t index = FindPayloadIndex();
|
||||
|
||||
VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
|
||||
|
||||
if (IsMacCommand() && IsVersion2015())
|
||||
{
|
||||
// The treatment of the Command ID field in a MAC command frame
|
||||
// is version-dependent. In the 2015 spec, it is part of the
|
||||
// encrypted payload, while in earlier versions, it is part of
|
||||
// the MAC header.
|
||||
//
|
||||
// `FindPayloadIndex()` accounts for this difference and returns
|
||||
// the starting index of the payload. To correctly validate a
|
||||
// 2015 frame, we must ensure it is long enough to contain the
|
||||
// Command ID, so we include its size in the length check.
|
||||
|
||||
index += kCommandIdSize;
|
||||
}
|
||||
|
||||
VerifyOrExit((index + GetFooterLength()) <= mLength, error = kErrorParse);
|
||||
|
||||
exit:
|
||||
@@ -826,7 +842,18 @@ Error Frame::GetCommandId(uint8_t &aCommandId) const
|
||||
|
||||
VerifyOrExit(index != kInvalidIndex, error = kErrorParse);
|
||||
|
||||
aCommandId = mPsdu[IsVersion2015() ? index : (index - 1)];
|
||||
// The treatment of the Command ID field in a MAC command frame
|
||||
// is version-dependent. In the 2015 spec, it is part of the
|
||||
// encrypted payload, while in earlier versions, it is part of
|
||||
// the MAC header. `FindPayloadIndex() accounts for both cases.
|
||||
|
||||
if (!IsVersion2015())
|
||||
{
|
||||
index -= kCommandIdSize;
|
||||
}
|
||||
|
||||
VerifyOrExit(index + kCommandIdSize + GetFooterLength() <= mLength, error = kErrorParse);
|
||||
aCommandId = mPsdu[index];
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -837,7 +864,7 @@ bool Frame::IsDataRequestCommand(void) const
|
||||
bool isDataRequest = false;
|
||||
uint8_t commandId;
|
||||
|
||||
VerifyOrExit(GetType() == kTypeMacCmd);
|
||||
VerifyOrExit(IsMacCommand());
|
||||
SuccessOrExit(GetCommandId(commandId));
|
||||
isDataRequest = (commandId == kMacCmdDataRequest);
|
||||
|
||||
@@ -1078,8 +1105,17 @@ uint8_t Frame::FindPayloadIndex(void) const
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
|
||||
|
||||
if (!IsVersion2015() && (GetFrameControlField() & kFcfFrameTypeMask) == kTypeMacCmd)
|
||||
if (IsMacCommand() && !IsVersion2015())
|
||||
{
|
||||
// The treatment of the Command ID field in a MAC command frame
|
||||
// is version-dependent. In IEEE 802.15.4-2015, it is part of
|
||||
// the payload and therefore encrypted. In earlier versions, it
|
||||
// is part of the MAC header and not encrypted.
|
||||
//
|
||||
// This adjusts the index to point to the start of the payload
|
||||
// for pre-2015 frames. The `GetCommandId()` method also
|
||||
// accounts for this version-specific difference.
|
||||
|
||||
index += kCommandIdSize;
|
||||
}
|
||||
|
||||
|
||||
@@ -178,6 +178,14 @@ public:
|
||||
*/
|
||||
bool IsAck(void) const { return GetType() == kTypeAck; }
|
||||
|
||||
/**
|
||||
* Returns whether the frame is a MAC Command frame.
|
||||
*
|
||||
* @retval TRUE If this is a MAC Command frame.
|
||||
* @retval FALSE If this is not a MAC Command Frame.
|
||||
*/
|
||||
bool IsMacCommand(void) const { return GetType() == kTypeMacCmd; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
|
||||
/**
|
||||
* This method returns whether the frame is an IEEE 802.15.4 Wake-up frame.
|
||||
|
||||
Reference in New Issue
Block a user