This commit is contained in:
Aniruddha Kanhere 2026-08-26 19:41:38 +00:00 • committed by GitHub
commit 48b6ed8e48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 137 additions and 62 deletions

View file

@ -637,7 +637,11 @@ void vPortGenerateSimulatedInterrupt( uint32_t ulInterruptNumber )
void vPortGenerateSimulatedInterruptFromWindowsThread( uint32_t ulInterruptNumber ) void vPortGenerateSimulatedInterruptFromWindowsThread( uint32_t ulInterruptNumber )
{ {
if( xPortRunning == pdTRUE ) /* Reject out-of-range interrupt numbers before the shift below. Mirrors the
* bounds check the task-context sibling vPortGenerateSimulatedInterrupt already
* performs: ( 1UL << ulInterruptNumber ) is undefined when ulInterruptNumber is
* >= portMAX_INTERRUPTS (the width of ulPendingInterrupts). */
if( ( xPortRunning == pdTRUE ) && ( ulInterruptNumber < portMAX_INTERRUPTS ) )
{ {
/* Can't proceed if in a critical section as pvInterruptEventMutex won't /* Can't proceed if in a critical section as pvInterruptEventMutex won't
* be available. */ * be available. */

View file

@ -53,6 +53,17 @@
/* A few bytes might be lost to byte aligning the heap start address. */ /* A few bytes might be lost to byte aligning the heap start address. */
#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) #define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )
/* configTOTAL_HEAP_SIZE must be larger than portBYTE_ALIGNMENT, otherwise the
* configADJUSTED_HEAP_SIZE subtraction above underflows. The "enough room left"
* check in pvPortMalloc() compares an unsigned size_t index against
* configADJUSTED_HEAP_SIZE, so an underflowed (very large) value silently
* defeats that check and pvPortMalloc() can return a pointer outside the ucHeap
* array. Reject such a nonsensical, too-small heap at compile time. This is a
* compiler (not preprocessor) check so that it still works when
* configTOTAL_HEAP_SIZE is defined with a cast, e.g. ( ( size_t ) 0x2000 ). */
typedef char heapCHECK_configTOTAL_HEAP_SIZE_EXCEEDS_portBYTE_ALIGNMENT
[ ( ( configTOTAL_HEAP_SIZE ) > ( portBYTE_ALIGNMENT ) ) ? 1 : -1 ];
/* Max value that fits in a size_t type. */ /* Max value that fits in a size_t type. */
#define heapSIZE_MAX ( ~( ( size_t ) 0 ) ) #define heapSIZE_MAX ( ~( ( size_t ) 0 ) )

View file

@ -820,10 +820,12 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
TickType_t xTicksToWait ) TickType_t xTicksToWait )
{ {
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
size_t xReturn, xSpace = 0; size_t xReturn = 0;
size_t xSpace = 0;
size_t xRequiredSpace = xDataLengthBytes; size_t xRequiredSpace = xDataLengthBytes;
TimeOut_t xTimeOut; TimeOut_t xTimeOut;
size_t xMaxReportedSpace = 0; size_t xMaxReportedSpace = 0;
BaseType_t xSendAllowed = pdTRUE;
traceENTER_xStreamBufferSend( xStreamBuffer, pvTxData, xDataLengthBytes, xTicksToWait ); traceENTER_xStreamBufferSend( xStreamBuffer, pvTxData, xDataLengthBytes, xTicksToWait );
@ -845,9 +847,22 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
/* Overflow? */ /* Overflow? */
configASSERT( xRequiredSpace > xDataLengthBytes ); 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 /* If this is a message buffer then it must be possible to write the
* whole message. */ * whole message. */
if( xRequiredSpace > xMaxReportedSpace ) else if( xRequiredSpace > xMaxReportedSpace )
{ {
/* The message would not fit even if the entire buffer was empty, /* The message would not fit even if the entire buffer was empty,
* so don't wait for space. */ * so don't wait for space. */
@ -921,7 +936,10 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
if( xSendAllowed == pdTRUE )
{
xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace ); xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
}
if( xReturn > ( size_t ) 0 ) if( xReturn > ( size_t ) 0 )
{ {
@ -955,8 +973,10 @@ size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
BaseType_t * const pxHigherPriorityTaskWoken ) BaseType_t * const pxHigherPriorityTaskWoken )
{ {
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
size_t xReturn, xSpace; size_t xReturn = 0;
size_t xSpace;
size_t xRequiredSpace = xDataLengthBytes; size_t xRequiredSpace = xDataLengthBytes;
BaseType_t xSendAllowed = pdTRUE;
traceENTER_xStreamBufferSendFromISR( xStreamBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken ); traceENTER_xStreamBufferSendFromISR( xStreamBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken );
@ -973,14 +993,31 @@ size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
/* Overflow? */ /* Overflow? */
configASSERT( xRequiredSpace > xDataLengthBytes ); 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 else
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
if( xSendAllowed == pdTRUE )
{
xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace ); xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
}
if( xReturn > ( size_t ) 0 ) if( xReturn > ( size_t ) 0 )
{ {
@ -1028,16 +1065,21 @@ static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
/* Ensure the data length given fits within configMESSAGE_BUFFER_LENGTH_TYPE. */ /* Ensure the data length given fits within configMESSAGE_BUFFER_LENGTH_TYPE. */
configASSERT( ( size_t ) xMessageLength == xDataLengthBytes ); configASSERT( ( size_t ) xMessageLength == xDataLengthBytes );
if( xSpace >= xRequiredSpace ) if( ( ( size_t ) xMessageLength == xDataLengthBytes ) && ( xSpace >= xRequiredSpace ) )
{ {
/* There is enough space to write both the message length and the message /* The message length fits within configMESSAGE_BUFFER_LENGTH_TYPE and
* there is enough space to write both the message length and the message
* itself into the buffer. Start by writing the length of the data, the data * itself into the buffer. Start by writing the length of the data, the data
* itself will be written later in this function. */ * itself will be written later in this function. */
xNextHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xMessageLength ), sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextHead ); xNextHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xMessageLength ), sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextHead );
} }
else else
{ {
/* Not enough space, so do not write data to the buffer. */ /* Either there is not enough space, or the message length cannot be
* represented by configMESSAGE_BUFFER_LENGTH_TYPE without truncation.
* Writing a truncated length header would corrupt the message
* framing at the receiver, so do not write any data to the buffer. When asserts are
* disabled this runtime check is the only guard against truncation. */
xDataLengthBytes = 0; xDataLengthBytes = 0;
} }
} }

18
tasks.c
View file

@ -1637,6 +1637,23 @@ STATIC void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
{ {
TCB_t * pxNewTCB; TCB_t * pxNewTCB;
/* Guard against the stack size calculation overflowing. The stack is
* allocated as ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ). If a
* caller-supplied uxStackDepth is large enough that this product wraps
* size_t, the allocation is far smaller than requested while
* prvInitialiseNewTask() still computes the top of stack from the full
* uxStackDepth, causing out-of-bounds writes when the initial stack frame
* is written. The wrap is detected by multiplying and dividing back:
* if dividing the byte size by sizeof( StackType_t ) does not recover
* uxStackDepth then the multiplication overflowed. Leave pxNewTCB NULL
* and skip allocation instead of under-allocating, so the failure is
* reported through the single return at the end of the function. */
if( ( ( size_t ) uxStackDepth ) != ( ( ( ( size_t ) uxStackDepth ) * sizeof( StackType_t ) ) / sizeof( StackType_t ) ) )
{
pxNewTCB = NULL;
}
else
{
/* If the stack grows down then allocate the stack then the TCB so the stack /* If the stack grows down then allocate the stack then the TCB so the stack
* does not grow into the TCB. Likewise if the stack grows up then allocate * does not grow into the TCB. Likewise if the stack grows up then allocate
* the TCB then the stack. */ * the TCB then the stack. */
@ -1708,6 +1725,7 @@ STATIC void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION;
} }
} }
#endif /* portSTACK_GROWTH */ #endif /* portSTACK_GROWTH */
}
if( pxNewTCB != NULL ) if( pxNewTCB != NULL )
{ {