mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2026-07-10 13:29:45 -04:00
stream_buffer: reject required-space overflow at runtime in message send
Defect: xStreamBufferSend() and xStreamBufferSendFromISR() on a message buffer can perform an out-of-bounds write when the required-space computation for a message overflows size_t and configASSERT() is compiled out. Root cause: for message buffers the code computes xRequiredSpace = xDataLengthBytes + sbBYTES_TO_STORE_MESSAGE_LENGTH and guards it only with configASSERT( xRequiredSpace > xDataLengthBytes ). When the addition wraps size_t, the wrapped (smaller) xRequiredSpace passes the subsequent space checks and the send proceeds to copy xDataLengthBytes bytes, writing past the buffer. With asserts disabled there is no guard at all. Fix: add a runtime check that returns 0 (nothing sent) when xRequiredSpace <= xDataLengthBytes, in both the task and FromISR send paths, so a wrapping message length is rejected regardless of the configASSERT() setting. A host regression test kept outside this repository demonstrates the fault before the change and its absence afterwards (red then green).
This commit is contained in:
parent
5b6c2f29db
commit
bc0572329a
1 changed files with 43 additions and 6 deletions
|
|
@ -820,10 +820,12 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
|
|||
TickType_t xTicksToWait )
|
||||
{
|
||||
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
|
||||
size_t xReturn, xSpace = 0;
|
||||
size_t xReturn = 0;
|
||||
size_t xSpace = 0;
|
||||
size_t xRequiredSpace = xDataLengthBytes;
|
||||
TimeOut_t xTimeOut;
|
||||
size_t xMaxReportedSpace = 0;
|
||||
BaseType_t xSendAllowed = pdTRUE;
|
||||
|
||||
traceENTER_xStreamBufferSend( xStreamBuffer, pvTxData, xDataLengthBytes, xTicksToWait );
|
||||
|
||||
|
|
@ -845,9 +847,22 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
|
|||
/* Overflow? */
|
||||
configASSERT( xRequiredSpace > xDataLengthBytes );
|
||||
|
||||
/* Enforce the overflow check at runtime as well, so that a message
|
||||
* length whose required-space addition wraps size_t is rejected even
|
||||
* when configASSERT() is compiled out. Without this the wrapped
|
||||
* (smaller) xRequiredSpace would pass the space checks below and the
|
||||
* send would proceed to copy xDataLengthBytes bytes, causing an
|
||||
* out-of-bounds write. Reject the send instead: leave xReturn 0, skip
|
||||
* blocking and the write, and exit through the single return below. */
|
||||
if( xRequiredSpace <= xDataLengthBytes )
|
||||
{
|
||||
xSendAllowed = pdFALSE;
|
||||
xTicksToWait = ( TickType_t ) 0;
|
||||
}
|
||||
|
||||
/* If this is a message buffer then it must be possible to write the
|
||||
* whole message. */
|
||||
if( xRequiredSpace > xMaxReportedSpace )
|
||||
else if( xRequiredSpace > xMaxReportedSpace )
|
||||
{
|
||||
/* The message would not fit even if the entire buffer was empty,
|
||||
* so don't wait for space. */
|
||||
|
|
@ -921,7 +936,10 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
|
|||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
|
||||
if( xSendAllowed == pdTRUE )
|
||||
{
|
||||
xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
|
||||
}
|
||||
|
||||
if( xReturn > ( size_t ) 0 )
|
||||
{
|
||||
|
|
@ -955,8 +973,10 @@ size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
|
|||
BaseType_t * const pxHigherPriorityTaskWoken )
|
||||
{
|
||||
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
|
||||
size_t xReturn, xSpace;
|
||||
size_t xReturn = 0;
|
||||
size_t xSpace;
|
||||
size_t xRequiredSpace = xDataLengthBytes;
|
||||
BaseType_t xSendAllowed = pdTRUE;
|
||||
|
||||
traceENTER_xStreamBufferSendFromISR( xStreamBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken );
|
||||
|
||||
|
|
@ -973,14 +993,31 @@ size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
|
|||
|
||||
/* Overflow? */
|
||||
configASSERT( xRequiredSpace > xDataLengthBytes );
|
||||
|
||||
/* Enforce the overflow check at runtime as well (see xStreamBufferSend),
|
||||
* so a wrapping message length is rejected when configASSERT() is
|
||||
* compiled out rather than proceeding to an out-of-bounds write. Reject
|
||||
* the send by leaving xReturn 0 and skipping the write below, so the
|
||||
* function still exits through its single return. */
|
||||
if( xRequiredSpace <= xDataLengthBytes )
|
||||
{
|
||||
xSendAllowed = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
|
||||
xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
|
||||
if( xSendAllowed == pdTRUE )
|
||||
{
|
||||
xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
|
||||
xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
|
||||
}
|
||||
|
||||
if( xReturn > ( size_t ) 0 )
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue