Skip to content

Commit 73d0dad

Browse files
committed
fix(esp_tee): Correct flash operation bound checks to handle all overlap cases
- Ensure bound checks correctly handle all scenarios, including when a requested operation's (SPI0/1) range fully contains the TEE-protected region. - Disable delegation of INTWDT timeout and Cache error interrupts as they reset the device after the panic handler
1 parent 22fe84b commit 73d0dad

File tree

8 files changed

+103
-18
lines changed

8 files changed

+103
-18
lines changed

components/bootloader_support/bootloader_flash/src/bootloader_flash.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
138138
#include "esp_flash_partitions.h"
139139
#include "rom/spi_flash.h"
140140

141-
extern bool esp_tee_flash_check_paddr_in_active_tee_part(size_t paddr);
141+
extern bool esp_tee_flash_check_prange_in_active_tee_part(const size_t paddr, const size_t len);
142142
#endif
143143

144144
static const char *TAG = "bootloader_flash";
@@ -524,7 +524,7 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
524524
* by validating the address before proceeding.
525525
*/
526526
#if ESP_TEE_BUILD
527-
bool addr_chk = esp_tee_flash_check_paddr_in_active_tee_part(dest_addr);
527+
bool addr_chk = esp_tee_flash_check_prange_in_active_tee_part(dest_addr, size);
528528
if (addr_chk) {
529529
ESP_EARLY_LOGE(TAG, "bootloader_flash_write invalid dest_addr");
530530
return ESP_FAIL;
@@ -578,7 +578,7 @@ esp_err_t bootloader_flash_erase_sector(size_t sector)
578578
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
579579
{
580580
#if ESP_TEE_BUILD
581-
bool addr_chk = esp_tee_flash_check_paddr_in_active_tee_part(start_addr);
581+
bool addr_chk = esp_tee_flash_check_prange_in_active_tee_part(start_addr, size);
582582
if (addr_chk) {
583583
return ESP_ERR_INVALID_ARG;
584584
}

components/esp_tee/subproject/components/tee_flash_mgr/esp_tee_flash.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,36 @@ bool esp_tee_flash_check_paddr_in_active_tee_part(const size_t paddr)
208208
{
209209
return ((paddr >= tee_prot_ctx.active_part_start_paddr) && (paddr < tee_prot_ctx.active_part_end_paddr));
210210
}
211+
212+
bool esp_tee_flash_check_vrange_in_tee_region(const size_t vaddr, const size_t len)
213+
{
214+
size_t vaddr_end = vaddr + len;
215+
if (vaddr_end < vaddr) {
216+
return true;
217+
}
218+
219+
bool prot_reg1_overlap = ((vaddr < SOC_S_IROM_HIGH) && (vaddr_end > SOC_S_DROM_LOW));
220+
bool prot_reg2_overlap = ((vaddr < SOC_MMU_END_VADDR) && (vaddr_end > SOC_S_MMU_MMAP_RESV_START_VADDR));
221+
222+
return (prot_reg1_overlap || prot_reg2_overlap);
223+
}
224+
225+
bool esp_tee_flash_check_prange_in_tee_region(const size_t paddr, const size_t len)
226+
{
227+
size_t paddr_end = paddr + len;
228+
if (paddr_end < paddr) {
229+
return true;
230+
}
231+
232+
return ((paddr < tee_prot_ctx.flash_reg_end_paddr) && (paddr_end > tee_prot_ctx.flash_reg_start_paddr));
233+
}
234+
235+
bool esp_tee_flash_check_prange_in_active_tee_part(const size_t paddr, const size_t len)
236+
{
237+
size_t paddr_end = paddr + len;
238+
if (paddr_end < paddr) {
239+
return true;
240+
}
241+
242+
return ((paddr < tee_prot_ctx.active_part_end_paddr) && (paddr_end > tee_prot_ctx.active_part_start_paddr));
243+
}

components/esp_tee/subproject/components/tee_flash_mgr/include/esp_tee_flash.h

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -80,7 +80,7 @@ esp_partition_info_t *esp_tee_flash_get_running_ree_partition(void);
8080
/**
8181
* @brief Check if the given virtual address falls within the TEE flash protected region
8282
*
83-
* @param addr Virtual address to check
83+
* @param vaddr Virtual address to check
8484
*
8585
* @return bool true if address is within protected region, false otherwise
8686
*/
@@ -89,7 +89,7 @@ bool esp_tee_flash_check_vaddr_in_tee_region(const size_t vaddr);
8989
/**
9090
* @brief Check if the given physical address falls within the TEE flash protected region
9191
*
92-
* @param addr Physical address to check
92+
* @param paddr Physical address to check
9393
*
9494
* @return bool true if address is within protected region, false otherwise
9595
*/
@@ -98,8 +98,38 @@ bool esp_tee_flash_check_paddr_in_tee_region(const size_t paddr);
9898
/**
9999
* @brief Check if the given physical address falls within the active TEE partition
100100
*
101-
* @param dest_addr Physical address to check
101+
* @param paddr Physical address to check
102102
*
103103
* @return bool true if address is within active TEE partition, false otherwise
104104
*/
105105
bool esp_tee_flash_check_paddr_in_active_tee_part(const size_t paddr);
106+
107+
/**
108+
* @brief Check if the given virtual address range overlaps with TEE flash protected regions
109+
*
110+
* @param vaddr Starting virtual address of the range to check
111+
* @param len Length of the address range in bytes
112+
*
113+
* @return bool true if any part of the range overlaps with protected regions, false otherwise
114+
*/
115+
bool esp_tee_flash_check_vrange_in_tee_region(const size_t vaddr, const size_t len);
116+
117+
/**
118+
* @brief Check if the given physical address range overlaps with TEE flash protected region
119+
*
120+
* @param paddr Starting physical address of the range to check
121+
* @param len Length of the address range in bytes
122+
*
123+
* @return bool true if any part of the range overlaps with TEE protected region, false otherwise
124+
*/
125+
bool esp_tee_flash_check_prange_in_tee_region(const size_t paddr, const size_t len);
126+
127+
/**
128+
* @brief Check if the given physical address range overlaps with active TEE partition
129+
*
130+
* @param paddr Starting physical address of the range to check
131+
* @param len Length of the address range in bytes
132+
*
133+
* @return bool true if any part of the range overlaps with active TEE partition, false otherwise
134+
*/
135+
bool esp_tee_flash_check_prange_in_active_tee_part(const size_t paddr, const size_t len);

components/esp_tee/subproject/main/arch/riscv/esp_tee_vectors_plic.S

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
.equ RTNVAL, 0xc0de
2424
.equ ECALL_U_MODE, 0x8
2525
.equ ECALL_M_MODE, 0xb
26-
.equ TEE_INTR_DELEG_MASK, ~(1U << TEE_SECURE_INUM)
26+
/* NOTE: INTWDT timeout and Cache error interrupts trigger the panic
27+
* handler before reset, so they don’t need to be delegated. */
28+
.equ TEE_INTR_DELEG_MASK, ~((1U << TEE_SECURE_INUM) | (1U << ETS_INT_WDT_INUM) | (1U << ETS_CACHEERR_INUM))
2729

2830
.global esp_tee_global_interrupt_handler
2931
.global esp_tee_service_dispatcher

components/esp_tee/subproject/main/core/esp_secure_services_iram.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,8 @@ esp_err_t _ss_esp_tee_sec_storage_ecdsa_sign_pbkdf2(const esp_tee_sec_storage_pb
219219
void _ss_mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vaddr,
220220
uint32_t paddr, uint32_t len, uint32_t *out_len)
221221
{
222-
bool vaddr_chk = esp_tee_flash_check_vaddr_in_tee_region(vaddr);
223-
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(paddr);
222+
bool vaddr_chk = esp_tee_flash_check_vrange_in_tee_region(vaddr, len);
223+
bool paddr_chk = esp_tee_flash_check_prange_in_tee_region(paddr, len);
224224
if (vaddr_chk || paddr_chk) {
225225
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x | 0x%08x", __func__, vaddr, paddr);
226226
return;
@@ -232,7 +232,7 @@ void _ss_mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vad
232232

233233
void _ss_mmu_hal_unmap_region(uint32_t mmu_id, uint32_t vaddr, uint32_t len)
234234
{
235-
bool vaddr_chk = esp_tee_flash_check_vaddr_in_tee_region(vaddr);
235+
bool vaddr_chk = esp_tee_flash_check_vrange_in_tee_region(vaddr, len);
236236
if (vaddr_chk) {
237237
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, vaddr);
238238
return;
@@ -279,7 +279,8 @@ uint32_t _ss_spi_flash_hal_check_status(spi_flash_host_inst_t *host)
279279

280280
esp_err_t _ss_spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans)
281281
{
282-
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(trans->address);
282+
bool paddr_chk = esp_tee_flash_check_prange_in_tee_region(trans->address, trans->mosi_len);
283+
paddr_chk |= esp_tee_flash_check_prange_in_tee_region(trans->address, trans->miso_len);
283284
if (paddr_chk) {
284285
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, trans->address);
285286
return ESP_FAIL;
@@ -310,7 +311,7 @@ void _ss_spi_flash_hal_erase_chip(spi_flash_host_inst_t *host)
310311

311312
void _ss_spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address)
312313
{
313-
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(start_address);
314+
bool paddr_chk = esp_tee_flash_check_prange_in_tee_region(start_address, FLASH_SECTOR_SIZE);
314315
if (paddr_chk) {
315316
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, start_address);
316317
return;
@@ -321,7 +322,7 @@ void _ss_spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_
321322

322323
void _ss_spi_flash_hal_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length)
323324
{
324-
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(address);
325+
bool paddr_chk = esp_tee_flash_check_prange_in_tee_region(address, length);
325326
if (paddr_chk) {
326327
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, address);
327328
return;
@@ -338,7 +339,7 @@ void _ss_spi_flash_hal_program_page(spi_flash_host_inst_t *host, const void *buf
338339

339340
esp_err_t _ss_spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len)
340341
{
341-
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(address);
342+
bool paddr_chk = esp_tee_flash_check_prange_in_tee_region(address, read_len);
342343
if (paddr_chk) {
343344
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, address);
344345
return ESP_FAIL;
@@ -396,10 +397,11 @@ uint32_t _ss_bootloader_flash_execute_command_common(
396397
uint8_t mosi_len, uint32_t mosi_data,
397398
uint8_t miso_len)
398399
{
399-
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(address);
400+
bool paddr_chk = esp_tee_flash_check_prange_in_tee_region(address, mosi_len);
401+
paddr_chk |= esp_tee_flash_check_prange_in_tee_region(address, miso_len);
400402
if (paddr_chk) {
401403
ESP_LOGD(TAG, "[%s] Illegal flash access at 0x%08x", __func__, address);
402-
return ESP_FAIL;
404+
return 0;
403405
}
404406
ESP_FAULT_ASSERT(!paddr_chk);
405407
return bootloader_flash_execute_command_common(command, addr_len, address, dummy_len,
@@ -408,7 +410,7 @@ uint32_t _ss_bootloader_flash_execute_command_common(
408410

409411
esp_err_t _ss_memspi_host_flush_cache(spi_flash_host_inst_t *host, uint32_t addr, uint32_t size)
410412
{
411-
bool paddr_chk = esp_tee_flash_check_paddr_in_tee_region(addr);
413+
bool paddr_chk = esp_tee_flash_check_prange_in_tee_region(addr, size);
412414
if (paddr_chk) {
413415
return ESP_FAIL;
414416
}

components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_flash_prot.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,16 @@ TEST_CASE_MULTIPLE_STAGES("Test REE-TEE isolation: Flash - SPI0 (spi_flash_mmap)
250250
test_initial_boot, test_spi_flash_mmap_api, test_spi_flash_mmap_api,
251251
test_spi_flash_mmap_api);
252252

253+
TEST_CASE("Test REE-TEE isolation: MMU-spillover", "[exception]")
254+
{
255+
const void *ptr;
256+
spi_flash_mmap_handle_t handle;
257+
const size_t len = 0x100000; // 1MB
258+
TEST_ESP_OK(spi_flash_mmap(0x00, len, SPI_FLASH_MMAP_DATA, &ptr, &handle));
259+
ESP_LOG_BUFFER_HEXDUMP(TAG, ptr, 32, ESP_LOG_INFO);
260+
TEST_FAIL_MESSAGE("Exception should have been generated!");
261+
}
262+
253263
/* ---------------------------------------------- API family 3: esp_flash ------------------------------------------------- */
254264

255265
#if CONFIG_SECURE_TEE_EXT_FLASH_MEMPROT_SPI1

components/esp_tee/test_apps/tee_test_fw/pytest_esp_tee_ut.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
('IROM-W1'): 'Store access fault',
5353
('DROM-R1'): 'Load access fault',
5454
('DROM-W1'): 'Store access fault',
55+
('MMU-spillover'): 'Cache error',
5556
}
5657

5758
TEE_APM_VIOLATION_EXC_CHK = ['eFuse', 'MMU', 'AES', 'HMAC', 'DS', 'SHA PCR', 'ECC PCR', 'SWDT/BOD']

components/mbedtls/test_apps/main/test_sha.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ TEST_CASE("Test esp_sha()", "[hw_crypto]")
117117
#endif
118118
}
119119

120+
/* NOTE: This test attempts to mmap 1MB of flash starting from address 0x00, which overlaps
121+
* the entire TEE protected region, causing the mmap operation to fail and triggering an
122+
* exception in the subsequent steps.
123+
*/
124+
#if !CONFIG_SECURE_ENABLE_TEE
125+
120126
TEST_CASE("Test esp_sha() function with long input", "[hw_crypto]")
121127
{
122128
int r = -1;
@@ -173,6 +179,7 @@ TEST_CASE("Test esp_sha() function with long input", "[hw_crypto]")
173179
#endif
174180
}
175181

182+
#endif
176183

177184
#if CONFIG_MBEDTLS_HARDWARE_SHA
178185

0 commit comments

Comments
 (0)