fix(esp_tee): Reject re-entrant secure service calls from the REE

This commit is contained in:
Laukik Hase
2026-09-04 10:20:19 +05:30
parent 9c8d416346
commit f26c18bd5b
4 changed files with 121 additions and 4 deletions
@@ -22,6 +22,7 @@
.equ SAVE_REGS, 32
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
.equ MAGIC, 0x1f
.equ NS_INT_RTN_MAGIC, (MAGIC << 12)
/* Macro which first allocates space on the stack to save general
* purpose registers, and then save them. GP register is excluded.
@@ -222,6 +223,24 @@
#endif
.endm
/**
* SVC_LOCK_ACQUIRE / SVC_LOCK_RELEASE
* Hold _s_svc_lock for the duration of a secure service call, so that a call issued
* while another one is active branches to \fail instead of clobbering it.
*
* Clobbers: \tx
*/
.macro SVC_LOCK_ACQUIRE tx, fail
la \tx, _s_svc_lock
amoswap.w.aq \tx, \tx, (\tx)
bnez \tx, \fail
.endm
.macro SVC_LOCK_RELEASE tx
la \tx, _s_svc_lock
amoswap.w.rl zero, zero, (\tx)
.endm
/**
* VALIDATE_REE_SP
* Validate an REE-supplied sp before the TEE stores through it. The TEE region is
@@ -61,6 +61,10 @@ _ns_sp_max:
_ns_int_rtn:
.word 0
.global _s_svc_lock
_s_svc_lock:
.word 0
.section .exception_vectors.text, "ax"
/* Exception handler. */
@@ -178,6 +182,9 @@ _1:
lui t0, ESP_TEE_M2U_SWITCH_MAGIC
beq a1, t0, _skip_ctx_restore
/* The secure service has returned - the REE may issue the next one */
SVC_LOCK_RELEASE t0
/* Check if we need to restore the MINTTHRESH register */
la t0, _s_intr_thresh
lw t1, 0(t0)
@@ -218,10 +225,13 @@ _skip_ctx_restore:
/* U-mode ecall handler */
_user_ecall:
/* Check whether we are returning after servicing an U-mode interrupt */
li t0, NS_INT_RTN_MAGIC
bne a0, t0, _svc_call_enter
la t0, _ns_int_rtn
lw t0, 0(t0)
bnez t0, _rtn_from_ns_int
_svc_call_enter:
/* Reject an sp whose frame would be out-of-bounds */
VALIDATE_REE_SP CONTEXT_SIZE, t0, 0
@@ -233,6 +243,9 @@ _user_ecall:
save_general_regs
save_mepc
/* Claim the TEE before touching any of its state */
SVC_LOCK_ACQUIRE t0, _svc_call_reject
# Check if REE is in a critical section
csrr t0, CSR_UINTTHRESH # t0 = current UINTTHRESH
beqz t0, _process_ecall # if threshold == 0 -> continue
@@ -314,6 +327,16 @@ _3:
mret
/* Discard a service call that arrived while another one was active */
_svc_call_reject:
addi sp, sp, CONTEXT_SIZE /* t0 is the only register clobbered past the context save */
csrr t0, mepc
addi t0, t0, 4 /* resume the REE after its ecall */
csrw mepc, t0
csrr t0, mscratch
li a0, -1
mret
.size _ecall_handler, .-_ecall_handler
/* This is the interrupt handler for the U-mode interrupts.
@@ -65,6 +65,10 @@ _ns_sp_max:
_ns_int_rtn:
.word 0
.global _s_svc_lock
_s_svc_lock:
.word 0
.section .exception_vectors.text, "ax"
/* Exception handler. */
@@ -167,6 +171,9 @@ _machine_ecall:
lui t0, ESP_TEE_M2U_SWITCH_MAGIC
beq a1, t0, _skip_ctx_restore
/* The secure service has returned - the REE may issue the next one */
SVC_LOCK_RELEASE t0
/* Check if we need to restore the MXINT threshold register */
la t0, _s_intr_thresh
lw t1, 0(t0)
@@ -208,10 +215,13 @@ _skip_ctx_restore:
/* U-mode ecall handler */
_user_ecall:
/* Check whether we are returning after servicing an U-mode interrupt */
li t0, NS_INT_RTN_MAGIC
bne a0, t0, _svc_call_enter
la t0, _ns_int_rtn
lw t0, 0(t0)
bnez t0, _rtn_from_ns_int
_svc_call_enter:
/* Reject an sp whose frame would be out-of-bounds */
VALIDATE_REE_SP CONTEXT_SIZE, t0, 0
@@ -223,6 +233,9 @@ _user_ecall:
save_general_regs
save_mepc
/* Claim the TEE before touching any of its state */
SVC_LOCK_ACQUIRE t0, _svc_call_reject
# Check if REE is in a critical section
li t0, PLIC_UXINT_THRESH_REG
lw t1, 0(t0) # t1 = current UXINT threshold
@@ -293,6 +306,16 @@ _rtn_from_ns_int:
mret
/* Discard a service call that arrived while another one was active */
_svc_call_reject:
addi sp, sp, CONTEXT_SIZE /* t0 is the only register clobbered past the context save */
csrr t0, mepc
addi t0, t0, 4 /* resume the REE after its ecall */
csrw mepc, t0
csrr t0, mscratch
li a0, -1
mret
.size _ecall_handler, .-_ecall_handler
/* This is the interrupt handler for the U-mode interrupts.