Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heap protect #747

Merged
merged 12 commits into from
Aug 23, 2023
4 changes: 4 additions & 0 deletions include/FreeRTOS.h
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,10 @@
#define configAPPLICATION_ALLOCATED_HEAP 0
#endif

#ifndef configENABLE_HEAP_PROTECTOR
#define configENABLE_HEAP_PROTECTOR 0
#endif

#ifndef configUSE_TASK_NOTIFICATIONS
#define configUSE_TASK_NOTIFICATIONS 1
#endif
Expand Down
97 changes: 77 additions & 20 deletions portable/MemMang/heap_4.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,13 @@
#define heapSIZE_MAX ( ~( ( size_t ) 0 ) )

/* Check if multiplying a and b will result in overflow. */
#define heapMULTIPLY_WILL_OVERFLOW( a, b ) ( ( ( a ) > 0 ) && ( ( b ) > ( heapSIZE_MAX / ( a ) ) ) )
#define heapMULTIPLY_WILL_OVERFLOW( a, b ) ( ( ( a ) > 0 ) && ( ( b ) > ( heapSIZE_MAX / ( a ) ) ) )

/* Check if adding a and b will result in overflow. */
#define heapADD_WILL_OVERFLOW( a, b ) ( ( a ) > ( heapSIZE_MAX - ( b ) ) )
#define heapADD_WILL_OVERFLOW( a, b ) ( ( a ) > ( heapSIZE_MAX - ( b ) ) )

/* Check if the subtraction operation ( a - b ) will result in underflow. */
#define heapSUBTRACT_WILL_UNDERFLOW( a, b ) ( ( a ) < ( b ) )

/* MSB of the xBlockSize member of an BlockLink_t structure is used to track
* the allocation status of a block. When MSB of the xBlockSize member of
Expand Down Expand Up @@ -100,6 +103,38 @@ typedef struct A_BLOCK_LINK
size_t xBlockSize; /**< The size of the free block. */
} BlockLink_t;

/* Setting configENABLE_HEAP_PROTECTOR to 1 enables heap block pointers
* protection using an application supplied canary value to catch heap
* corruption should a heap buffer overflow occur.
*/
#if ( configENABLE_HEAP_PROTECTOR == 1 )

/**
* @brief Application provided function to get a random value to be used as canary.
*
* @param pxHeapCanary [out] Output parameter to return the canary value.
*/
extern void vApplicationGetRandomHeapCanary( portPOINTER_SIZE_TYPE * pxHeapCanary );

/* Canary value for protecting internal heap pointers. */
PRIVILEGED_DATA static portPOINTER_SIZE_TYPE xHeapCanary;

/* Macro to load/store BlockLink_t pointers to memory. By XORing the
* pointers with a random canary value, heap overflows will result
* in randomly unpredictable pointer values which will be caught by
* heapVALIDATE_BLOCK_POINTER assert. */
#define heapPROTECT_BLOCK_POINTER( pxBlock ) ( ( BlockLink_t * ) ( ( ( portPOINTER_SIZE_TYPE ) ( pxBlock ) ) ^ xHeapCanary ) )
#else

#define heapPROTECT_BLOCK_POINTER( pxBlock ) ( pxBlock )

#endif /* configENABLE_HEAP_PROTECTOR */

/* Assert that a heap block pointer is within the heap bounds. */
#define heapVALIDATE_BLOCK_POINTER( pxBlock ) \
configASSERT( ( ( uint8_t * ) ( pxBlock ) >= &( ucHeap[ 0 ] ) ) && \
( ( uint8_t * ) ( pxBlock ) <= &( ucHeap[ configTOTAL_HEAP_SIZE - 1 ] ) ) )

/*-----------------------------------------------------------*/

/*
Expand Down Expand Up @@ -206,12 +241,14 @@ void * pvPortMalloc( size_t xWantedSize )
/* Traverse the list from the start (lowest address) block until
* one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
pxBlock = heapPROTECT_BLOCK_POINTER( xStart.pxNextFreeBlock );
heapVALIDATE_BLOCK_POINTER( pxBlock );

while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( NULL ) ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock );
heapVALIDATE_BLOCK_POINTER( pxBlock );
}

/* If the end marker was reached then a block of adequate size
Expand All @@ -220,14 +257,17 @@ void * pvPortMalloc( size_t xWantedSize )
{
/* Return the memory space pointed to - jumping over the
* BlockLink_t structure at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
pvReturn = ( void * ) ( ( ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxPreviousBlock->pxNextFreeBlock ) ) + xHeapStructSize );
heapVALIDATE_BLOCK_POINTER( pvReturn );

/* This block is being returned for use so must be taken out
* of the list of free blocks. */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

