diff --git a/components/esp_tee/subproject/main/arch/riscv/esp_tee_asm_utils.inc b/components/esp_tee/subproject/main/arch/riscv/esp_tee_asm_utils.inc index 6478f02e13a..7e638cf55af 100644 --- a/components/esp_tee/subproject/main/arch/riscv/esp_tee_asm_utils.inc +++ b/components/esp_tee/subproject/main/arch/riscv/esp_tee_asm_utils.inc @@ -221,3 +221,35 @@ 1: #endif .endm + +/** + * VALIDATE_REE_SP + * Validate an REE-supplied sp before the TEE stores through it. The TEE region is + * at the bottom of SRAM, so a valid REE frame [sp - framesz, sp) must lie in the + * band above it and below the peripheral window: [SOC_S_DRAM_END, SOC_PERIPHERAL_LOW]. + * An out-of-bound sp will lead to a fault. + * + * With chk_priv (default) the check is skipped unless the trap came from U-mode; + * pass chk_priv=0 where the U-mode origin is already guaranteed (ecall-from-U). + * + * TODO: Revisit these bounds for high-performance RISC-V SoCs (e.g. ESP32-P4, + * ESP32-S31) with different memory maps than current ESP-TEE targets. + * + * Clobbers: \tx + */ +.macro VALIDATE_REE_SP framesz, tx, chk_priv=1 +.if \chk_priv + /* Skip validation unless the previous privilege (mstatus.MPP) was U-mode */ + csrr \tx, mstatus + srli \tx, \tx, MSTATUS_MPP_SHIFT + andi \tx, \tx, (MSTATUS_MPP >> MSTATUS_MPP_SHIFT) + bnez \tx, 1f +.endif + li \tx, (SOC_S_DRAM_END + \framesz) + bltu sp, \tx, _tee_sp_reject /* frame would dip into the TEE (or sub-TEE) region */ + li \tx, SOC_PERIPHERAL_LOW + bltu \tx, sp, _tee_sp_reject /* sp at/above the peripheral window */ +.if \chk_priv +1: +.endif +.endm diff --git a/components/esp_tee/subproject/main/arch/riscv/esp_tee_vectors_clic.S b/components/esp_tee/subproject/main/arch/riscv/esp_tee_vectors_clic.S index bf64ea045d5..debc4f77a3d 100644 --- a/components/esp_tee/subproject/main/arch/riscv/esp_tee_vectors_clic.S +++ b/components/esp_tee/subproject/main/arch/riscv/esp_tee_vectors_clic.S @@ -25,6 +25,8 @@ .equ ECALL_M_MODE, 0xb .equ CSR_UINTTHRESH, 0x047 .equ CSR_MINTTHRESH, 0x347 + .equ MCAUSE_EXCCODE_SHIFT, 20 + .equ MSTATUS_MPP_SHIFT, 11 .global esp_tee_global_interrupt_handler .global esp_tee_service_dispatcher @@ -55,6 +57,10 @@ _ns_sp_min: _ns_sp_max: .word 0 + .global _ns_int_rtn +_ns_int_rtn: + .word 0 + .section .exception_vectors.text, "ax" /* Exception handler. */ @@ -62,28 +68,23 @@ _ns_sp_max: .global _tee_panic_handler .type _tee_panic_handler, @function _tee_exception_handler: - /* Backup t0, t1 on the stack before using it */ - addi sp, sp, -16 - sw t0, 0(sp) - sw t1, 4(sp) + /* Backup t0 before using it */ + csrw mscratch, t0 - /* Read mcause */ + /* Check whether the exception is an M-mode/U-mode ecall */ csrr t0, mcause - li t1, VECTORS_MCAUSE_REASON_MASK - and t0, t0, t1 + slli t0, t0, MCAUSE_EXCCODE_SHIFT + srli t0, t0, MCAUSE_EXCCODE_SHIFT + addi t0, t0, -ECALL_M_MODE + beqz t0, _machine_ecall /* M-mode ecall */ + addi t0, t0, (ECALL_M_MODE - ECALL_U_MODE) + beqz t0, _user_ecall /* U-mode ecall */ - /* Check whether the exception is an M-mode ecall */ - li t1, ECALL_M_MODE - beq t0, t1, _machine_ecall + /* Validate a U-mode-origin sp before the handler stores/dumps through it */ + VALIDATE_REE_SP RV_STK_FRMSZ, t0 - /* Check whether the exception is an U-mode ecall */ - li t1, ECALL_U_MODE - beq t0, t1, _user_ecall - - /* Restore t0, t1 from the stack */ - lw t0, 0(sp) - lw t1, 4(sp) - addi sp, sp, 16 + /* Restore t0 */ + csrr t0, mscratch _tee_panic_handler: /* Not an ecall, proceed to the panic handler */ @@ -147,6 +148,12 @@ _return_from_exception: restore_general_regs RV_STK_FRMSZ mret + /* Fault if the sp given by the REE is found to be out-of-bounds */ +_tee_sp_reject: + csrr t0, mscratch + la sp, _tee_stack + j _tee_panic_handler + .size _tee_exception_handler, .-_tee_exception_handler /* ECALL handler. */ @@ -211,14 +218,15 @@ _skip_ctx_restore: /* U-mode ecall handler */ _user_ecall: /* Check whether we are returning after servicing an U-mode interrupt */ - lui t0, RTNVAL - csrrw t1, mscratch, zero - beq t0, t1, _rtn_from_ns_int + la t0, _ns_int_rtn + lw t0, 0(t0) + bnez t0, _rtn_from_ns_int - /* Restore t0, t1 from the stack */ - lw t0, 0(sp) - lw t1, 4(sp) - addi sp, sp, 16 + /* Reject an sp whose frame would be out-of-bounds */ + VALIDATE_REE_SP CONTEXT_SIZE, t0, 0 + + /* Restore t0 */ + csrr t0, mscratch /* This point is reached when a secure service call is issued from the REE */ /* Save register context and mepc */ @@ -272,6 +280,10 @@ _2: /* This point is reached after servicing a U-mode interrupt occurred * while executing a secure service */ _rtn_from_ns_int: + /* Consume the U-mode-interrupt-return sentinel (checked in _user_ecall). */ + la t0, _ns_int_rtn + sw zero, 0(t0) + /* Disable the U-mode interrupt delegation */ li t0, INTMTX_SIG_IDX_ASSERT_IN_SEC_REG li t1, TEE_PASS_INUM + CLIC_EXT_INTR_NUM_OFFSET @@ -415,8 +427,9 @@ _4: fence /* Set a flag to identify the next U2M switch would be after handling a U-mode interrupt */ - lui t0, RTNVAL - csrw mscratch, t0 + la t0, _ns_int_rtn + li t1, RTNVAL + sw t1, 0(t0) STACK_GUARD_POST_SWITCH t3 1 _ns_sp_min _ns_sp_max @@ -435,6 +448,11 @@ _4: .global _tee_s_intr_handler .type _tee_s_intr_handler, @function _tee_s_intr_handler: + /* Check sp if trapped from U-mode */ + csrw mscratch, t0 + VALIDATE_REE_SP RV_STK_FRMSZ, t0 + csrr t0, mscratch /* restore the preempted t0 */ + /* Start by saving the general purpose registers and the PC value before * the interrupt happened. */ save_general_regs RV_STK_FRMSZ diff --git a/components/esp_tee/subproject/main/arch/riscv/esp_tee_vectors_plic.S b/components/esp_tee/subproject/main/arch/riscv/esp_tee_vectors_plic.S index 1274e5df3d6..28437683e35 100644 --- a/components/esp_tee/subproject/main/arch/riscv/esp_tee_vectors_plic.S +++ b/components/esp_tee/subproject/main/arch/riscv/esp_tee_vectors_plic.S @@ -23,6 +23,7 @@ .equ RTNVAL, 0xc0de .equ ECALL_U_MODE, 0x8 .equ ECALL_M_MODE, 0xb + .equ MSTATUS_MPP_SHIFT, 11 /* NOTE: INTWDT timeout, Cache error and Stack protection interrupts * trigger the panic handler before reset, so they don't need to be delegated. */ .equ TEE_INTR_DELEG_BASE, ((1U << TEE_SECURE_INUM) | (1U << ETS_INT_WDT_INUM) | (1U << ETS_CACHEERR_INUM)) @@ -60,6 +61,10 @@ _ns_sp_min: _ns_sp_max: .word 0 + .global _ns_int_rtn +_ns_int_rtn: + .word 0 + .section .exception_vectors.text, "ax" /* Exception handler. */ @@ -67,28 +72,22 @@ _ns_sp_max: .global _tee_panic_handler .type _tee_exception_handler, @function _tee_exception_handler: - /* Backup t0, t1 on the stack before using it */ - addi sp, sp, -16 - sw t0, 0(sp) - sw t1, 4(sp) + /* Backup t0 before using it */ + csrw mscratch, t0 - /* Read mcause */ + /* Check whether the exception is an M-mode/U-mode ecall */ csrr t0, mcause - li t1, VECTORS_MCAUSE_REASON_MASK - and t0, t0, t1 + andi t0, t0, VECTORS_MCAUSE_REASON_MASK + addi t0, t0, -ECALL_M_MODE + beqz t0, _machine_ecall /* M-mode ecall */ + addi t0, t0, (ECALL_M_MODE - ECALL_U_MODE) + beqz t0, _user_ecall /* U-mode ecall */ - /* Check whether the exception is an M-mode ecall */ - li t1, ECALL_M_MODE - beq t0, t1, _machine_ecall + /* Validate a U-mode-origin sp before the handler stores/dumps through it */ + VALIDATE_REE_SP RV_STK_FRMSZ, t0 - /* Check whether the exception is an U-mode ecall */ - li t1, ECALL_U_MODE - beq t0, t1, _user_ecall - - /* Restore t0, t1 from the stack */ - lw t0, 0(sp) - lw t1, 4(sp) - addi sp, sp, 16 + /* Restore t0 */ + csrr t0, mscratch _tee_panic_handler: /* Not an ecall, proceed to the panic handler */ @@ -143,6 +142,12 @@ _return_from_exception: restore_general_regs RV_STK_FRMSZ mret + /* Fault if the sp given by the REE is found to be out-of-bounds */ +_tee_sp_reject: + csrr t0, mscratch + la sp, _tee_stack + j _tee_panic_handler + .size _tee_exception_handler, .-_tee_exception_handler /* ECALL handler. */ @@ -203,14 +208,15 @@ _skip_ctx_restore: /* U-mode ecall handler */ _user_ecall: /* Check whether we are returning after servicing an U-mode interrupt */ - lui t0, RTNVAL - csrrw t1, mscratch, zero - beq t0, t1, _rtn_from_ns_int + la t0, _ns_int_rtn + lw t0, 0(t0) + bnez t0, _rtn_from_ns_int - /* Restore t0, t1 from the stack */ - lw t0, 0(sp) - lw t1, 4(sp) - addi sp, sp, 16 + /* Reject an sp whose frame would be out-of-bounds */ + VALIDATE_REE_SP CONTEXT_SIZE, t0, 0 + + /* Restore t0 */ + csrr t0, mscratch /* This point is reached when a secure service call is issued from the REE */ /* Save register context and mepc */ @@ -260,6 +266,10 @@ _process_ecall: /* This point is reached after servicing a U-mode interrupt occurred * while executing a secure service */ _rtn_from_ns_int: + /* Consume the U-mode-interrupt-return sentinel (checked in _user_ecall). */ + la t0, _ns_int_rtn + sw zero, 0(t0) + /* Disable the U-mode interrupt delegation */ csrwi mideleg, 0 @@ -341,8 +351,9 @@ _tee_ns_intr_handler: fence /* Set a flag to identify the next U2M switch would be after handling a U-mode interrupt */ - lui t0, RTNVAL - csrw mscratch, t0 + la t0, _ns_int_rtn + li t1, RTNVAL + sw t1, 0(t0) /* Enable the U-mode interrupt delegation (except for the TEE secure interrupt) */ li t0, TEE_INTR_DELEG_MASK @@ -365,6 +376,11 @@ _tee_ns_intr_handler: .global _tee_s_intr_handler .type _tee_s_intr_handler, @function _tee_s_intr_handler: + /* Check sp if trapped from U-mode */ + csrw mscratch, t0 + VALIDATE_REE_SP RV_STK_FRMSZ, t0 + csrr t0, mscratch /* restore the preempted t0 */ + /* Start by saving the general purpose registers and the PC value before * the interrupt happened. */ save_general_regs RV_STK_FRMSZ diff --git a/components/esp_tee/subproject/main/include/esp_tee_memory_utils.h b/components/esp_tee/subproject/main/include/esp_tee_memory_utils.h index e3ec2f50dfa..0d52b8fc636 100644 --- a/components/esp_tee/subproject/main/include/esp_tee_memory_utils.h +++ b/components/esp_tee/subproject/main/include/esp_tee_memory_utils.h @@ -16,19 +16,9 @@ extern "C" { #endif -FORCE_INLINE_ATTR bool esp_tee_ptr_in_ree(const void *p) -{ - uintptr_t addr = (uintptr_t)p; - return ( - (addr >= SOC_NS_IDRAM_START && addr < SOC_NS_IDRAM_END) || - (addr >= (uintptr_t)esp_tee_app_config.ns_drom_start && - addr < SOC_S_MMU_MMAP_RESV_START_VADDR) -#if SOC_RTC_MEM_SUPPORTED - || (addr >= SOC_RTC_DATA_LOW && addr < SOC_RTC_DATA_HIGH) -#endif - ); -} - +/* TODO: Revisit these bounds for high-performance RISC-V SoCs (e.g. ESP32-P4, + * ESP32-S31) with different memory maps than current ESP-TEE targets. + */ FORCE_INLINE_ATTR bool esp_tee_buf_in_ree(const void *p, size_t len) { uintptr_t start = (uintptr_t)p; @@ -40,13 +30,18 @@ FORCE_INLINE_ATTR bool esp_tee_buf_in_ree(const void *p, size_t len) uintptr_t end = start + len; return ((start >= SOC_NS_IDRAM_START && end <= SOC_NS_IDRAM_END) || - (start >= (uintptr_t)esp_tee_app_config.ns_drom_start && end <= SOC_S_MMU_MMAP_RESV_START_VADDR) + (start >= SOC_S_DROM_HIGH && end <= SOC_S_MMU_MMAP_RESV_START_VADDR) #if SOC_RTC_MEM_SUPPORTED || (start >= SOC_RTC_DATA_LOW && end <= SOC_RTC_DATA_HIGH) #endif ); } +FORCE_INLINE_ATTR bool esp_tee_ptr_in_ree(const void *p) +{ + return esp_tee_buf_in_ree(p, 4); +} + #ifdef __cplusplus } #endif diff --git a/components/esp_tee/subproject/main/soc/esp32c5/esp_tee_pmp_pma_prot_cfg.c b/components/esp_tee/subproject/main/soc/esp32c5/esp_tee_pmp_pma_prot_cfg.c index f7d47af6365..3947a6e72f2 100644 --- a/components/esp_tee/subproject/main/soc/esp32c5/esp_tee_pmp_pma_prot_cfg.c +++ b/components/esp_tee/subproject/main/soc/esp32c5/esp_tee_pmp_pma_prot_cfg.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -55,9 +55,9 @@ static void esp_tee_configure_invalid_regions(void) // 7. Using PMA to configure the TEE text and data section access attribute. */ PMA_ENTRY_CFG_RESET(12); - assert(IS_PMA_ENTRY_UNLOCKED(13)); - assert(IS_PMA_ENTRY_UNLOCKED(14)); - assert(IS_PMA_ENTRY_UNLOCKED(15)); + ESP_FAULT_ASSERT(IS_PMA_ENTRY_UNLOCKED(13) && + IS_PMA_ENTRY_UNLOCKED(14) && + IS_PMA_ENTRY_UNLOCKED(15)); extern int _tee_iram_end; PMA_RESET_AND_ENTRY_SET_TOR(13, SOC_S_IRAM_START, PMA_NONE); @@ -122,6 +122,20 @@ void esp_tee_configure_region_protection(void) PMP_ENTRY_CFG_RESET(4); PMP_ENTRY_CFG_RESET(5); PMP_ENTRY_CFG_RESET(6); + /* Validate the REE-supplied (esp_tee_app_config) bounds before programming + * the TOR-chained PMP entries below */ + const uint32_t ns_iram_end = (uint32_t)esp_tee_app_config.ns_iram_end; + const uint32_t s_irom_resv_end = SOC_IROM_LOW + CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE; + const uint32_t ns_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_irom_end); + const uint32_t ns_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_drom_end); + const uint32_t ns_drom_mmap_end = (uint32_t)(SOC_S_MMU_MMAP_RESV_START_VADDR); + + ESP_FAULT_ASSERT(ns_iram_end >= SOC_NS_IRAM_START && + ns_iram_end <= SOC_DRAM_HIGH && + s_irom_resv_end <= ns_irom_resv_end && + ns_irom_resv_end <= ns_drom_resv_end && + ns_drom_resv_end <= ns_drom_mmap_end); + if (esp_cpu_dbgr_is_attached()) { // Anti-FI check that cpu is really in ocd mode ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached()); @@ -131,15 +145,10 @@ void esp_tee_configure_region_protection(void) } else { // REE SRAM (D/IRAM) PMP_ENTRY_SET(4, (int)SOC_NS_IRAM_START, NONE); - PMP_ENTRY_SET(5, (int)esp_tee_app_config.ns_iram_end, PMP_TOR | RX); + PMP_ENTRY_SET(5, (int)ns_iram_end, PMP_TOR | RX); PMP_ENTRY_SET(6, SOC_DRAM_HIGH, PMP_TOR | RW); } - const uint32_t s_irom_resv_end = SOC_IROM_LOW + CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE; - const uint32_t ns_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_irom_end); - const uint32_t ns_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_drom_end); - const uint32_t ns_drom_mmap_end = (uint32_t)(SOC_S_MMU_MMAP_RESV_START_VADDR); - // 4. I_Cache / D_Cache (flash) - REE PMP_ENTRY_CFG_RESET(7); PMP_ENTRY_CFG_RESET(8); diff --git a/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_pmp_pma_prot_cfg.c b/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_pmp_pma_prot_cfg.c index bea234af031..4f977647f59 100644 --- a/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_pmp_pma_prot_cfg.c +++ b/components/esp_tee/subproject/main/soc/esp32c6/esp_tee_pmp_pma_prot_cfg.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -63,9 +63,9 @@ static void esp_tee_configure_invalid_regions(void) PMA_RESET_AND_ENTRY_SET_TOR(12, UINT32_MAX, PMA_TOR | PMA_NONE); // 8. Using PMA to configure the TEE text and data section access attribute. */ - assert(IS_PMA_ENTRY_UNLOCKED(13)); - assert(IS_PMA_ENTRY_UNLOCKED(14)); - assert(IS_PMA_ENTRY_UNLOCKED(15)); + ESP_FAULT_ASSERT(IS_PMA_ENTRY_UNLOCKED(13) && + IS_PMA_ENTRY_UNLOCKED(14) && + IS_PMA_ENTRY_UNLOCKED(15)); extern int _tee_iram_end; PMA_RESET_AND_ENTRY_SET_TOR(13, SOC_S_IRAM_START, PMA_NONE); @@ -112,7 +112,20 @@ void esp_tee_configure_region_protection(void) PMP_ENTRY_SET(1, SOC_IROM_MASK_HIGH, PMP_TOR | RX); _Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region"); - /* TODO: Check whether changes are required here */ + /* Validate the REE-supplied (esp_tee_app_config) bounds before programming + * the TOR-chained PMP entries below */ + const uint32_t ns_iram_end = (uint32_t)esp_tee_app_config.ns_iram_end; + const uint32_t s_irom_resv_end = SOC_IROM_LOW + CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE; + const uint32_t ns_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_irom_end); + const uint32_t ns_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_drom_end); + const uint32_t ns_drom_mmap_end = (uint32_t)(SOC_S_MMU_MMAP_RESV_START_VADDR); + + ESP_FAULT_ASSERT(ns_iram_end >= SOC_NS_IRAM_START && + ns_iram_end <= SOC_DRAM_HIGH && + s_irom_resv_end <= ns_irom_resv_end && + ns_irom_resv_end <= ns_drom_resv_end && + ns_drom_resv_end <= ns_drom_mmap_end); + if (esp_cpu_dbgr_is_attached()) { // Anti-FI check that cpu is really in ocd mode ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached()); @@ -125,15 +138,10 @@ void esp_tee_configure_region_protection(void) // 2. IRAM and DRAM // Splitting the REE SRAM region into IRAM and DRAM PMP_ENTRY_SET(2, (int)SOC_NS_IRAM_START, NONE); - PMP_ENTRY_SET(3, (int)esp_tee_app_config.ns_iram_end, PMP_TOR | RX); + PMP_ENTRY_SET(3, (int)ns_iram_end, PMP_TOR | RX); PMP_ENTRY_SET(4, SOC_DRAM_HIGH, PMP_TOR | RW); } - const uint32_t s_irom_resv_end = SOC_IROM_LOW + CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE; - const uint32_t ns_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_irom_end); - const uint32_t ns_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_drom_end); - const uint32_t ns_drom_mmap_end = (uint32_t)(SOC_S_MMU_MMAP_RESV_START_VADDR); - // 4. I_Cache / D_Cache (flash) - REE PMP_ENTRY_CFG_RESET(5); PMP_ENTRY_CFG_RESET(6); diff --git a/components/esp_tee/subproject/main/soc/esp32c61/esp_tee_pmp_pma_prot_cfg.c b/components/esp_tee/subproject/main/soc/esp32c61/esp_tee_pmp_pma_prot_cfg.c index 26c8116cf94..a574db48a7a 100644 --- a/components/esp_tee/subproject/main/soc/esp32c61/esp_tee_pmp_pma_prot_cfg.c +++ b/components/esp_tee/subproject/main/soc/esp32c61/esp_tee_pmp_pma_prot_cfg.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -55,9 +55,9 @@ static void esp_cpu_configure_invalid_regions(void) // 8. Using PMA to configure the TEE text and data section access attribute. */ PMA_ENTRY_CFG_RESET(12); - assert(IS_PMA_ENTRY_UNLOCKED(13)); - assert(IS_PMA_ENTRY_UNLOCKED(14)); - assert(IS_PMA_ENTRY_UNLOCKED(15)); + ESP_FAULT_ASSERT(IS_PMA_ENTRY_UNLOCKED(13) && + IS_PMA_ENTRY_UNLOCKED(14) && + IS_PMA_ENTRY_UNLOCKED(15)); extern int _tee_iram_end; PMA_RESET_AND_ENTRY_SET_TOR(13, SOC_S_IRAM_START, PMA_NONE); @@ -121,6 +121,20 @@ void esp_tee_configure_region_protection(void) PMP_ENTRY_CFG_RESET(4); PMP_ENTRY_CFG_RESET(5); PMP_ENTRY_CFG_RESET(6); + /* Validate the REE-supplied (esp_tee_app_config) bounds before programming + * the TOR-chained PMP entries below */ + const uint32_t ns_iram_end = (uint32_t)esp_tee_app_config.ns_iram_end; + const uint32_t s_irom_resv_end = SOC_IROM_LOW + CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE; + const uint32_t ns_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_irom_end); + const uint32_t ns_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_drom_end); + const uint32_t ns_drom_mmap_end = (uint32_t)(SOC_S_MMU_MMAP_RESV_START_VADDR); + + ESP_FAULT_ASSERT(ns_iram_end >= SOC_NS_IRAM_START && + ns_iram_end <= SOC_DRAM_HIGH && + s_irom_resv_end <= ns_irom_resv_end && + ns_irom_resv_end <= ns_drom_resv_end && + ns_drom_resv_end <= ns_drom_mmap_end); + if (esp_cpu_dbgr_is_attached()) { // Anti-FI check that cpu is really in ocd mode ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached()); @@ -130,15 +144,10 @@ void esp_tee_configure_region_protection(void) } else { // REE SRAM (D/IRAM) PMP_ENTRY_SET(4, (int)SOC_NS_IRAM_START, NONE); - PMP_ENTRY_SET(5, (int)esp_tee_app_config.ns_iram_end, PMP_TOR | RX); + PMP_ENTRY_SET(5, (int)ns_iram_end, PMP_TOR | RX); PMP_ENTRY_SET(6, SOC_DRAM_HIGH, PMP_TOR | RW); } - const uint32_t s_irom_resv_end = SOC_IROM_LOW + CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE; - const uint32_t ns_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_irom_end); - const uint32_t ns_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_drom_end); - const uint32_t ns_drom_mmap_end = (uint32_t)(SOC_S_MMU_MMAP_RESV_START_VADDR); - // 4. I_Cache / D_Cache (flash) - REE PMP_ENTRY_CFG_RESET(7); PMP_ENTRY_CFG_RESET(8); diff --git a/components/esp_tee/subproject/main/soc/esp32h2/esp_tee_pmp_pma_prot_cfg.c b/components/esp_tee/subproject/main/soc/esp32h2/esp_tee_pmp_pma_prot_cfg.c index 8de916768ce..5c7d3acd54b 100644 --- a/components/esp_tee/subproject/main/soc/esp32h2/esp_tee_pmp_pma_prot_cfg.c +++ b/components/esp_tee/subproject/main/soc/esp32h2/esp_tee_pmp_pma_prot_cfg.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -65,9 +65,9 @@ static void esp_tee_configure_invalid_regions(void) PMA_ENTRY_SET_TOR(12, UINT32_MAX, PMA_TOR | PMA_NONE); /* 8. Using PMA to configure the TEE text and data section access attribute. */ - assert(IS_PMA_ENTRY_UNLOCKED(13)); - assert(IS_PMA_ENTRY_UNLOCKED(14)); - assert(IS_PMA_ENTRY_UNLOCKED(15)); + ESP_FAULT_ASSERT(IS_PMA_ENTRY_UNLOCKED(13) && + IS_PMA_ENTRY_UNLOCKED(14) && + IS_PMA_ENTRY_UNLOCKED(15)); extern int _tee_iram_end; PMA_RESET_AND_ENTRY_SET_TOR(13, SOC_S_IRAM_START, PMA_NONE); @@ -108,7 +108,20 @@ void esp_tee_configure_region_protection(void) PMP_ENTRY_SET(0, pmpaddr0, PMP_NAPOT | RX); _Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region"); - /* TODO: Check whether changes are required here */ + /* Validate the REE-supplied (esp_tee_app_config) bounds before programming + * the TOR-chained PMP entries below */ + const uint32_t ns_iram_end = (uint32_t)esp_tee_app_config.ns_iram_end; + const uint32_t s_irom_resv_end = SOC_IROM_LOW + CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE; + const uint32_t ns_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_irom_end); + const uint32_t ns_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_drom_end); + const uint32_t ns_drom_mmap_end = (uint32_t)(SOC_S_MMU_MMAP_RESV_START_VADDR); + + ESP_FAULT_ASSERT(ns_iram_end >= SOC_NS_IRAM_START && + ns_iram_end <= SOC_DRAM_HIGH && + s_irom_resv_end <= ns_irom_resv_end && + ns_irom_resv_end <= ns_drom_resv_end && + ns_drom_resv_end <= ns_drom_mmap_end); + if (esp_cpu_dbgr_is_attached()) { // Anti-FI check that cpu is really in ocd mode ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached()); @@ -121,15 +134,10 @@ void esp_tee_configure_region_protection(void) // 2. IRAM and DRAM // Splitting the REE SRAM region into IRAM and DRAM PMP_ENTRY_SET(1, (int)SOC_NS_IRAM_START, NONE); - PMP_ENTRY_SET(2, (int)esp_tee_app_config.ns_iram_end, PMP_TOR | RX); + PMP_ENTRY_SET(2, (int)ns_iram_end, PMP_TOR | RX); PMP_ENTRY_SET(3, SOC_DRAM_HIGH, PMP_TOR | RW); } - const uint32_t s_irom_resv_end = SOC_IROM_LOW + CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE; - const uint32_t ns_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_irom_end); - const uint32_t ns_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)esp_tee_app_config.ns_drom_end); - const uint32_t ns_drom_mmap_end = (uint32_t)(SOC_S_MMU_MMAP_RESV_START_VADDR); - // 4. I_Cache / D_Cache (flash) - REE PMP_ENTRY_CFG_RESET(5); PMP_ENTRY_CFG_RESET(6); diff --git a/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt b/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt index af0c5563825..9c8e4c6e968 100644 --- a/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt +++ b/components/esp_tee/test_apps/tee_test_fw/main/CMakeLists.txt @@ -1,6 +1,6 @@ idf_build_get_property(idf_path IDF_PATH) -set(priv_requires bootloader_support esp_driver_gptimer esp_tee esp_timer mbedtls spi_flash) +set(priv_requires bootloader_support esp_driver_gptimer esp_system esp_tee esp_timer mbedtls spi_flash) # Test FW related list(APPEND priv_requires nvs_flash test_utils unity) # TEE related diff --git a/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_panic.c b/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_panic.c index 79382076166..63f004d011d 100644 --- a/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_panic.c +++ b/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_panic.c @@ -29,6 +29,7 @@ #include "unity.h" #include "esp_tee.h" +#include "esp_private/hw_stack_guard.h" #include "secure_service_num.h" #define ALIGN_DOWN_TO_MMU_PAGE_SIZE(addr) ((addr) & ~((SOC_MMU_PAGE_SIZE) - 1)) @@ -229,6 +230,25 @@ TEST_CASE("Test REE-TEE isolation: DROM-W1", "[exception]") TEST_FAIL_MESSAGE("Exception should have been generated"); } +TEST_CASE("Test REE-TEE isolation: Corrupted SP", "[exception]") +{ + uintptr_t atk_sp = (uintptr_t)&_iram_start - 0x100; + + /* Disable U-mode interrupts so the tick cannot preempt before the ecall */ + __asm__ volatile("csrci ustatus, 0x1\n\t" : : : "memory"); + + /* Stop the REE-owned HW stack guard, as a malicious REE could */ +#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD + esp_hw_stack_guard_monitor_stop(); +#endif + + /* Cross into the TEE with the doctored sp; the handler rejects it and panics */ + __asm__ volatile("mv sp, %0\n\t" + "ecall\n\t" : : "r"(atk_sp) : "memory"); + + TEST_FAIL_MESSAGE("Exception should have been generated"); +} + static void do_stack_overflow(int depth, volatile uint8_t *sink) { if (depth == -1) { diff --git a/components/esp_tee/test_apps/tee_test_fw/tee_exception_test_map.py b/components/esp_tee/test_apps/tee_test_fw/tee_exception_test_map.py index 7590bae9469..b53d7d5df9c 100644 --- a/components/esp_tee/test_apps/tee_test_fw/tee_exception_test_map.py +++ b/components/esp_tee/test_apps/tee_test_fw/tee_exception_test_map.py @@ -23,6 +23,7 @@ _BASE_CONFIG = { 'DROM-R1': 'Load access fault', 'DROM-W1': 'Store access fault', 'MMU-spillover': 'Illegal instruction', + 'Corrupted SP': 'Environment call from U-mode', }, 'apm_violation': { 'eFuse': 'APM - Space exception',