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

Refine heap_5 heap protector #1146

Merged
merged 2 commits into from
Sep 19, 2024
Merged

Conversation

Saiiijchan
Copy link
Contributor

@Saiiijchan Saiiijchan commented Sep 12, 2024

heap_5 is used for multiple separated memory spaces. In the previous implementation, it only verifies the highest and lowest addresses. A pointer may not be within heap regions, but is still located between the highest and lowest addressed.

Description
heap_5 is used for multiple separated memory spaces. In the previous implementation, it only verifies the highest and lowest addresses. A pointer may not be within heap regions, but is still located between the highest and lowest addressed.

This PR will use a buffer to record the boundary of each heap region so the pointer detection can be made more accurate . This buffter is dynamically allocated at the end of vPortDefineHeapRegions(). At this time, the multi heap regions have been defined and there is only a free block and "pxFakeEnd" (the heap structure points to the next heap region) and pxEnd (At the last heap region).

Heap_range_diagram

As shown in the diagram above, the white area represents the valid pointer range.

Test Steps

Test on FreeRTO and runs correctly.
I have also manually corrupted a free list block and triggered assertion successfully.

Checklist:

  • I have tested my changes. No regression in existing tests.
  • I have modified and/or added unit-tests to cover the code changes in this Pull Request.

Related Issue

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@Saiiijchan Saiiijchan requested a review from a team as a code owner September 12, 2024 09:08
@aggarg
Copy link
Member

aggarg commented Sep 16, 2024

Thank you for sharing your proposal! I think it is a lot of complexity to bring to catch one specific type of pointer corruption. This also requires handling another corner case when pvPortMalloc for Region_Bound_t fails.

What do you think about letting the application to override heapVALIDATE_BLOCK_POINTER:

    #ifndef configVALIDATE_HEAP_BLOCK_POINTER
        #define heapVALIDATE_BLOCK_POINTER( pxBlock )                       \
        configASSERT( ( pucHeapHighAddress != NULL ) &&                     \
                    ( pucHeapLowAddress != NULL ) &&                        \
                    ( ( uint8_t * ) ( pxBlock ) >= pucHeapLowAddress ) &&   \
                    ( ( uint8_t * ) ( pxBlock ) < pucHeapHighAddress ) )
    #else
        #define heapVALIDATE_BLOCK_POINTER( pxBlock )                       \
            configVALIDATE_HEAP_BLOCK_POINTER( pxBlock )
    #endif

This way the interested application can implement configVALIDATE_HEAP_BLOCK_POINTER. Since the application already knows the number of memory regions it is using for heap, it does not need to do any dynamic allocation.

@Saiiijchan
Copy link
Contributor Author

@aggarg Thanks for your review.

This way the interested application can implement configVALIDATE_HEAP_BLOCK_POINTER. Since the application already knows the number of memory regions it is using for heap, it does not need to do any dynamic allocation .

I agree with your point. When implementing this PR, the uncertainty about the number of memory regions is the reason why dynamic allocation of Region_Bound_t is needed in vPortDefinesRegion() after the heap is initialized, as at that point only free blocks are available.

configVALIDATE_HEAP_BLOCK_POINTER is a good idea. In cases where the number of memory regions is known, static allocation can reduce complexity. However, in this case, the user will need to manually calculate the highest and lowest aligned addresses for each memory region, which is something to be aware of.

This also requires handling another corner case when pvPortMalloc for Region_Bound_t fails.

I'm a bit confused about this point. pvPortMalloc() for Region_Bound_t is the first allocation in the system, so if it fails, doesn't that mean the first pvPortMalloc() will fail? I can't quite understand under what circumstances it would fail.

@aggarg
Copy link
Member

aggarg commented Sep 17, 2024

In cases where the number of memory regions is known, static allocation can reduce complexity. However, in this case, the user will need to manually calculate the highest and lowest aligned addresses for each memory region, which is something to be aware of.

