Mask MPU region base addresses when writing to MPU_RBAR on ARM_CM3/4

Bits 0-4 are reserved for VALID and REGION, while ADDR  spans at most bits 5-31 (bits 5-7 are sometimes reserved and not assigned to ADDR field). Masking ensures that a misaligned base address cannot modify less significant bits in the attribute reserved for other use. Failing to mask the address may allow a malicious user to pass in misaligned addresses in a user-defined region or as stack buffer which could in turn override the settings for higher-priority kernel-defined regions.

This change doesn't guarantee that only properly aligned addresses are written to the ADDR field of the register, and doesn't ensure that reserved field from bits 5-7 are not written to, but protects the VALID and REGION fields.
This commit is contained in:
Corentin Pane 2026-08-20 10:10:54 +02:00
parent 8be86d4a24
commit b4972f4093
4 changed files with 32 additions and 28 deletions

View file

@ -106,6 +106,7 @@ typedef void ( * portISR_t )( void );
#define portMPU_REGION_ENABLE ( 0x01UL )
#define portPERIPHERALS_START_ADDRESS 0x40000000UL
#define portPERIPHERALS_END_ADDRESS 0x5FFFFFFFUL
#define portMPU_RBAR_ADDRESS_MASK 0xFFFFFFE0
/* ...then bits in the registers. */
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
@ -1071,7 +1072,7 @@ static void prvSetupMPU( void )
if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )
{
/* First setup the unprivileged flash for unprivileged read only access. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( ( uint32_t ) __FLASH_segment_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | /* Base address. */
( portMPU_REGION_VALID ) |
( portUNPRIVILEGED_FLASH_REGION );
@ -1082,7 +1083,7 @@ static void prvSetupMPU( void )
/* Setup the privileged flash for privileged only access. This is where
* the kernel code is placed. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_functions_start__ ) | /* Base address. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( ( uint32_t ) __privileged_functions_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | /* Base address. */
( portMPU_REGION_VALID ) |
( portPRIVILEGED_FLASH_REGION );
@ -1093,7 +1094,7 @@ static void prvSetupMPU( void )
/* Setup the privileged data RAM region. This is where the kernel data
* is placed. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( ( uint32_t ) __privileged_data_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | /* Base address. */
( portMPU_REGION_VALID ) |
( portPRIVILEGED_RAM_REGION );
@ -1105,7 +1106,7 @@ static void prvSetupMPU( void )
/* By default allow everything to access the general peripherals. The
* system peripherals and registers are protected. */
portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |
portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS & portMPU_RBAR_ADDRESS_MASK ) |
( portMPU_REGION_VALID ) |
( portGENERAL_PERIPHERALS_REGION );
@ -1162,7 +1163,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
{
/* No MPU regions are specified so allow access to all RAM. */
xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
( ( uint32_t ) __SRAM_segment_start__ ) | /* Base address. */
( ( ( uint32_t ) __SRAM_segment_start__ ) & portMPU_RBAR_ADDRESS_MASK ) | /* Base address. */
( portMPU_REGION_VALID ) |
( portSTACK_REGION ); /* Region number. */
@ -1198,7 +1199,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
{
/* Define the region that allows access to the stack. */
xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
( ( uint32_t ) pxBottomOfStack ) |
( ( ( uint32_t ) pxBottomOfStack ) & portMPU_RBAR_ADDRESS_MASK ) |
( portMPU_REGION_VALID ) |
( portSTACK_REGION ); /* Region number. */
@ -1226,7 +1227,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
* xRegions into the CM4 specific MPU settings that are then
* stored in xMPUSettings. */
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =
( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |
( ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) & portMPU_RBAR_ADDRESS_MASK ) |
( portMPU_REGION_VALID ) |
( ul - 1UL ); /* Region number. */