From 2fcdb164a16985e800fb45cc037f54acf50a0b02 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Tue, 7 Jul 2026 11:00:40 +0800 Subject: [PATCH] fix(esp_tee): enforce MMU-map vaddr validity at the REE->TEE boundary --- .../main/core/esp_secure_services_iram.c | 48 ++++++++++++++++--- components/hal/include/hal/mmu_hal.h | 12 +++++ components/hal/mmu_hal.c | 5 ++ 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/components/esp_tee/subproject/main/core/esp_secure_services_iram.c b/components/esp_tee/subproject/main/core/esp_secure_services_iram.c index b5030720fc4..5f8fea28433 100644 --- a/components/esp_tee/subproject/main/core/esp_secure_services_iram.c +++ b/components/esp_tee/subproject/main/core/esp_secure_services_iram.c @@ -8,6 +8,7 @@ #include "esp_err.h" #include "esp_log.h" +#include "esp_macros.h" #include "esp_fault.h" #include "hal/mmu_types.h" @@ -38,6 +39,9 @@ static __attribute__((unused)) const char *TAG = "esp_tee_sec_srv_iram"; +#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) +#define ALIGN_DOWN(num, align) ((num) & ~((align) - 1)) + /* ---------------------------------------------- Interrupts ------------------------------------------------- */ #if SOC_INT_CLIC_SUPPORTED @@ -274,11 +278,37 @@ esp_err_t _ss_esp_tee_sec_storage_ecdsa_sign_pbkdf2(const esp_tee_sec_storage_pb /* ---------------------------------------------- MMU HAL ------------------------------------------------- */ +/* Gates for REE-supplied external-flash address ranges. The HAL maps whole pages, + * so validate the page-rounded span it will actually touch (not the raw byte len) + * and require page-aligned addresses, so a sub-page or misaligned request cannot + * smuggle in an adjacent TEE page. mmu_hal_check_valid_ext_vaddr_region() must be + * enforced HERE, at the boundary: it rejects out-of-window (aliased) vaddrs. */ +static bool tee_ree_ext_vaddr_ok(uint32_t mmu_id, uint32_t vaddr, uint32_t len) +{ + uint32_t page = mmu_hal_pages_to_bytes(mmu_id, 1); + uint32_t map_len = ALIGN_UP(len, page); + + return (len != 0 && map_len >= len && (vaddr % page == 0) && + mmu_hal_check_valid_ext_vaddr_region(mmu_id, vaddr, map_len, + MMU_VADDR_DATA | MMU_VADDR_INSTRUCTION) && + !esp_tee_flash_check_vrange_in_tee_region(vaddr, map_len)); +} + +static bool tee_ree_ext_paddr_ok(uint32_t mmu_id, uint32_t paddr, uint32_t len) +{ + uint32_t page = mmu_hal_pages_to_bytes(mmu_id, 1); + uint32_t map_len = ALIGN_UP(len, page); + + return (len != 0 && map_len >= len && (paddr % page == 0) && + mmu_hal_check_valid_paddr_region(mmu_id, paddr, map_len) && + !esp_tee_flash_check_prange_in_tee_region(paddr, map_len)); +} + void _ss_mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vaddr, uint32_t paddr, uint32_t len, uint32_t *out_len) { - bool valid_addr = (!esp_tee_flash_check_vrange_in_tee_region(vaddr, len) && - !esp_tee_flash_check_prange_in_tee_region(paddr, len) && + bool valid_addr = (tee_ree_ext_vaddr_ok(mmu_id, vaddr, len) && + tee_ree_ext_paddr_ok(mmu_id, paddr, len) && esp_tee_buf_in_ree(out_len, sizeof(uint32_t))); if (!valid_addr) { @@ -292,20 +322,23 @@ void _ss_mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vad void _ss_mmu_hal_unmap_region(uint32_t mmu_id, uint32_t vaddr, uint32_t len) { - bool vaddr_chk = esp_tee_flash_check_vrange_in_tee_region(vaddr, len); + bool valid_addr = tee_ree_ext_vaddr_ok(mmu_id, vaddr, len); - if (vaddr_chk) { + if (!valid_addr) { ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, vaddr); return; } - ESP_FAULT_ASSERT(!vaddr_chk); + ESP_FAULT_ASSERT(valid_addr); mmu_hal_unmap_region(mmu_id, vaddr, len); } bool _ss_mmu_hal_vaddr_to_paddr(uint32_t mmu_id, uint32_t vaddr, uint32_t *out_paddr, mmu_target_t *out_target) { - bool valid_addr = (!esp_tee_flash_check_vaddr_in_tee_region(vaddr) && + /* Same aliasing gate as map/unmap; translation itself is page-granular and + * vaddr need not be aligned, so validate the page containing it. */ + uint32_t page = mmu_hal_pages_to_bytes(mmu_id, 1); + bool valid_addr = (tee_ree_ext_vaddr_ok(mmu_id, ALIGN_DOWN(vaddr, page), 1) && esp_tee_buf_in_ree(out_paddr, sizeof(uint32_t)) && esp_tee_buf_in_ree(out_target, sizeof(mmu_target_t))); @@ -319,7 +352,8 @@ bool _ss_mmu_hal_vaddr_to_paddr(uint32_t mmu_id, uint32_t vaddr, uint32_t *out_p bool _ss_mmu_hal_paddr_to_vaddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target, mmu_vaddr_t type, uint32_t *out_vaddr) { - bool valid_addr = (!esp_tee_flash_check_paddr_in_tee_region(paddr) && + bool valid_addr = (mmu_hal_check_valid_paddr_region(mmu_id, paddr, 1) && + !esp_tee_flash_check_paddr_in_tee_region(paddr) && esp_tee_buf_in_ree(out_vaddr, sizeof(uint32_t))); if (!valid_addr) { diff --git a/components/hal/include/hal/mmu_hal.h b/components/hal/include/hal/mmu_hal.h index 779af2d068e..82551ea7152 100644 --- a/components/hal/include/hal/mmu_hal.h +++ b/components/hal/include/hal/mmu_hal.h @@ -149,6 +149,18 @@ bool mmu_hal_paddr_to_vaddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target */ bool mmu_hal_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t vaddr_start, uint32_t len, mmu_vaddr_t type); +/** + * Check if the paddr region is valid + * + * @param mmu_id MMU ID + * @param paddr_start start of the physical address + * @param len length, in bytes + * + * @return + * True for valid + */ +bool mmu_hal_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len); + #if SOC_MMU_PER_EXT_MEM_TARGET /** * Get MMU ID from MMU target diff --git a/components/hal/mmu_hal.c b/components/hal/mmu_hal.c index 5c83a9681fd..0cd593d8efa 100644 --- a/components/hal/mmu_hal.c +++ b/components/hal/mmu_hal.c @@ -197,6 +197,11 @@ bool mmu_hal_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t vaddr_start, return mmu_ll_check_valid_ext_vaddr_region(mmu_id, vaddr_start, len, type); } +bool mmu_hal_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len) +{ + return mmu_ll_check_valid_paddr_region(mmu_id, paddr_start, len); +} + #if SOC_MMU_PER_EXT_MEM_TARGET uint32_t mmu_hal_get_id_from_target(mmu_target_t target) {