enclave_ecalls.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
  2. /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
  3. #include "pal_linux.h"
  4. #include "pal_security.h"
  5. #include "pal_internal.h"
  6. #include <api.h>
  7. #include "ecall_types.h"
  8. #define SGX_CAST(type, item) ((type)(item))
  9. void pal_linux_main(char * uptr_args, uint64_t args_size,
  10. char * uptr_env, uint64_t env_size,
  11. struct pal_sec * uptr_sec_info);
  12. void pal_start_thread (void);
  13. extern void * enclave_base, * enclave_top;
  14. static struct atomic_int enclave_start_called = ATOMIC_INIT(0);
  15. /*
  16. * Called from enclave_entry.S to execute ecalls.
  17. *
  18. * During normal operation handle_ecall will not return. The exception is that
  19. * it will return if invalid parameters are passed. In this case
  20. * enclave_entry.S will go into an endless loop since a clean return to urts is
  21. * not easy in all cases.
  22. *
  23. * Parameters:
  24. *
  25. * ecall_index:
  26. * Number of requested ecall. Untrusted.
  27. *
  28. * ecall_args:
  29. * Pointer to arguments for requested ecall. Untrusted.
  30. *
  31. * exit_target:
  32. * Address to return to after EEXIT. Untrusted.
  33. *
  34. * untrusted_stack:
  35. * Address to urts stack. Restored before EEXIT and used for ocall
  36. * arguments. Untrusted.
  37. *
  38. * enclave_base_addr:
  39. * Base address of enclave. Calculated dynamically in enclave_entry.S.
  40. * Trusted.
  41. */
  42. void handle_ecall (long ecall_index, void * ecall_args, void * exit_target,
  43. void * untrusted_stack, void * enclave_base_addr)
  44. {
  45. if (ecall_index < 0 || ecall_index >= ECALL_NR)
  46. return;
  47. if (!enclave_top) {
  48. enclave_base = enclave_base_addr;
  49. enclave_top = enclave_base_addr + GET_ENCLAVE_TLS(enclave_size);
  50. }
  51. SET_ENCLAVE_TLS(exit_target, exit_target);
  52. SET_ENCLAVE_TLS(ustack_top, untrusted_stack);
  53. SET_ENCLAVE_TLS(ustack, untrusted_stack);
  54. if (atomic_cmpxchg(&enclave_start_called, 0, 1) == 0) {
  55. // ENCLAVE_START not yet called, so only valid ecall is ENCLAVE_START.
  56. if (ecall_index != ECALL_ENCLAVE_START) {
  57. // To keep things simple, we treat an invalid ecall_index like an
  58. // unsuccessful call to ENCLAVE_START.
  59. return;
  60. }
  61. ms_ecall_enclave_start_t * ms =
  62. (ms_ecall_enclave_start_t *) ecall_args;
  63. if (!ms || !sgx_is_completely_outside_enclave(ms, sizeof(*ms))) {
  64. return;
  65. }
  66. /* pal_linux_main is responsible to check the passed arguments */
  67. pal_linux_main(ms->ms_args, ms->ms_args_size,
  68. ms->ms_env, ms->ms_env_size,
  69. ms->ms_sec_info);
  70. } else {
  71. // ENCLAVE_START already called (maybe successfully, maybe not), so
  72. // only valid ecall is THREAD_START.
  73. if (ecall_index != ECALL_THREAD_START) {
  74. return;
  75. }
  76. // Only allow THREAD_START after successful enclave initialization.
  77. if (!(pal_enclave_state.enclave_flags & PAL_ENCLAVE_INITIALIZED)) {
  78. return;
  79. }
  80. pal_start_thread();
  81. }
  82. // pal_linux_main and pal_start_thread should never return.
  83. }