mirror of
https://github.com/espressif/openthread.git
synced 2026-06-06 05:24:51 +00:00
[coap] fix null-pointer dereference on Block2 invalid requests (#13079)
This commit fixes a deterministic null-pointer dereference in CoapBase::ProcessBlock2Request when receiving a Block2 request with block number greater than 0 without a preceding active blockwise transfer. Previously, when mLastResponse was null, the option copying logic would unconditionally attempt to initialize the iterator with a dereferenced mLastResponse pointer (iterator.Init(*mLastResponse)), causing a segmentation fault crash. This fix inserts a VerifyOrExit check on mLastResponse inside ProcessBlock2Request. If mLastResponse is null, it returns the kErrorNoFrameReceived error code. In ProcessBlockwiseRequest, this is mapped to a 4.08 Request Entity Incomplete response, matching the spec-compliant error handling behavior of Block1. An automated reproduction and verification test case has also been added to tests/nexus/test_coap_block.cpp.
This commit is contained in:
+11
-1
@@ -978,10 +978,18 @@ Error CoapBase::ProcessBlockwiseRequest(Msg &aRxMsg, const Message::UriPathStrin
|
||||
case 2:
|
||||
if (resource.mTransmitHook != nullptr)
|
||||
{
|
||||
if ((error = ProcessBlock2Request(aRxMsg, resource)) != kErrorNone)
|
||||
switch (ProcessBlock2Request(aRxMsg, resource))
|
||||
{
|
||||
case kErrorNone:
|
||||
break;
|
||||
case kErrorNoFrameReceived:
|
||||
IgnoreError(SendResponse(kCodeRequestIncomplete, aRxMsg));
|
||||
error = kErrorDrop;
|
||||
break;
|
||||
default:
|
||||
IgnoreError(SendResponse(kCodeInternalError, aRxMsg));
|
||||
error = kErrorDrop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1268,6 +1276,8 @@ Error CoapBase::ProcessBlock2Request(Msg &aRxMsg, const ResourceBlockWise &aReso
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
VerifyOrExit(mLastResponse != nullptr, error = kErrorNoFrameReceived);
|
||||
|
||||
VerifyOrExit((response = NewMessage()) != nullptr, error = kErrorNoBufs);
|
||||
|
||||
SuccessOrExit(error = response->Init(kTypeAck, kCodeContent, aRxMsg.GetMessageId()));
|
||||
|
||||
@@ -38,9 +38,27 @@ namespace Nexus {
|
||||
|
||||
static otError TransmitHook(void *aContext, uint8_t *aBlock, uint32_t aPosition, uint16_t *aBlockLength, bool *aMore);
|
||||
|
||||
static bool sRequestHandlerCalled = false;
|
||||
static bool sReceiveHookCalled = false;
|
||||
static bool sTransmitHookCalled = false;
|
||||
static bool sRequestHandlerCalled = false;
|
||||
static bool sReceiveHookCalled = false;
|
||||
static bool sTransmitHookCalled = false;
|
||||
static bool sReproductionResponseReceived = false;
|
||||
static otCoapCode sReproductionResponseCode = OT_COAP_CODE_EMPTY;
|
||||
|
||||
static void HandleReproductionResponse(void *aContext,
|
||||
otMessage *aMessage,
|
||||
const otMessageInfo *aMessageInfo,
|
||||
otError aResult)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aContext);
|
||||
OT_UNUSED_VARIABLE(aMessageInfo);
|
||||
OT_UNUSED_VARIABLE(aResult);
|
||||
|
||||
sReproductionResponseReceived = true;
|
||||
if (aMessage != nullptr)
|
||||
{
|
||||
sReproductionResponseCode = otCoapMessageGetCode(aMessage);
|
||||
}
|
||||
}
|
||||
|
||||
static void HandleRequest(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
{
|
||||
@@ -212,6 +230,29 @@ void TestCoapBlock(void)
|
||||
VerifyOrQuit(sTransmitHookCalled); // Router should transmit blocks
|
||||
VerifyOrQuit(sReceiveHookCalled); // Leader should receive blocks
|
||||
|
||||
// Reproduction test case:
|
||||
// Router sends GET request with Block2 number 1 (NUM > 0) but without active transfer
|
||||
message = router.Get<Coap::ApplicationCoap>().NewMessage();
|
||||
VerifyOrQuit(message != nullptr);
|
||||
SuccessOrQuit(message->Init(Coap::kTypeConfirmable, Coap::kCodeGet));
|
||||
SuccessOrQuit(message->AppendUriPathOptions("test"));
|
||||
|
||||
blockInfo.mBlockNumber = 1;
|
||||
blockInfo.mBlockSzx = Coap::kBlockSzx16;
|
||||
blockInfo.mMoreBlocks = false;
|
||||
SuccessOrQuit(message->AppendBlockOption(Coap::kOptionBlock2, blockInfo));
|
||||
|
||||
sReproductionResponseReceived = false;
|
||||
sReproductionResponseCode = OT_COAP_CODE_EMPTY;
|
||||
|
||||
SuccessOrQuit(router.Get<Coap::ApplicationCoap>().SendMessageWithResponseHandlerSeparateParams(
|
||||
*message, messageInfo, nullptr, &HandleReproductionResponse, nullptr, nullptr, nullptr));
|
||||
|
||||
nexus.AdvanceTime(5 * 1000);
|
||||
|
||||
VerifyOrQuit(sReproductionResponseReceived);
|
||||
VerifyOrQuit(sReproductionResponseCode == OT_COAP_CODE_REQUEST_INCOMPLETE);
|
||||
|
||||
leader.Get<Coap::ApplicationCoap>().RemoveBlockWiseResource(resource);
|
||||
IgnoreError(leader.Get<Coap::ApplicationCoap>().Stop());
|
||||
IgnoreError(router.Get<Coap::ApplicationCoap>().Stop());
|
||||
|
||||
Reference in New Issue
Block a user