mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
refactor(esp_tee): Adopt Picolibc as the default LibC for ESP-TEE build
- Also fixed an issue where NewLib ROM APIs, when called from TEE, were using the syscall table located in the REE SRAM. This could be abused as an attack vector to invoke illegal functions from the TEE. To prevent this, the syscall table is now switched to the TEE-specific copy during every M-U mode transition.
This commit is contained in:
@@ -34,6 +34,8 @@
|
||||
.global esp_tee_global_interrupt_handler
|
||||
.global esp_tee_service_dispatcher
|
||||
.global _tee_s_entry
|
||||
.global syscall_enter_tee
|
||||
.global syscall_exit_tee
|
||||
|
||||
.section .data
|
||||
.balign 4
|
||||
@@ -392,6 +394,8 @@ _skip_thresh_restore:
|
||||
STACK_GUARD_POST_SWITCH t3 1 _ns_sp_min _ns_sp_max
|
||||
fence
|
||||
|
||||
call syscall_exit_tee
|
||||
|
||||
/* Backup the A0 register
|
||||
* This point is reached after an ecall is triggered after executing the secure service.
|
||||
* The A0 register contains the return value of the corresponding service.
|
||||
@@ -464,6 +468,8 @@ _2:
|
||||
li t0, MSTATUS_MPP
|
||||
csrs mstatus, t0
|
||||
|
||||
call syscall_enter_tee
|
||||
|
||||
mret
|
||||
|
||||
/* This point is reached after servicing a U-mode interrupt occurred
|
||||
@@ -491,6 +497,8 @@ _3:
|
||||
li t0, MSTATUS_MPP
|
||||
csrs mstatus, t0
|
||||
|
||||
call syscall_enter_tee
|
||||
|
||||
/* Restore register context and resume the secure service */
|
||||
restore_mepc
|
||||
restore_general_regs
|
||||
@@ -615,6 +623,8 @@ _4:
|
||||
|
||||
STACK_GUARD_POST_SWITCH t3 1 _ns_sp_min _ns_sp_max
|
||||
|
||||
call syscall_exit_tee
|
||||
|
||||
/* Place magic bytes in all the general registers */
|
||||
store_magic_general_regs
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
.global esp_tee_global_interrupt_handler
|
||||
.global esp_tee_service_dispatcher
|
||||
.global _tee_s_entry
|
||||
.global syscall_enter_tee
|
||||
.global syscall_exit_tee
|
||||
|
||||
.section .data
|
||||
.balign 4
|
||||
@@ -384,6 +386,8 @@ _skip_thresh_restore:
|
||||
STACK_GUARD_POST_SWITCH t3 1 _ns_sp_min _ns_sp_max
|
||||
fence
|
||||
|
||||
call syscall_exit_tee
|
||||
|
||||
/* Backup the A0 register
|
||||
* This point is reached after an ecall is triggered after executing the secure service.
|
||||
* The A0 register contains the return value of the corresponding service.
|
||||
@@ -452,6 +456,8 @@ _process_ecall:
|
||||
li t0, MSTATUS_MPP
|
||||
csrs mstatus, t0
|
||||
|
||||
call syscall_enter_tee
|
||||
|
||||
mret
|
||||
|
||||
/* This point is reached after servicing a U-mode interrupt occurred
|
||||
@@ -472,6 +478,8 @@ _rtn_from_ns_int:
|
||||
li t0, MSTATUS_MPP
|
||||
csrs mstatus, t0
|
||||
|
||||
call syscall_enter_tee
|
||||
|
||||
/* Restore register context and resume the secure service */
|
||||
restore_mepc
|
||||
restore_general_regs
|
||||
@@ -545,6 +553,8 @@ _tee_ns_intr_handler:
|
||||
|
||||
STACK_GUARD_POST_SWITCH t3 1 _ns_sp_min _ns_sp_max
|
||||
|
||||
call syscall_exit_tee
|
||||
|
||||
/* Place magic bytes in all the general registers */
|
||||
store_magic_general_regs
|
||||
|
||||
|
||||
@@ -152,7 +152,6 @@ void *calloc(size_t n, size_t size)
|
||||
return esp_tee_heap_calloc(n, size);
|
||||
}
|
||||
|
||||
#if CONFIG_LIBC_PICOLIBC
|
||||
void *realloc(void* ptr, size_t size)
|
||||
{
|
||||
if (tee_heap == NULL) {
|
||||
@@ -160,7 +159,7 @@ void *realloc(void* ptr, size_t size)
|
||||
}
|
||||
|
||||
if (ptr == NULL) {
|
||||
return esp_tee_heap_malloc(heap, size);
|
||||
return esp_tee_heap_malloc(size);
|
||||
}
|
||||
|
||||
size_t previous_block_size = tlsf_block_size(ptr);
|
||||
@@ -177,7 +176,6 @@ void *realloc(void* ptr, size_t size)
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
void free(void *ptr)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,13 @@
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#include "rom/libc_stubs.h"
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_random.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_LIBC_NEWLIB
|
||||
@@ -76,7 +82,44 @@ int _getentropy_r(struct _reent *r, void *buffer, size_t length)
|
||||
esp_fill_random(buffer, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct syscall_stub_table *syscall_table_ptr;
|
||||
static struct syscall_stub_table *syscall_table_ptr_ree;
|
||||
|
||||
static struct syscall_stub_table s_stub_table_tee = {
|
||||
.__getreent = &__getreent,
|
||||
};
|
||||
|
||||
void IRAM_ATTR syscall_enter_tee(void)
|
||||
{
|
||||
if (syscall_table_ptr) {
|
||||
syscall_table_ptr_ree = syscall_table_ptr;
|
||||
syscall_table_ptr = &s_stub_table_tee;
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR syscall_exit_tee(void)
|
||||
{
|
||||
if (syscall_table_ptr_ree) {
|
||||
syscall_table_ptr = syscall_table_ptr_ree;
|
||||
syscall_table_ptr_ree = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Picolibc does not initialize 'errno' and places it in the TBSS section.
|
||||
*
|
||||
* To allow convenient initialization and support interoperability with Newlib,
|
||||
* 'errno' is defined in the TDATA section. The linker script ensures that
|
||||
* it is positioned at the beginning of the TDATA segment.
|
||||
*/
|
||||
__thread int errno __attribute__((section(".tdata.errno"))) = 0;
|
||||
|
||||
int *__errno(void)
|
||||
{
|
||||
return &errno;
|
||||
}
|
||||
|
||||
int fstat(int fd, struct stat *st)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
@@ -123,6 +166,40 @@ int getentropy(void *buffer, size_t length)
|
||||
esp_fill_random(buffer, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open(const char *path, int flags, ...)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rename(const char *src, const char *dst)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unlink(const char *path)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern uint32_t _tee_tdata_start;
|
||||
static void *s_tp_ree[SOC_CPU_CORES_NUM];
|
||||
|
||||
void IRAM_ATTR syscall_enter_tee(void)
|
||||
{
|
||||
int core_id = esp_cpu_get_core_id();
|
||||
s_tp_ree[core_id] = esp_cpu_get_threadptr();
|
||||
esp_cpu_set_threadptr(&_tee_tdata_start);
|
||||
}
|
||||
|
||||
void IRAM_ATTR syscall_exit_tee(void)
|
||||
{
|
||||
int core_id = esp_cpu_get_core_id();
|
||||
esp_cpu_set_threadptr(s_tp_ree[core_id]);
|
||||
}
|
||||
#endif // CONFIG_LIBC_NEWLIB
|
||||
|
||||
void *pthread_getspecific(pthread_key_t key)
|
||||
|
||||
@@ -132,6 +132,28 @@ SECTIONS
|
||||
ALIGNED_SYMBOL(8, _tee_bss_end)
|
||||
} > sram_tee_seg
|
||||
|
||||
.dram.tee.tdata :
|
||||
{
|
||||
/* tdata sections */
|
||||
_tee_tdata_start = ABSOLUTE(.);
|
||||
#if CONFIG_LIBC_PICOLIBC
|
||||
KEEP(*(.tdata.errno))
|
||||
#endif // CONFIG_LIBC_PICOLIBC
|
||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||
_tee_tdata_end = ABSOLUTE(.);
|
||||
|
||||
/* tbss sections */
|
||||
_tee_tbss_start = ABSOLUTE(.);
|
||||
*(.tbss .tbss.* .gnu.linkonce.tb.*)
|
||||
*(.tcommon .tcommon.*)
|
||||
_tee_tbss_end = ABSOLUTE(.);
|
||||
|
||||
. = ALIGN(ALIGNOF(.dram.tee.rodata));
|
||||
} > sram_tee_seg
|
||||
ASSERT_SECTIONS_GAP(.dram.tee.tdata, .dram.tee.rodata)
|
||||
ASSERT(_tee_tdata_end == _tee_tbss_start,
|
||||
"tdata and tbss must be contiguous.")
|
||||
|
||||
.dram.tee.rodata :
|
||||
{
|
||||
_tee_rodata_start = ABSOLUTE(.);
|
||||
|
||||
@@ -137,6 +137,28 @@ SECTIONS
|
||||
ALIGNED_SYMBOL(8, _tee_bss_end)
|
||||
} > sram_tee_seg
|
||||
|
||||
.dram.tee.tdata :
|
||||
{
|
||||
/* tdata sections */
|
||||
_tee_tdata_start = ABSOLUTE(.);
|
||||
#if CONFIG_LIBC_PICOLIBC
|
||||
KEEP(*(.tdata.errno))
|
||||
#endif // CONFIG_LIBC_PICOLIBC
|
||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||
_tee_tdata_end = ABSOLUTE(.);
|
||||
|
||||
/* tbss sections */
|
||||
_tee_tbss_start = ABSOLUTE(.);
|
||||
*(.tbss .tbss.* .gnu.linkonce.tb.*)
|
||||
*(.tcommon .tcommon.*)
|
||||
_tee_tbss_end = ABSOLUTE(.);
|
||||
|
||||
. = ALIGN(ALIGNOF(.dram.tee.rodata));
|
||||
} > sram_tee_seg
|
||||
ASSERT_SECTIONS_GAP(.dram.tee.tdata, .dram.tee.rodata)
|
||||
ASSERT(_tee_tdata_end == _tee_tbss_start,
|
||||
"tdata and tbss must be contiguous.")
|
||||
|
||||
.dram.tee.rodata :
|
||||
{
|
||||
_tee_rodata_start = ABSOLUTE(.);
|
||||
|
||||
@@ -132,6 +132,28 @@ SECTIONS
|
||||
ALIGNED_SYMBOL(8, _tee_bss_end)
|
||||
} > sram_tee_seg
|
||||
|
||||
.dram.tee.tdata :
|
||||
{
|
||||
/* tdata sections */
|
||||
_tee_tdata_start = ABSOLUTE(.);
|
||||
#if CONFIG_LIBC_PICOLIBC
|
||||
KEEP(*(.tdata.errno))
|
||||
#endif // CONFIG_LIBC_PICOLIBC
|
||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||
_tee_tdata_end = ABSOLUTE(.);
|
||||
|
||||
/* tbss sections */
|
||||
_tee_tbss_start = ABSOLUTE(.);
|
||||
*(.tbss .tbss.* .gnu.linkonce.tb.*)
|
||||
*(.tcommon .tcommon.*)
|
||||
_tee_tbss_end = ABSOLUTE(.);
|
||||
|
||||
. = ALIGN(ALIGNOF(.dram.tee.rodata));
|
||||
} > sram_tee_seg
|
||||
ASSERT_SECTIONS_GAP(.dram.tee.tdata, .dram.tee.rodata)
|
||||
ASSERT(_tee_tdata_end == _tee_tbss_start,
|
||||
"tdata and tbss must be contiguous.")
|
||||
|
||||
.dram.tee.rodata :
|
||||
{
|
||||
_tee_rodata_start = ABSOLUTE(.);
|
||||
|
||||
@@ -137,6 +137,28 @@ SECTIONS
|
||||
ALIGNED_SYMBOL(8, _tee_bss_end)
|
||||
} > sram_tee_seg
|
||||
|
||||
.dram.tee.tdata :
|
||||
{
|
||||
/* tdata sections */
|
||||
_tee_tdata_start = ABSOLUTE(.);
|
||||
#if CONFIG_LIBC_PICOLIBC
|
||||
KEEP(*(.tdata.errno))
|
||||
#endif // CONFIG_LIBC_PICOLIBC
|
||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||
_tee_tdata_end = ABSOLUTE(.);
|
||||
|
||||
/* tbss sections */
|
||||
_tee_tbss_start = ABSOLUTE(.);
|
||||
*(.tbss .tbss.* .gnu.linkonce.tb.*)
|
||||
*(.tcommon .tcommon.*)
|
||||
_tee_tbss_end = ABSOLUTE(.);
|
||||
|
||||
. = ALIGN(ALIGNOF(.dram.tee.rodata));
|
||||
} > sram_tee_seg
|
||||
ASSERT_SECTIONS_GAP(.dram.tee.tdata, .dram.tee.rodata)
|
||||
ASSERT(_tee_tdata_end == _tee_tbss_start,
|
||||
"tdata and tbss must be contiguous.")
|
||||
|
||||
.dram.tee.rodata :
|
||||
{
|
||||
_tee_rodata_start = ABSOLUTE(.);
|
||||
|
||||
Reference in New Issue
Block a user