/* If the block is larger than required it can be split into
* two. */
configASSERT( heapSUBTRACT_WILL_UNDERFLOW( pxBlock->xBlockSize, xWantedSize ) == 0 );

if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{
/* This block is to be split into two. Create a new
Expand All @@ -244,7 +284,7 @@ void * pvPortMalloc( size_t xWantedSize )

/* Insert the new block into the list of free blocks. */
pxNewBlockLink->pxNextFreeBlock = pxPreviousBlock->pxNextFreeBlock;
pxPreviousBlock->pxNextFreeBlock = pxNewBlockLink;
pxPreviousBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxNewBlockLink );
}
else
{
Expand Down Expand Up @@ -319,6 +359,7 @@ void vPortFree( void * pv )
/* This casting is to keep the compiler from issuing warnings. */
pxLink = ( void * ) puc;

heapVALIDATE_BLOCK_POINTER( pxLink );
configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );

Expand All @@ -331,7 +372,12 @@ void vPortFree( void * pv )
heapFREE_BLOCK( pxLink );
#if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )
{
( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize );
/* Check for underflow as this can occur if xBlockSize is
* overwritten in a heap block. */
if( heapSUBTRACT_WILL_UNDERFLOW( pxLink->xBlockSize, xHeapStructSize ) == 0 )
{
( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize );
}
}
#endif

Expand Down Expand Up @@ -414,9 +460,15 @@ static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */

pucAlignedHeap = ( uint8_t * ) uxAddress;

#if ( configENABLE_HEAP_PROTECTOR == 1 )
{
vApplicationGetRandomHeapCanary( &( xHeapCanary ) );
}
#endif

/* xStart is used to hold a pointer to the first item in the list of free
* blocks. The void cast is used to prevent compiler warnings. */
xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
xStart.pxNextFreeBlock = ( void * ) heapPROTECT_BLOCK_POINTER( pucAlignedHeap );
xStart.xBlockSize = ( size_t ) 0;

/* pxEnd is used to mark the end of the list of free blocks and is inserted
Expand All @@ -426,13 +478,13 @@ static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
uxAddress &= ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( BlockLink_t * ) uxAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
pxEnd->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( NULL );

/* To start with there is a single free block that is sized to take up the
* entire heap space, minus the space taken by pxEnd. */
pxFirstFreeBlock = ( BlockLink_t * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = ( size_t ) ( uxAddress - ( portPOINTER_SIZE_TYPE ) pxFirstFreeBlock );
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
pxFirstFreeBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxEnd );

/* Only one block exists - and it covers the entire usable heap space. */
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
Expand All @@ -447,11 +499,16 @@ static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVI

/* Iterate through the list until a block is found that has a higher address
* than the block being inserted. */
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
for( pxIterator = &xStart; heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) < pxBlockToInsert; pxIterator = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) )
{
/* Nothing to do here, just iterate to the right position. */
}

if( pxIterator != &xStart )
{
heapVALIDATE_BLOCK_POINTER( pxIterator );
}

/* Do the block being inserted, and the block it is being inserted after
* make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator;
Expand All @@ -470,17 +527,17 @@ static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVI
* make a contiguous block of memory? */
puc = ( uint8_t * ) pxBlockToInsert;

if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) )
{
if( pxIterator->pxNextFreeBlock != pxEnd )
if( heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) != pxEnd )
{
/* Form one big block from the two blocks. */
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
pxBlockToInsert->xBlockSize += heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxEnd;
pxBlockToInsert->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxEnd );
}
}
else
Expand All @@ -494,7 +551,7 @@ static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVI
* to itself. */
if( pxIterator != pxBlockToInsert )
{
pxIterator->pxNextFreeBlock = pxBlockToInsert;
pxIterator->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxBlockToInsert );
}
else
{
Expand All @@ -510,7 +567,7 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats )

vTaskSuspendAll();
{
pxBlock = xStart.pxNextFreeBlock;
pxBlock = heapPROTECT_BLOCK_POINTER( xStart.pxNextFreeBlock );

/* pxBlock will be NULL if the heap has not been initialised. The heap
* is initialised automatically when the first allocation is made. */
Expand All @@ -534,7 +591,7 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats )

/* Move to the next block in the chain until the last block is
* reached. */
pxBlock = pxBlock->pxNextFreeBlock;
pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock );
}
}
}
Expand Down
Loading
Loading