From d4428869181b09f48a8df4878e580761b00d8047 Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Mon, 24 Mar 2025 16:34:50 +0530 Subject: [PATCH 1/3] refactor(esp_tee): Refactor the TEE heap-related APIs --- .../subproject/main/common/multi_heap.c | 54 ++++---- .../subproject/main/core/esp_tee_init.c | 2 +- .../subproject/main/include/multi_heap.h | 117 ++++++++++-------- .../test_sec_srv/src/test_dummy_srv.c | 9 +- 4 files changed, 101 insertions(+), 81 deletions(-) diff --git a/components/esp_tee/subproject/main/common/multi_heap.c b/components/esp_tee/subproject/main/common/multi_heap.c index 6d92034cca..091f98e381 100644 --- a/components/esp_tee/subproject/main/common/multi_heap.c +++ b/components/esp_tee/subproject/main/common/multi_heap.c @@ -34,12 +34,12 @@ static void assert_valid_block(const heap_t *heap, const block_header_t *block) (uintptr_t)ptr); } -int tee_heap_register(void *start_ptr, size_t size) +esp_err_t esp_tee_heap_init(void *start_ptr, size_t size) { assert(start_ptr); if (size < (sizeof(heap_t))) { - //Region too small to be a heap. - return -1; + // Region too small to be a heap. + return ESP_ERR_INVALID_SIZE; } heap_t *result = (heap_t *)start_ptr; @@ -50,7 +50,7 @@ int tee_heap_register(void *start_ptr, size_t size) result->heap_data = tlsf_create_with_pool(start_ptr + sizeof(heap_t), size, max_bytes); if (result->heap_data == NULL) { - return -1; + return ESP_FAIL; } result->lock = NULL; @@ -60,10 +60,10 @@ int tee_heap_register(void *start_ptr, size_t size) tee_heap = (multi_heap_handle_t)result; - return 0; + return ESP_OK; } -void *tee_heap_malloc(size_t size) +void *esp_tee_heap_malloc(size_t size) { if (tee_heap == NULL || size == 0) { return NULL; @@ -81,17 +81,17 @@ void *tee_heap_malloc(size_t size) return result; } -void *tee_heap_calloc(size_t n, size_t size) +void *esp_tee_heap_calloc(size_t n, size_t size) { size_t reg_size = n * size; - void *ptr = tee_heap_malloc(reg_size); + void *ptr = esp_tee_heap_malloc(reg_size); if (ptr != NULL) { memset(ptr, 0x00, reg_size); } return ptr; } -void *tee_heap_aligned_alloc(size_t size, size_t alignment) +void *esp_tee_heap_aligned_alloc(size_t size, size_t alignment) { if (tee_heap == NULL || size == 0) { return NULL; @@ -114,7 +114,7 @@ void *tee_heap_aligned_alloc(size_t size, size_t alignment) return result; } -void tee_heap_free(void *p) +void esp_tee_heap_free(void *p) { if (tee_heap == NULL || p == NULL) { return; @@ -129,25 +129,27 @@ void tee_heap_free(void *p) void *malloc(size_t size) { - return tee_heap_malloc(size); + return esp_tee_heap_malloc(size); } void *calloc(size_t n, size_t size) { - return tee_heap_calloc(n, size); + return esp_tee_heap_calloc(n, size); } void free(void *ptr) { - tee_heap_free(ptr); + esp_tee_heap_free(ptr); } -void tee_heap_dump_free_size(void) +size_t esp_tee_heap_get_free_size(void) { - if (tee_heap == NULL) { - return; - } - printf("Free: %uB | Minimum free: %uB\n", tee_heap->free_bytes, tee_heap->minimum_free_bytes); + return tee_heap->free_bytes; +} + +size_t esp_tee_heap_get_min_free_size(void) +{ + return tee_heap->minimum_free_bytes; } static bool tee_heap_dump_tlsf(void* ptr, size_t size, int used, void* user) @@ -160,14 +162,10 @@ static bool tee_heap_dump_tlsf(void* ptr, size_t size, int used, void* user) return true; } -void tee_heap_dump_info(void) +void esp_tee_heap_dump_info(void) { - if (tee_heap == NULL) { - return; - } - printf("Showing data for TEE heap: %p\n", (void *)tee_heap); - tee_heap_dump_free_size(); - tlsf_walk_pool(tlsf_get_pool(tee_heap->heap_data), tee_heap_dump_tlsf, NULL); + printf("Showing data for TEE heap: %p (%uB)\n", (void *)tee_heap, tee_heap->pool_size); + tlsf_walk_pool(tlsf_get_pool(tee_heap->heap_data), heap_dump_tlsf, NULL); } /* Definitions for functions from the heap component, used in files shared with ESP-IDF */ @@ -175,13 +173,13 @@ void tee_heap_dump_info(void) void *heap_caps_malloc(size_t alignment, size_t size, uint32_t caps) { (void) caps; - return tee_heap_malloc(size); + return esp_tee_heap_malloc(size); } void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t caps) { (void) caps; - return tee_heap_aligned_alloc(size, alignment); + return esp_tee_heap_aligned_alloc(size, alignment); } void *heap_caps_aligned_calloc(size_t alignment, size_t n, size_t size, uint32_t caps) @@ -189,7 +187,7 @@ void *heap_caps_aligned_calloc(size_t alignment, size_t n, size_t size, uint32_t (void) caps; uint32_t reg_size = n * size; - void *ptr = tee_heap_aligned_alloc(reg_size, alignment); + void *ptr = esp_tee_heap_aligned_alloc(reg_size, alignment); if (ptr != NULL) { memset(ptr, 0x00, reg_size); } diff --git a/components/esp_tee/subproject/main/core/esp_tee_init.c b/components/esp_tee/subproject/main/core/esp_tee_init.c index 995f282769..ddd12b4596 100644 --- a/components/esp_tee/subproject/main/core/esp_tee_init.c +++ b/components/esp_tee/subproject/main/core/esp_tee_init.c @@ -132,7 +132,7 @@ void __attribute__((noreturn)) esp_tee_init(uint32_t ree_entry_addr, uint32_t re tee_init_app_config(); /* TEE Secure World heap initialization. */ - assert(tee_heap_register(((void *)&_tee_heap_start), TEE_HEAP_SIZE) == 0); + assert(esp_tee_heap_init(((void *)&_tee_heap_start), TEE_HEAP_SIZE) == ESP_OK); /* SoC specific secure initialization. */ esp_tee_soc_secure_sys_init(); diff --git a/components/esp_tee/subproject/main/include/multi_heap.h b/components/esp_tee/subproject/main/include/multi_heap.h index c46c401a71..8b83e814e5 100644 --- a/components/esp_tee/subproject/main/include/multi_heap.h +++ b/components/esp_tee/subproject/main/include/multi_heap.h @@ -1,11 +1,11 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include -#include "tlsf.h" +#include "esp_err.h" /* multi_heap is a heap implementation for handling multiple heterogeneous heaps in a single program. @@ -29,70 +29,89 @@ typedef struct multi_heap_info heap_t; /** @brief Opaque handle to a registered heap */ typedef struct multi_heap_info *multi_heap_handle_t; -/** @brief malloc() a buffer in a given heap +/** @brief Initialize the TEE heap * - * Semantics are the same as standard malloc(), only the returned buffer will be allocated in the TEE heap. + * This function initialises the TEE heap at the specified address, and + * sets up a handle for future heap operations. * - * @param size Size of desired buffer. + * @param start Start address of the memory to use for the TEE heap. + * @param size Size (in bytes) of the TEE heap. * - * @return Pointer to new memory, or NULL if allocation fails. + * @return ESP_OK on success, or an `esp_err_t` error code on failure. */ -void *tee_heap_malloc(size_t size); - -/** @brief calloc() a buffer in a given heap - * - * Semantics are the same as standard calloc(), only the returned buffer will be allocated in the TEE heap. - * - * @param size Size of desired buffer. - * - * @return Pointer to new memory, or NULL if allocation fails. - */ -void *tee_heap_calloc(size_t n, size_t size); +esp_err_t esp_tee_heap_init(void *start, size_t size); /** - * @brief allocate a chunk of memory with specific alignment + * @brief Allocate a buffer (malloc) in the TEE heap * - * @param heap Handle to a registered heap. - * @param size size in bytes of memory chunk - * @param alignment how the memory must be aligned + * This function allocates a buffer of the specified size in the TEE heap. + * The semantics are the same as the standard malloc(). * - * @return pointer to the memory allocated, NULL on failure + * @param size The size of the desired buffer in bytes. + * + * @return A pointer to the newly allocated memory, or NULL if the allocation fails. */ -void *tee_heap_aligned_alloc(size_t size, size_t alignment); - -/** @brief free() a buffer in a given heap. - * - * Semantics are the same as standard free(), only the argument 'p' must be NULL or have been allocated in the TEE heap. - * - * @param p NULL, or a pointer previously returned from multi_heap_malloc() or multi_heap_realloc() for the same heap. - */ -void tee_heap_free(void *p); - -/** @brief Register a new heap for use - * - * This function initialises a heap at the specified address, and returns a handle for future heap operations. - * - * There is no equivalent function for deregistering a heap - if all blocks in the heap are free, you can immediately start using the memory for other purposes. - * - * @param start Start address of the memory to use for a new heap. - * @param size Size (in bytes) of the new heap. - * - * @return Handle of a new heap ready for use, or NULL if the heap region was too small to be initialised. - */ -int tee_heap_register(void *start, size_t size); +void *esp_tee_heap_malloc(size_t size); /** - * @brief Dump free and minimum free TEE heap information to stdout + * @brief Allocate and zero-initialize (calloc) a buffer in the TEE heap * + * This function allocates a buffer for an array of 'n' elements, each of 'size' bytes, + * and initializes all bytes in the allocated storage to zero. The semantics are the same + * as the standard calloc(). + * + * @param n The number of elements to allocate. + * @param size The size of each element in bytes. + * + * @return A pointer to the newly allocated and zero-initialized memory, or NULL if the allocation fails. */ -void tee_heap_dump_free_size(void); +void *esp_tee_heap_calloc(size_t n, size_t size); -/** @brief Dump TEE heap information to stdout +/** + * @brief Allocate a memory chunk with specific alignment in the TEE heap * - * For debugging purposes, this function dumps information about every block in the heap to stdout. + * This function allocates a chunk of memory of the specified size with the specified alignment + * in the TEE heap. * + * @param size The size in bytes of the memory chunk. + * @param alignment The alignment requirement for the memory chunk. + * + * @return A pointer to the allocated memory, or NULL if the allocation fails. */ -void tee_heap_dump_info(void); +void *esp_tee_heap_aligned_alloc(size_t size, size_t alignment); + +/** + * @brief Free a buffer in the TEE heap + * + * This function frees a buffer that was previously allocated in the TEE heap. + * The semantics are the same as the standard free(). + * + * @param p A pointer to the memory to be freed, or NULL. The pointer must have been + * returned from esp_tee_heap_malloc(), esp_tee_heap_calloc(), or esp_tee_heap_aligned_alloc(). + */ +void esp_tee_heap_free(void *p); + +/** + * @brief Get the size of available TEE heap + * + * @return Available TEE heap size, in bytes + */ +size_t esp_tee_heap_get_free_size(void); + +/** + * @brief Get the minimum TEE heap that has ever been available + * + * @return Minimum free TEE heap ever available, in bytes + */ +size_t esp_tee_heap_get_min_free_size(void); + +/** + * @brief Dump info about the entire structure of the TEE heap + * + * This function outputs detailed information about every block in the TEE heap to stdout. + * (Intended for debugging purposes) + */ +void esp_tee_heap_dump_info(void); #ifdef __cplusplus } diff --git a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/src/test_dummy_srv.c b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/src/test_dummy_srv.c index 7562516a77..049d59290c 100644 --- a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/src/test_dummy_srv.c +++ b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/src/test_dummy_srv.c @@ -1,16 +1,19 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "secure_service_num.h" -#include "esp_tee.h" -#include "esp_err.h" #include "esp_rom_sys.h" #include "esp_attr.h" +#include "multi_heap.h" + void NOINLINE_ATTR _ss_dummy_secure_service(int a, int b, int c, int d, int e, int f, int g, int h, int *i) { esp_rom_printf("Dummy secure service\n"); *i = a + b + c + d + e + f + g + h; + + esp_rom_printf("[TEE] Heap: Free - %uB | Min free - %uB\n", esp_tee_heap_get_free_size(), esp_tee_heap_get_min_free_size()); + esp_tee_heap_dump_info(); } From 223c0d5f9d289bfb1a07e8cb3865234d646f26f2 Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Thu, 20 Mar 2025 22:19:44 +0530 Subject: [PATCH 2/3] feat(esp_tee): Use the ROM TLSF implementation for the TEE build --- components/esp_rom/CMakeLists.txt | 1 + components/esp_rom/include/esp_rom_tlsf.h | 56 ++++++++++++++++++- components/esp_rom/patches/esp_rom_tlsf.c | 8 +-- .../esp_tee/subproject/main/CMakeLists.txt | 5 +- .../subproject/main/common/multi_heap.c | 17 +++--- .../test_apps/tee_test_fw/sdkconfig.ci.ota | 3 +- .../test_apps/tee_test_fw/sdkconfig.defaults | 1 - 7 files changed, 67 insertions(+), 24 deletions(-) diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 75dd12d4d8..ad638e1b1c 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -133,6 +133,7 @@ endif() if(ESP_TEE_BUILD) if(target STREQUAL "esp32c6") rom_linker_script("spiflash") + rom_linker_script("heap") endif() endif() diff --git a/components/esp_rom/include/esp_rom_tlsf.h b/components/esp_rom/include/esp_rom_tlsf.h index 0f5e5c138d..dc9481d0e2 100644 --- a/components/esp_rom/include/esp_rom_tlsf.h +++ b/components/esp_rom/include/esp_rom_tlsf.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,60 @@ extern "C" { #endif +/* tlsf_t: a TLSF structure. Can contain 1 to N pools. */ +/* pool_t: a block of memory that TLSF can manage. */ +typedef void* tlsf_t; +typedef void* pool_t; + +/* Create/destroy a memory pool. */ +tlsf_t tlsf_create(void* mem); +tlsf_t tlsf_create_with_pool(void* mem, size_t bytes); +pool_t tlsf_get_pool(tlsf_t tlsf); + +/* Add/remove memory pools. */ +pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes); +void tlsf_remove_pool(tlsf_t tlsf, pool_t pool); + +/* malloc/memalign/realloc/free replacements. */ +void* tlsf_malloc(tlsf_t tlsf, size_t size); +void* tlsf_memalign(tlsf_t tlsf, size_t align, size_t size); +void* tlsf_memalign_offs(tlsf_t tlsf, size_t align, size_t size, size_t offset); +void* tlsf_realloc(tlsf_t tlsf, void* ptr, size_t size); +void tlsf_free(tlsf_t tlsf, void* ptr); + +/* Returns internal block size, not original request size */ +size_t tlsf_block_size(void* ptr); + +/* Overheads/limits of internal structures. */ +size_t tlsf_size(void); +size_t tlsf_pool_overhead(void); +size_t tlsf_alloc_overhead(void); + +#if ESP_TEE_BUILD +/* NOTE: These declarations are only needed for the TEE build, since these + * functions are (static inline) defined in tlsf_control_functions.h for + * IDF builds. + */ +size_t tlsf_align_size(void); +size_t tlsf_block_size_min(void); +size_t tlsf_block_size_max(void); + +/* NOTE: The consumer of this callback function (tlsf_walk_pool) is patched + * in IDF builds to address issues in the ROM implementation. For TEE build, + * the ROM declarations can be used directly, as heap integrity checking is not + * supported. + */ +typedef void (*tlsf_walker)(void* ptr, size_t size, int used, void* user); +#else +typedef bool (*tlsf_walker)(void* ptr, size_t size, int used, void* user); +#endif + +/* Debugging. */ +void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user); +/* Returns nonzero if any internal consistency check fails. */ +int tlsf_check(tlsf_t tlsf); +int tlsf_check_pool(pool_t pool); + /*! * Defines the function prototypes for multi_heap_internal_poison_fill_region * and multi_heap_internal_check_block_poisoning, these two function will diff --git a/components/esp_rom/patches/esp_rom_tlsf.c b/components/esp_rom/patches/esp_rom_tlsf.c index 1d1acdc5a2..09487be75b 100644 --- a/components/esp_rom/patches/esp_rom_tlsf.c +++ b/components/esp_rom/patches/esp_rom_tlsf.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -24,10 +24,6 @@ #include "tlsf_block_functions.h" #include "tlsf_control_functions.h" -/* Definition of types used in TLSF */ -typedef void* tlsf_t; -typedef void* pool_t; - static poison_check_pfunc_t s_poison_check_region = NULL; void tlsf_poison_check_pfunc_set(poison_check_pfunc_t pfunc) @@ -43,8 +39,6 @@ typedef struct integrity_t int status; } integrity_t; -typedef bool (*tlsf_walker)(void* ptr, size_t size, int used, void* user); - static bool integrity_walker(void* ptr, size_t size, int used, void* user) { block_header_t* block = block_from_ptr(ptr); diff --git a/components/esp_tee/subproject/main/CMakeLists.txt b/components/esp_tee/subproject/main/CMakeLists.txt index a2cb8059df..145b8c4553 100644 --- a/components/esp_tee/subproject/main/CMakeLists.txt +++ b/components/esp_tee/subproject/main/CMakeLists.txt @@ -40,10 +40,7 @@ list(APPEND include "include" list(APPEND srcs "common/multi_heap.c") # TLSF implementation for heap -list(APPEND include "${heap_dir}/tlsf" - "${heap_dir}/tlsf/include") - -list(APPEND srcs "${heap_dir}/tlsf/tlsf.c") +list(APPEND include "${heap_dir}/tlsf") # esp_app_desc_t configuration structure for TEE list(APPEND srcs "common/esp_app_desc_tee.c") diff --git a/components/esp_tee/subproject/main/common/multi_heap.c b/components/esp_tee/subproject/main/common/multi_heap.c index 091f98e381..7e45c6f617 100644 --- a/components/esp_tee/subproject/main/common/multi_heap.c +++ b/components/esp_tee/subproject/main/common/multi_heap.c @@ -1,10 +1,11 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include -#include "tlsf.h" +#include +#include "esp_rom_tlsf.h" #include "tlsf_block_functions.h" #include "multi_heap.h" @@ -37,7 +38,7 @@ static void assert_valid_block(const heap_t *heap, const block_header_t *block) esp_err_t esp_tee_heap_init(void *start_ptr, size_t size) { assert(start_ptr); - if (size < (sizeof(heap_t))) { + if (size < (tlsf_size() + tlsf_block_size_min() + sizeof(heap_t))) { // Region too small to be a heap. return ESP_ERR_INVALID_SIZE; } @@ -45,16 +46,13 @@ esp_err_t esp_tee_heap_init(void *start_ptr, size_t size) heap_t *result = (heap_t *)start_ptr; size -= sizeof(heap_t); - /* Do not specify any maximum size for the allocations so that the default configuration is used */ - const size_t max_bytes = 0; - - result->heap_data = tlsf_create_with_pool(start_ptr + sizeof(heap_t), size, max_bytes); + result->heap_data = tlsf_create_with_pool(start_ptr + sizeof(heap_t), size); if (result->heap_data == NULL) { return ESP_FAIL; } result->lock = NULL; - result->free_bytes = size - tlsf_size(result->heap_data); + result->free_bytes = size - tlsf_size(); result->pool_size = size; result->minimum_free_bytes = result->free_bytes; @@ -152,14 +150,13 @@ size_t esp_tee_heap_get_min_free_size(void) return tee_heap->minimum_free_bytes; } -static bool tee_heap_dump_tlsf(void* ptr, size_t size, int used, void* user) +static void heap_dump_tlsf(void* ptr, size_t size, int used, void* user) { (void)user; printf("Block %p data, size: %d bytes, Free: %s\n", (void *)ptr, size, used ? "No" : "Yes"); - return true; } void esp_tee_heap_dump_info(void) diff --git a/components/esp_tee/test_apps/tee_test_fw/sdkconfig.ci.ota b/components/esp_tee/test_apps/tee_test_fw/sdkconfig.ci.ota index ac1f00d7d0..5224e6bc4b 100644 --- a/components/esp_tee/test_apps/tee_test_fw/sdkconfig.ci.ota +++ b/components/esp_tee/test_apps/tee_test_fw/sdkconfig.ci.ota @@ -4,8 +4,9 @@ CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_tee_ota.csv" CONFIG_PARTITION_TABLE_FILENAME="partitions_tee_ota.csv" -# Increasing Bootloader log verbosity +# Increasing Bootloader and TEE log verbosity CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG=y +CONFIG_SECURE_TEE_LOG_LEVEL_DEBUG=y CONFIG_SECURE_TEE_SEC_STG_SUPPORT_SECP192R1_SIGN=y diff --git a/components/esp_tee/test_apps/tee_test_fw/sdkconfig.defaults b/components/esp_tee/test_apps/tee_test_fw/sdkconfig.defaults index 9f36b65b80..c0467c64cb 100644 --- a/components/esp_tee/test_apps/tee_test_fw/sdkconfig.defaults +++ b/components/esp_tee/test_apps/tee_test_fw/sdkconfig.defaults @@ -5,7 +5,6 @@ CONFIG_ESP_TASK_WDT_INIT=n # Enabling TEE CONFIG_SECURE_ENABLE_TEE=y CONFIG_SECURE_TEE_DEBUG_MODE=y -CONFIG_SECURE_TEE_LOG_LEVEL_DEBUG=y CONFIG_SECURE_TEE_TEST_MODE=y # Custom partition table From d26e18cb491c333716bf2964b3e7d4f31d7464be Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Wed, 2 Apr 2025 16:35:45 +0530 Subject: [PATCH 3/3] ci(esp_tee): Verify the malloc-write-free cycle in the TEE heap --- .../components/test_sec_srv/CMakeLists.txt | 3 +- .../test_sec_srv/include/esp_tee_test.h | 2 + .../test_sec_srv/sec_srv_tbl_test.yml | 4 + .../components/test_sec_srv/src/test_heap.c | 99 +++++++++++++++++++ .../main/test_esp_tee_ctx_switch.c | 5 + .../tee_test_fw/pytest_esp_tee_ut.py | 3 +- 6 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/src/test_heap.c diff --git a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/CMakeLists.txt b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/CMakeLists.txt index a93e6bc7ef..0dae5f2596 100644 --- a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/CMakeLists.txt +++ b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/CMakeLists.txt @@ -9,7 +9,8 @@ if(esp_tee_build) list(APPEND srcs "src/test_dummy_srv.c" "src/test_interrupt.c" "src/test_panic.c" - "src/test_sec_srv.c") + "src/test_sec_srv.c" + "src/test_heap.c") list(APPEND priv_requires main) else() list(APPEND srcs "src/test_dummy_srv_wrapper.c") diff --git a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/include/esp_tee_test.h b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/include/esp_tee_test.h index 705383e5fc..4874ccc5c7 100644 --- a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/include/esp_tee_test.h +++ b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/include/esp_tee_test.h @@ -38,6 +38,8 @@ void NOINLINE_ATTR dummy_secure_service(int a, int b, int c, int d, int e, int f uint32_t add_in_loop(uint32_t a, uint32_t b, uint32_t iter); +int _ss_esp_tee_test_heap_malloc_write_free(void); + #ifdef __cplusplus } #endif diff --git a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/sec_srv_tbl_test.yml b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/sec_srv_tbl_test.yml index 5945326e7a..d62238944a 100644 --- a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/sec_srv_tbl_test.yml +++ b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/sec_srv_tbl_test.yml @@ -69,3 +69,7 @@ secure_services: type: custom function: add_in_loop args: 3 + - id: 217 + type: custom + function: esp_tee_test_heap_malloc_write_free + args: 0 diff --git a/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/src/test_heap.c b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/src/test_heap.c new file mode 100644 index 0000000000..457cb31e23 --- /dev/null +++ b/components/esp_tee/test_apps/tee_test_fw/components/test_sec_srv/src/test_heap.c @@ -0,0 +1,99 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "esp_rom_sys.h" +#include "multi_heap.h" +#include "esp_rom_tlsf.h" + +typedef struct { + int *ptr; + size_t size; +} alloc_block_t; + +static size_t try_malloc_write_free(void) +{ + size_t blk_sz = 512; + size_t max_blks = esp_tee_heap_get_free_size() / blk_sz; + size_t total_mem = 0; + + alloc_block_t *blocks = malloc(sizeof(alloc_block_t) * (max_blks + 1)); + if (!blocks) { + return -1; + } + + int n_blks = 0; + + // Attempt to allocate memory blocks and write to them + for (int i = 0; i < max_blks; i++) { + blocks[i].ptr = malloc(blk_sz); + if (!blocks[i].ptr) { + break; + } + blocks[i].size = blk_sz; + total_mem += blk_sz; + memset(blocks[i].ptr, 0xEF, blk_sz); + n_blks++; + } + + // Check if there is leftover memory that can be allocated + size_t left = esp_tee_heap_get_free_size(); + if (left > 24 && n_blks == max_blks) { + size_t rm_sz = left - 24; // Calculate remaining size to allocate + blocks[n_blks].ptr = malloc(rm_sz); + if (blocks[n_blks].ptr) { + blocks[n_blks].size = rm_sz; + total_mem += rm_sz; + memset(blocks[n_blks].ptr, 0xEF, rm_sz); + n_blks++; + } else { + esp_rom_printf("Failed to allocate leftover bytes\n"); + free(blocks); + return -1; + } + } + + int *ptr = malloc(blk_sz); + if (ptr) { + esp_rom_printf("Illegal allocation\n"); + free(blocks); + return -1; + } + + // Verify the integrity of allocated memory blocks + for (int i = 0; i < n_blks; i++) { + unsigned char *block_ptr = (unsigned char *)blocks[i].ptr; + for (size_t j = 0; j < blocks[i].size; j++) { + if (block_ptr[j] != 0xEF) { + esp_rom_printf("Corrupt heap\n"); + free(blocks); + return -1; + } + } + free(blocks[i].ptr); + } + + free(blocks); + return total_mem; +} + +int _ss_esp_tee_test_heap_malloc_write_free(void) +{ + size_t prev_sz = 0; + for (int i = 0; i < 3; i++) { + size_t cur_sz = try_malloc_write_free(); + if (cur_sz == -1) { + return -1; + } + + if (i > 0 && cur_sz != prev_sz) { + esp_rom_printf("Processed memory sizes differ between iterations!\n"); + return -1; + } + + prev_sz = cur_sz; + } + + return 0; +} diff --git a/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_ctx_switch.c b/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_ctx_switch.c index 474e2c3430..6534cf712f 100644 --- a/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_ctx_switch.c +++ b/components/esp_tee/test_apps/tee_test_fw/main/test_esp_tee_ctx_switch.c @@ -95,3 +95,8 @@ TEST_CASE("Task switching during secure service calls", "[basic]") world = esp_cpu_get_curr_privilege_level(); TEST_ASSERT_MESSAGE((world == ESP_CPU_NS_MODE), "Current world is not NS"); } + +TEST_CASE("Test TEE Heap: Malloc-write-free cycles", "[heap]") +{ + TEST_ASSERT_EQUAL(0, esp_tee_service_call(1, SS_ESP_TEE_TEST_HEAP_MALLOC_WRITE_FREE)); +} diff --git a/components/esp_tee/test_apps/tee_test_fw/pytest_esp_tee_ut.py b/components/esp_tee/test_apps/tee_test_fw/pytest_esp_tee_ut.py index ec47009f7f..e4f574c69f 100644 --- a/components/esp_tee/test_apps/tee_test_fw/pytest_esp_tee_ut.py +++ b/components/esp_tee/test_apps/tee_test_fw/pytest_esp_tee_ut.py @@ -51,6 +51,7 @@ TEST_PARTITION_LABEL = 'test' @idf_parametrize('target', ['esp32c6'], indirect=['target']) def test_esp_tee(dut: IdfDut) -> None: dut.run_all_single_board_cases(group='basic') + dut.run_all_single_board_cases(group='heap') @pytest.mark.generic @@ -104,7 +105,7 @@ def test_esp_tee_apm_violation(dut: IdfDut) -> None: @idf_parametrize('target', ['esp32c6'], indirect=['target']) def test_esp_tee_illegal_instruction(dut: IdfDut) -> None: dut.expect_exact('Press ENTER to see the list of tests') - dut.write(f'"Test TEE-TEE violation: Illegal Instruction"') + dut.write('"Test TEE-TEE violation: Illegal Instruction"') exc = dut.expect(r'Core ([01]) panic\'ed \(([^)]+)\)', timeout=30).group(2).decode() if exc != 'Illegal instruction': raise RuntimeError('Incorrect exception received!')