Use highest numbered MPU regions for kernel

ARMv7-M allows overlapping MPU regions. When 2 MPU regions overlap, the
MPU configuration of the higher numbered MPU region is applied. For
example, if a memory area is covered by 2 MPU regions 0 and 1, the
memory permissions for MPU region 1 are applied.

We use 5 MPU regions for kernel code and kernel data protections and
leave the remaining for the application writer. We were using lowest
numbered MPU regions (0-4) for kernel protections and leaving the
remaining for the application writer. The application writer could
configure those higher numbered MPU regions to override kernel
protections.

This commit changes the code to use highest numbered MPU regions for
kernel protections and leave the remaining for the application writer.
This ensures that the application writer cannot override kernel
protections.

We thank the SecLab team at Northeastern University for reporting this
issue.

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
This commit is contained in:
Gaurav Aggarwal 2022-09-07 16:01:11 +05:30 committed by Gaurav-Aggarwal-AWS
parent 1e08439294
commit acd9279fc2
8 changed files with 79 additions and 134 deletions

View file

@ -68,7 +68,7 @@
#define portMPU_REGION_BASE_ADDRESS_REG ( *( ( volatile uint32_t * ) 0xe000ed9C ) )
#define portMPU_REGION_ATTRIBUTE_REG ( *( ( volatile uint32_t * ) 0xe000edA0 ) )
#define portMPU_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed94 ) )
#define portEXPECTED_MPU_TYPE_VALUE ( portTOTAL_NUM_REGIONS << 8UL )
#define portEXPECTED_MPU_TYPE_VALUE ( configTOTAL_MPU_REGIONS << 8UL )
#define portMPU_ENABLE ( 0x01UL )
#define portMPU_BACKGROUND_ENABLE ( 1UL << 2UL )
#define portPRIVILEGED_EXECUTION_START_ADDRESS ( 0UL )
@ -359,12 +359,12 @@ static void prvRestoreContextOfFirstTask( void )
" ldmia r1!, {r4-r11} \n"/* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */
" stmia r2, {r4-r11} \n"/* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */
" \n"
#if ( portTOTAL_NUM_REGIONS == 16 )
#if ( configTOTAL_MPU_REGIONS == 16 )
" ldmia r1!, {r4-r11} \n"/* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */
" stmia r2, {r4-r11} \n"/* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */
" ldmia r1!, {r4-r11} \n"/* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */
" stmia r2, {r4-r11} \n"/* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */
#endif /* portTOTAL_NUM_REGIONS == 16. */
#endif /* configTOTAL_MPU_REGIONS == 16. */
" \n"
" ldr r2, =0xe000ed94 \n"/* MPU_CTRL register. */
" ldr r3, [r2] \n"/* Read the value of MPU_CTRL. */
@ -585,12 +585,12 @@ void xPortPendSVHandler( void )
" ldmia r1!, {r4-r11} \n"/* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */
" stmia r2, {r4-r11} \n"/* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */
" \n"
#if ( portTOTAL_NUM_REGIONS == 16 )
#if ( configTOTAL_MPU_REGIONS == 16 )
" ldmia r1!, {r4-r11} \n"/* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */
" stmia r2, {r4-r11} \n"/* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */
" ldmia r1!, {r4-r11} \n"/* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */
" stmia r2, {r4-r11} \n"/* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */
#endif /* portTOTAL_NUM_REGIONS == 16. */
#endif /* configTOTAL_MPU_REGIONS == 16. */
" \n"
" ldr r2, =0xe000ed94 \n"/* MPU_CTRL register. */
" ldr r3, [r2] \n"/* Read the value of MPU_CTRL. */
@ -687,7 +687,7 @@ static void prvSetupMPU( void )
#endif /* if defined( __ARMCC_VERSION ) */
/* The only permitted number of regions are 8 or 16. */
configASSERT( ( portTOTAL_NUM_REGIONS == 8 ) || ( portTOTAL_NUM_REGIONS == 16 ) );
configASSERT( ( configTOTAL_MPU_REGIONS == 8 ) || ( configTOTAL_MPU_REGIONS == 16 ) );
/* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */
configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE );
@ -830,7 +830,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
( ( uint32_t ) __SRAM_segment_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) |
( portSTACK_REGION );
( portSTACK_REGION ); /* Region number. */
xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
( portMPU_REGION_READ_WRITE ) |
@ -838,23 +838,10 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) |
( portMPU_REGION_ENABLE );
/* Re-instate the privileged only RAM region as xRegion[ 0 ] will have
* just removed the privileged only parameters. */
xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress =
( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) |
( portSTACK_REGION + 1 );
xMPUSettings->xRegion[ 1 ].ulRegionAttribute =
( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |
( portMPU_REGION_ENABLE );
/* Invalidate all other regions. */
for( ul = 2; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
/* Invalidate user configurable regions. */
for( ul = 1UL; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
{
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( portSTACK_REGION + ul ) | portMPU_REGION_VALID;
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( ( ul - 1UL ) | portMPU_REGION_VALID );
xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
}
}
@ -881,7 +868,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
lIndex = 0;
for( ul = 1; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
for( ul = 1UL; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
{
if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )
{
@ -891,7 +878,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =
( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |
( portMPU_REGION_VALID ) |
( portSTACK_REGION + ul ); /* Region number. */
( ul - 1UL ); /* Region number. */
xMPUSettings->xRegion[ ul ].ulRegionAttribute =
( prvGetMPURegionSizeSetting( xRegions[ lIndex ].ulLengthInBytes ) ) |
@ -901,7 +888,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
else
{
/* Invalidate the region. */
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( portSTACK_REGION + ul ) | portMPU_REGION_VALID;
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( ( ul - 1UL ) | portMPU_REGION_VALID );
xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
}