fix(esp_tee): enforce MMU-map vaddr validity at the REE->TEE boundary

This commit is contained in:
Ashish Sharma
2026-07-07 11:00:40 +08:00
committed by Laukik Hase
parent c146cb5322
commit 2fcdb164a1
3 changed files with 58 additions and 7 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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)
{