|
|
@@ -17,6 +17,8 @@ void pal_start_thread (void);
|
|
|
|
|
|
extern void * enclave_base, * enclave_top;
|
|
|
|
|
|
+static struct atomic_int enclave_start_called = ATOMIC_INIT(0);
|
|
|
+
|
|
|
void handle_ecall (long ecall_index, void * ecall_args, void * exit_target,
|
|
|
void * untrusted_stack, void * enclave_base_addr)
|
|
|
{
|
|
|
@@ -38,22 +40,34 @@ void handle_ecall (long ecall_index, void * ecall_args, void * exit_target,
|
|
|
SET_ENCLAVE_TLS(ustack_top, untrusted_stack);
|
|
|
SET_ENCLAVE_TLS(ustack, untrusted_stack);
|
|
|
|
|
|
- switch(ecall_index) {
|
|
|
- case ECALL_ENCLAVE_START: {
|
|
|
- ms_ecall_enclave_start_t * ms =
|
|
|
- (ms_ecall_enclave_start_t *) ecall_args;
|
|
|
+ if (atomic_cmpxchg(&enclave_start_called, 0, 1) == 0) {
|
|
|
+ // ENCLAVE_START not yet called, so only valid ecall is ENCLAVE_START.
|
|
|
+ if (ecall_index != ECALL_ENCLAVE_START) {
|
|
|
+ // To keep things simple, we treat an invalid ecall_index like an
|
|
|
+ // unsuccessful call to ENCLAVE_START.
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ms_ecall_enclave_start_t * ms =
|
|
|
+ (ms_ecall_enclave_start_t *) ecall_args;
|
|
|
|
|
|
- if (!ms) return;
|
|
|
+ if (!ms) return;
|
|
|
|
|
|
- pal_linux_main(ms->ms_arguments, ms->ms_environments,
|
|
|
- ms->ms_sec_info);
|
|
|
- break;
|
|
|
+ pal_linux_main(ms->ms_arguments, ms->ms_environments,
|
|
|
+ ms->ms_sec_info);
|
|
|
+ } else {
|
|
|
+ // ENCLAVE_START already called (maybe successfully, maybe not), so
|
|
|
+ // only valid ecall is THREAD_START.
|
|
|
+ if (ecall_index != ECALL_THREAD_START) {
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- case ECALL_THREAD_START:
|
|
|
- pal_start_thread();
|
|
|
- break;
|
|
|
- }
|
|
|
+ // Only allow THREAD_START after successful enclave initialization.
|
|
|
+ if (!(pal_enclave_state.enclave_flags & PAL_ENCLAVE_INITIALIZED)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- ocall_exit(0);
|
|
|
+ pal_start_thread();
|
|
|
+ }
|
|
|
+ // pal_linux_main and pal_start_thread should never return.
|
|
|
}
|