But those regions are known to the application, isn't it? One possible implementation is -

#define HEAP_1_SIZE ( 24 * 1024 )
#define HEAP_2_SIZE ( 48 * 1024 )

uint8_t ucHeap1[ HEAP_1_SIZE ] __attribute__( ( section( ".freertos_heap1" ) ) );
uint8_t ucHeap2[ HEAP_2_SIZE ] __attribute__( ( section( ".freertos_heap2" ) ) );


void AppInitializeHeap( void )
{
    HeapRegion_t xHeapRegions[] =
    {
        { ( unsigned char * ) ucHeap1, sizeof( ucHeap1 ) },
        { ( unsigned char * ) ucHeap2, sizeof( ucHeap2 ) },
        { NULL,                        0                 }
    };

    vPortDefineHeapRegions( xHeapRegions );
}

And in this case the application can implement the check like this -

#define configVALIDATE_HEAP_BLOCK_POINTER( pxBlock ) ValidateHeapPointer( pxBlock )

void ValidateHeapPointer( void * ptr )
{
    if( !( ptr >= &( ucHeap1[ 0 ] ) ) && ( ptr < &( ucHeap1[ HEAP_1_SIZE ] ) ) &&
        !( ptr >= &( ucHeap2[ 0 ] ) ) && ( ptr < &( ucHeap2[ HEAP_2_SIZE ] ) ) )
    {
        /* If pointer is not in ucHeap1 and ucHeap2, it is invalid. */
        configASSERT( pdFALSE );
    }
}

I'm a bit confused about this point. pvPortMalloc() for Region_Bound_t is the first allocation in the system, so if it fails, doesn't that mean the first pvPortMalloc() will fail? I can't quite understand under what circumstances it would fail.

You are right that if this fails, likely the first cal to pvPortMalloc will fail too. We'll still want an assert or if check to avoid NULL pointer de-reference. It is not needed if we go with the configVALIDATE_HEAP_BLOCK_POINTER solution.

@Saiiijchan
Copy link
Contributor Author

Thank you for your reply, I agree with your point of view.

@aggarg
Copy link
Member

aggarg commented Sep 18, 2024

Thank you! Would you please update your PR?

@Saiiijchan
Copy link
Contributor Author

Of course, then I will modify the PR according to this suggestion.

    #ifndef configVALIDATE_HEAP_BLOCK_POINTER
        #define heapVALIDATE_BLOCK_POINTER( pxBlock )                       \
        configASSERT( ( pucHeapHighAddress != NULL ) &&                     \
                    ( pucHeapLowAddress != NULL ) &&                        \
                    ( ( uint8_t * ) ( pxBlock ) >= pucHeapLowAddress ) &&   \
                    ( ( uint8_t * ) ( pxBlock ) < pucHeapHighAddress ) )
    #else
        #define heapVALIDATE_BLOCK_POINTER( pxBlock )                       \
            configVALIDATE_HEAP_BLOCK_POINTER( pxBlock )
    #endif

heap_5 is used for multiple separated memory spaces. In the
previous implementation, it only verifies the highest and
lowest addresses. A pointer may not be within heap regions,
but is still located between the highest and lowest addressed.

Add maco configVALIDATE_HEAP_BLOCK_POINTER to provide customized
heap block pointers detection based on the settings of heap
regions.

Signed-off-by: wangfei_chen <wangfei_chen@realsil.com.cn>
@Saiiijchan
Copy link
Contributor Author

I updated the PR and force pushed. Thanks for your suggestion!

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
Copy link

sonarcloud bot commented Sep 19, 2024

@aggarg aggarg merged commit 61440fc into FreeRTOS:main Sep 19, 2024
16 checks passed
@aggarg
Copy link
Member

aggarg commented Sep 19, 2024

@Saiiijchan Thank you for your contribution!

@Saiiijchan Saiiijchan deleted the refine_heap_protector branch September 19, 2024 05:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants