From b4972f4093d9c2050f17159fa40f7ed5615d59ee Mon Sep 17 00:00:00 2001 From: Corentin Pane Date: Thu, 20 Aug 2026 10:10:54 +0200 Subject: [PATCH] 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. --- portable/GCC/ARM_CM3_MPU/port.c | 15 ++++++++------- portable/GCC/ARM_CM4_MPU/port.c | 15 ++++++++------- portable/IAR/ARM_CM4F_MPU/port.c | 15 ++++++++------- portable/RVDS/ARM_CM4_MPU/port.c | 15 ++++++++------- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/portable/GCC/ARM_CM3_MPU/port.c b/portable/GCC/ARM_CM3_MPU/port.c index 6b7ed02a00..381fc8569f 100644 --- a/portable/GCC/ARM_CM3_MPU/port.c +++ b/portable/GCC/ARM_CM3_MPU/port.c @@ -95,6 +95,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 /* Constants required to access and manipulate the SysTick and other FreeRTOS * interrupts. */ @@ -1137,7 +1138,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 ); @@ -1148,7 +1149,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 ); @@ -1159,7 +1160,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 ); @@ -1171,7 +1172,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 ); @@ -1281,7 +1282,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. */ @@ -1317,7 +1318,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. */ @@ -1344,7 +1345,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, * xRegions into the CM3 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. */ diff --git a/portable/GCC/ARM_CM4_MPU/port.c b/portable/GCC/ARM_CM4_MPU/port.c index e1a70c5117..908b57373e 100644 --- a/portable/GCC/ARM_CM4_MPU/port.c +++ b/portable/GCC/ARM_CM4_MPU/port.c @@ -105,6 +105,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 /* Constants required to access and manipulate the SysTick and other FreeRTOS * interrupts. */ @@ -1282,7 +1283,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 ); @@ -1293,7 +1294,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 ); @@ -1304,7 +1305,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 ); @@ -1316,7 +1317,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 ); @@ -1426,7 +1427,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. */ @@ -1462,7 +1463,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. */ @@ -1490,7 +1491,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. */ diff --git a/portable/IAR/ARM_CM4F_MPU/port.c b/portable/IAR/ARM_CM4F_MPU/port.c index a3b6517efb..311b72474a 100644 --- a/portable/IAR/ARM_CM4F_MPU/port.c +++ b/portable/IAR/ARM_CM4F_MPU/port.c @@ -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. */ diff --git a/portable/RVDS/ARM_CM4_MPU/port.c b/portable/RVDS/ARM_CM4_MPU/port.c index 7cdf3ea871..86d227b171 100644 --- a/portable/RVDS/ARM_CM4_MPU/port.c +++ b/portable/RVDS/ARM_CM4_MPU/port.c @@ -94,6 +94,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 /* Constants required to access and manipulate the SysTick and other FreeRTOS * interrupts. */ @@ -1282,7 +1283,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 ); @@ -1293,7 +1294,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 ); @@ -1304,7 +1305,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 ); @@ -1316,7 +1317,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 ); @@ -1416,7 +1417,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. */ @@ -1452,7 +1453,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. */ @@ -1480,7 +1481,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. */