Browse Source

[Pal/Linux-SGX] Enforce ordering of ENCLAVE_START and THREAD_START

This change enforces that:

 1. ENCLAVE_START is called only once per process.

 2. THREAD_START is only called after ENCLAVE_START.

 3. THREAD_START is only called after pal_linux_main marked the enclave
    as initialized.
Simon Gaiser 6 years ago
parent
commit
13515295b2
1 changed files with 27 additions and 13 deletions
  1. 27 13
      Pal/src/host/Linux-SGX/enclave_ecalls.c

+ 27 - 13
Pal/src/host/Linux-SGX/enclave_ecalls.c

@@ -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.
 }