65
65
#define heapSIZE_MAX ( ~( ( size_t ) 0 ) )
66
66
67
67
/* Check if multiplying a and b will result in overflow. */
68
- #define heapMULTIPLY_WILL_OVERFLOW ( a , b ) ( ( ( a ) > 0 ) && ( ( b ) > ( heapSIZE_MAX / ( a ) ) ) )
68
+ #define heapMULTIPLY_WILL_OVERFLOW ( a , b ) ( ( ( a ) > 0 ) && ( ( b ) > ( heapSIZE_MAX / ( a ) ) ) )
69
69
70
70
/* Check if adding a and b will result in overflow. */
71
- #define heapADD_WILL_OVERFLOW ( a , b ) ( ( a ) > ( heapSIZE_MAX - ( b ) ) )
71
+ #define heapADD_WILL_OVERFLOW ( a , b ) ( ( a ) > ( heapSIZE_MAX - ( b ) ) )
72
+
73
+ /* Check if the subtraction operation ( a - b ) will result in underflow. */
74
+ #define heapSUBTRACT_WILL_UNDERFLOW ( a , b ) ( ( a ) < ( b ) )
72
75
73
76
/* MSB of the xBlockSize member of an BlockLink_t structure is used to track
74
77
* the allocation status of a block. When MSB of the xBlockSize member of
@@ -100,6 +103,38 @@ typedef struct A_BLOCK_LINK
100
103
size_t xBlockSize ; /**< The size of the free block. */
101
104
} BlockLink_t ;
102
105
106
+ /* Setting configENABLE_HEAP_PROTECTOR to 1 enables heap block pointers
107
+ * protection using an application supplied canary value to catch heap
108
+ * corruption should a heap buffer overflow occur.
109
+ */
110
+ #if ( configENABLE_HEAP_PROTECTOR == 1 )
111
+
112
+ /**
113
+ * @brief Application provided function to get a random value to be used as canary.
114
+ *
115
+ * @param pxHeapCanary [out] Output parameter to return the canary value.
116
+ */
117
+ extern void vApplicationGetRandomHeapCanary ( portPOINTER_SIZE_TYPE * pxHeapCanary );
118
+
119
+ /* Canary value for protecting internal heap pointers. */
120
+ PRIVILEGED_DATA static portPOINTER_SIZE_TYPE xHeapCanary ;
121
+
122
+ /* Macro to load/store BlockLink_t pointers to memory. By XORing the
123
+ * pointers with a random canary value, heap overflows will result
124
+ * in randomly unpredictable pointer values which will be caught by
125
+ * heapVALIDATE_BLOCK_POINTER assert. */
126
+ #define heapPROTECT_BLOCK_POINTER ( pxBlock ) ( ( BlockLink_t * ) ( ( ( portPOINTER_SIZE_TYPE ) ( pxBlock ) ) ^ xHeapCanary ) )
127
+ #else
128
+
129
+ #define heapPROTECT_BLOCK_POINTER ( pxBlock ) ( pxBlock )
130
+
131
+ #endif /* configENABLE_HEAP_PROTECTOR */
132
+
133
+ /* Assert that a heap block pointer is within the heap bounds. */
134
+ #define heapVALIDATE_BLOCK_POINTER ( pxBlock ) \
135
+ configASSERT( ( ( uint8_t * ) ( pxBlock ) >= &( ucHeap[ 0 ] ) ) && \
136
+ ( ( uint8_t * ) ( pxBlock ) <= &( ucHeap[ configTOTAL_HEAP_SIZE - 1 ] ) ) )
137
+
103
138
/*-----------------------------------------------------------*/
104
139
105
140
/*
@@ -206,12 +241,14 @@ void * pvPortMalloc( size_t xWantedSize )
206
241
/* Traverse the list from the start (lowest address) block until
207
242
* one of adequate size is found. */
208
243
pxPreviousBlock = & xStart ;
209
- pxBlock = xStart .pxNextFreeBlock ;
244
+ pxBlock = heapPROTECT_BLOCK_POINTER ( xStart .pxNextFreeBlock );
245
+ heapVALIDATE_BLOCK_POINTER ( pxBlock );
210
246
211
- while ( ( pxBlock -> xBlockSize < xWantedSize ) && ( pxBlock -> pxNextFreeBlock != NULL ) )
247
+ while ( ( pxBlock -> xBlockSize < xWantedSize ) && ( pxBlock -> pxNextFreeBlock != heapPROTECT_BLOCK_POINTER ( NULL ) ) )
212
248
{
213
249
pxPreviousBlock = pxBlock ;
214
- pxBlock = pxBlock -> pxNextFreeBlock ;
250
+ pxBlock = heapPROTECT_BLOCK_POINTER ( pxBlock -> pxNextFreeBlock );
251
+ heapVALIDATE_BLOCK_POINTER ( pxBlock );
215
252
}
216
253
217
254
/* If the end marker was reached then a block of adequate size
@@ -220,14 +257,17 @@ void * pvPortMalloc( size_t xWantedSize )
220
257
{
221
258
/* Return the memory space pointed to - jumping over the
222
259
* BlockLink_t structure at its start. */
223
- pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock -> pxNextFreeBlock ) + xHeapStructSize );
260
+ pvReturn = ( void * ) ( ( ( uint8_t * ) heapPROTECT_BLOCK_POINTER ( pxPreviousBlock -> pxNextFreeBlock ) ) + xHeapStructSize );
261
+ heapVALIDATE_BLOCK_POINTER ( pvReturn );
224
262
225
263
/* This block is being returned for use so must be taken out
226
264
* of the list of free blocks. */
227
265
pxPreviousBlock -> pxNextFreeBlock = pxBlock -> pxNextFreeBlock ;
228
266
229
267
/* If the block is larger than required it can be split into
230
268
* two. */
269
+ configASSERT ( heapSUBTRACT_WILL_UNDERFLOW ( pxBlock -> xBlockSize , xWantedSize ) == 0 );
270
+
231
271
if ( ( pxBlock -> xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
232
272
{
233
273
/* This block is to be split into two. Create a new
@@ -244,7 +284,7 @@ void * pvPortMalloc( size_t xWantedSize )
244
284
245
285
/* Insert the new block into the list of free blocks. */
246
286
pxNewBlockLink -> pxNextFreeBlock = pxPreviousBlock -> pxNextFreeBlock ;
247
- pxPreviousBlock -> pxNextFreeBlock = pxNewBlockLink ;
287
+ pxPreviousBlock -> pxNextFreeBlock = heapPROTECT_BLOCK_POINTER ( pxNewBlockLink ) ;
248
288
}
249
289
else
250
290
{
@@ -319,6 +359,7 @@ void vPortFree( void * pv )
319
359
/* This casting is to keep the compiler from issuing warnings. */
320
360
pxLink = ( void * ) puc ;
321
361
362
+ heapVALIDATE_BLOCK_POINTER ( pxLink );
322
363
configASSERT ( heapBLOCK_IS_ALLOCATED ( pxLink ) != 0 );
323
364
configASSERT ( pxLink -> pxNextFreeBlock == NULL );
324
365
@@ -331,7 +372,12 @@ void vPortFree( void * pv )
331
372
heapFREE_BLOCK ( pxLink );
332
373
#if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )
333
374
{
334
- ( void ) memset ( puc + xHeapStructSize , 0 , pxLink -> xBlockSize - xHeapStructSize );
375
+ /* Check for underflow as this can occur if xBlockSize is
376
+ * overwritten in a heap block. */
377
+ if ( heapSUBTRACT_WILL_UNDERFLOW ( pxLink -> xBlockSize , xHeapStructSize ) == 0 )
378
+ {
379
+ ( void ) memset ( puc + xHeapStructSize , 0 , pxLink -> xBlockSize - xHeapStructSize );
380
+ }
335
381
}
336
382
#endif
337
383
@@ -414,9 +460,15 @@ static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
414
460
415
461
pucAlignedHeap = ( uint8_t * ) uxAddress ;
416
462
463
+ #if ( configENABLE_HEAP_PROTECTOR == 1 )
464
+ {
465
+ vApplicationGetRandomHeapCanary ( & ( xHeapCanary ) );
466
+ }
467
+ #endif
468
+
417
469
/* xStart is used to hold a pointer to the first item in the list of free
418
470
* blocks. The void cast is used to prevent compiler warnings. */
419
- xStart .pxNextFreeBlock = ( void * ) pucAlignedHeap ;
471
+ xStart .pxNextFreeBlock = ( void * ) heapPROTECT_BLOCK_POINTER ( pucAlignedHeap ) ;
420
472
xStart .xBlockSize = ( size_t ) 0 ;
421
473
422
474
/* pxEnd is used to mark the end of the list of free blocks and is inserted
@@ -426,13 +478,13 @@ static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
426
478
uxAddress &= ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK );
427
479
pxEnd = ( BlockLink_t * ) uxAddress ;
428
480
pxEnd -> xBlockSize = 0 ;
429
- pxEnd -> pxNextFreeBlock = NULL ;
481
+ pxEnd -> pxNextFreeBlock = heapPROTECT_BLOCK_POINTER ( NULL ) ;
430
482
431
483
/* To start with there is a single free block that is sized to take up the
432
484
* entire heap space, minus the space taken by pxEnd. */
433
485
pxFirstFreeBlock = ( BlockLink_t * ) pucAlignedHeap ;
434
486
pxFirstFreeBlock -> xBlockSize = ( size_t ) ( uxAddress - ( portPOINTER_SIZE_TYPE ) pxFirstFreeBlock );
435
- pxFirstFreeBlock -> pxNextFreeBlock = pxEnd ;
487
+ pxFirstFreeBlock -> pxNextFreeBlock = heapPROTECT_BLOCK_POINTER ( pxEnd ) ;
436
488
437
489
/* Only one block exists - and it covers the entire usable heap space. */
438
490
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock -> xBlockSize ;
@@ -447,11 +499,16 @@ static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVI
447
499
448
500
/* Iterate through the list until a block is found that has a higher address
449
501
* than the block being inserted. */
450
- for ( pxIterator = & xStart ; pxIterator -> pxNextFreeBlock < pxBlockToInsert ; pxIterator = pxIterator -> pxNextFreeBlock )
502
+ for ( pxIterator = & xStart ; heapPROTECT_BLOCK_POINTER ( pxIterator -> pxNextFreeBlock ) < pxBlockToInsert ; pxIterator = heapPROTECT_BLOCK_POINTER ( pxIterator -> pxNextFreeBlock ) )
451
503
{
452
504
/* Nothing to do here, just iterate to the right position. */
453
505
}
454
506
507
+ if ( pxIterator != & xStart )
508
+ {
509
+ heapVALIDATE_BLOCK_POINTER ( pxIterator );
510
+ }
511
+
455
512
/* Do the block being inserted, and the block it is being inserted after
456
513
* make a contiguous block of memory? */
457
514
puc = ( uint8_t * ) pxIterator ;
@@ -470,17 +527,17 @@ static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVI
470
527
* make a contiguous block of memory? */
471
528
puc = ( uint8_t * ) pxBlockToInsert ;
472
529
473
- if ( ( puc + pxBlockToInsert -> xBlockSize ) == ( uint8_t * ) pxIterator -> pxNextFreeBlock )
530
+ if ( ( puc + pxBlockToInsert -> xBlockSize ) == ( uint8_t * ) heapPROTECT_BLOCK_POINTER ( pxIterator -> pxNextFreeBlock ) )
474
531
{
475
- if ( pxIterator -> pxNextFreeBlock != pxEnd )
532
+ if ( heapPROTECT_BLOCK_POINTER ( pxIterator -> pxNextFreeBlock ) != pxEnd )
476
533
{
477
534
/* Form one big block from the two blocks. */
478
- pxBlockToInsert -> xBlockSize += pxIterator -> pxNextFreeBlock -> xBlockSize ;
479
- pxBlockToInsert -> pxNextFreeBlock = pxIterator -> pxNextFreeBlock -> pxNextFreeBlock ;
535
+ pxBlockToInsert -> xBlockSize += heapPROTECT_BLOCK_POINTER ( pxIterator -> pxNextFreeBlock ) -> xBlockSize ;
536
+ pxBlockToInsert -> pxNextFreeBlock = heapPROTECT_BLOCK_POINTER ( pxIterator -> pxNextFreeBlock ) -> pxNextFreeBlock ;
480
537
}
481
538
else
482
539
{
483
- pxBlockToInsert -> pxNextFreeBlock = pxEnd ;
540
+ pxBlockToInsert -> pxNextFreeBlock = heapPROTECT_BLOCK_POINTER ( pxEnd ) ;
484
541
}
485
542
}
486
543
else
@@ -494,7 +551,7 @@ static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVI
494
551
* to itself. */
495
552
if ( pxIterator != pxBlockToInsert )
496
553
{
497
- pxIterator -> pxNextFreeBlock = pxBlockToInsert ;
554
+ pxIterator -> pxNextFreeBlock = heapPROTECT_BLOCK_POINTER ( pxBlockToInsert ) ;
498
555
}
499
556
else
500
557
{
@@ -510,7 +567,7 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats )
510
567
511
568
vTaskSuspendAll ();
512
569
{
513
- pxBlock = xStart .pxNextFreeBlock ;
570
+ pxBlock = heapPROTECT_BLOCK_POINTER ( xStart .pxNextFreeBlock ) ;
514
571
515
572
/* pxBlock will be NULL if the heap has not been initialised. The heap
516
573
* is initialised automatically when the first allocation is made. */
@@ -534,7 +591,7 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats )
534
591
535
592
/* Move to the next block in the chain until the last block is
536
593
* reached. */
537
- pxBlock = pxBlock -> pxNextFreeBlock ;
594
+ pxBlock = heapPROTECT_BLOCK_POINTER ( pxBlock -> pxNextFreeBlock ) ;
538
595
}
539
596
}
540
597
}
0 commit comments