trts.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Intel Corporation nor the names of its
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. #include "sgx_trts.h"
  32. #include "sgx_edger8r.h"
  33. #include "trts_inst.h"
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include "util.h"
  37. #include "thread_data.h"
  38. #include "global_data.h"
  39. #include "trts_internal.h"
  40. #include "internal/rts.h"
  41. #ifdef SE_SIM
  42. #include "t_instructions.h" /* for `g_global_data_sim' */
  43. #include "sgx_spinlock.h"
  44. #endif
  45. #ifndef SE_SIM
  46. #include "se_cdefs.h"
  47. // add a version to trts
  48. SGX_ACCESS_VERSION(trts, 1);
  49. #endif
  50. // sgx_is_within_enclave()
  51. // Parameters:
  52. // addr - the start address of the buffer
  53. // size - the size of the buffer
  54. // Return Value:
  55. // 1 - the buffer is strictly within the enclave
  56. // 0 - the whole buffer or part of the buffer is not within the enclave,
  57. // or the buffer is wrap around
  58. //
  59. int sgx_is_within_enclave(__attribute__((unused))const void *addr, __attribute__((unused))size_t size)
  60. {
  61. /* size_t start = reinterpret_cast<size_t>(addr);
  62. size_t end = 0;
  63. size_t enclave_start = (size_t)&__ImageBase;
  64. size_t enclave_end = enclave_start + g_global_data.enclave_size - 1;
  65. // g_global_data.enclave_end = enclave_base + enclave_size - 1;
  66. // so the enclave range is [enclave_start, enclave_end] inclusively
  67. if(size > 0)
  68. {
  69. end = start + size - 1;
  70. }
  71. else
  72. {
  73. end = start;
  74. }
  75. if( (start <= end) && (start >= enclave_start) && (end <= enclave_end) )
  76. {
  77. return 1;
  78. }
  79. return 0;
  80. */ return 1;
  81. }
  82. // sgx_is_outside_enclave()
  83. // Parameters:
  84. // addr - the start address of the buffer
  85. // size - the size of the buffer
  86. // Return Value:
  87. // 1 - the buffer is strictly outside the enclave
  88. // 0 - the whole buffer or part of the buffer is not outside the enclave,
  89. // or the buffer is wrap around
  90. //
  91. int sgx_is_outside_enclave(__attribute__((unused)) const void *addr, __attribute__((unused)) size_t size)
  92. {
  93. /* size_t start = reinterpret_cast<size_t>(addr);
  94. size_t end = 0;
  95. size_t enclave_start = (size_t)&__ImageBase;
  96. size_t enclave_end = enclave_start + g_global_data.enclave_size - 1;
  97. // g_global_data.enclave_end = enclave_base + enclave_size - 1;
  98. // so the enclave range is [enclave_start, enclave_end] inclusively
  99. if(size > 0)
  100. {
  101. end = start + size - 1;
  102. }
  103. else
  104. {
  105. end = start;
  106. }
  107. if( (start <= end) && ((end < enclave_start) || (start > enclave_end)) )
  108. {
  109. return 1;
  110. }
  111. return 0;
  112. */ return 1;
  113. }
  114. // sgx_ocalloc()
  115. // Parameters:
  116. // size - bytes to allocate on the outside stack
  117. // Return Value:
  118. // the pointer to the allocated space on the outside stack
  119. // NULL - fail to allocate
  120. //
  121. // sgx_ocalloc allocates memory on the outside stack. It is only used for OCALL, and will be auto freed when ECALL returns.
  122. // To achieve this, the outside stack pointer in SSA is updated when the stack memory is allocated,
  123. // but the outside stack pointer saved in the ECALL stack frame is not changed accordingly.
  124. // When doing an OCALL, the stack pointer is set as the value in SSA and EEXIT.
  125. // When ECALL or exception handling returns, the stack pointer is set as the value in the ECALL stack frame and then EEXIT,
  126. // so the outside stack is automatically unwind.
  127. // In addition, sgx_ocalloc needs perform outside stack probe to make sure it is not allocating beyond the end of the stack.
  128. #define OC_ROUND 16
  129. /*
  130. void * sgx_ocalloc(size_t size)
  131. {
  132. // read the outside stack address from current SSA
  133. thread_data_t *thread_data = get_thread_data();
  134. ssa_gpr_t *ssa_gpr = reinterpret_cast<ssa_gpr_t *>(thread_data->first_ssa_gpr);
  135. size_t addr = ssa_gpr->REG(sp_u);
  136. // check u_rsp points to the untrusted address.
  137. // if the check fails, it should be hacked. call abort directly
  138. if(!sgx_is_outside_enclave(reinterpret_cast<void *>(addr), sizeof(size_t)))
  139. {
  140. abort();
  141. }
  142. // size is too large to allocate. call abort() directly.
  143. if(addr < size)
  144. {
  145. abort();
  146. }
  147. // calculate the start address for the allocated memory
  148. addr -= size;
  149. addr &= ~(static_cast<size_t>(OC_ROUND - 1)); // for stack alignment
  150. // the allocated memory has overlap with enclave, abort the enclave
  151. if(!sgx_is_outside_enclave(reinterpret_cast<void *>(addr), size))
  152. {
  153. abort();
  154. }
  155. // probe the outside stack to ensure that we do not skip over the stack3 guard page
  156. // we need to probe all the pages including the first page and the last page
  157. // the first page need to be probed in case uRTS didnot touch that page before EENTER enclave
  158. // the last page need to be probed in case the enclave didnot touch that page before another OCALLOC
  159. size_t first_page = TRIM_TO_PAGE(ssa_gpr->REG(sp_u) - 1);
  160. size_t last_page = TRIM_TO_PAGE(addr);
  161. // To avoid the dead-loop in the following for(...) loop.
  162. // Attacker might fake a stack address that is within address 0x4095.
  163. if (last_page == 0)
  164. {
  165. abort();
  166. }
  167. // the compiler may optimize the following code to probe the pages in any order
  168. // while we only expect the probe order should be from higher addr to lower addr
  169. // so use volatile to avoid optimization by the compiler
  170. for(volatile size_t page = first_page; page >= last_page; page -= SE_PAGE_SIZE)
  171. {
  172. // OS may refuse to commit a physical page if the page fault address is smaller than RSP
  173. // So update the outside stack address before probe the page
  174. ssa_gpr->REG(sp_u) = page;
  175. *reinterpret_cast<uint8_t *>(page) = 0;
  176. }
  177. // update the outside stack address in the SSA to the allocated address
  178. ssa_gpr->REG(sp_u) = addr;
  179. return reinterpret_cast<void *>(addr);
  180. }
  181. */
  182. // sgx_ocfree()
  183. // Parameters:
  184. // N/A
  185. // Return Value:
  186. // N/A
  187. // sgx_ocfree restores the original outside stack pointer in the SSA.
  188. // Do not call this function if you still need the buffer allocated by sgx_ocalloc within the ECALL.
  189. /*void sgx_ocfree()
  190. {
  191. // ECALL stack frame
  192. // last_sp -> | |
  193. // -------------
  194. // | ret_addr |
  195. // | xbp_u |
  196. // | xsp_u |
  197. thread_data_t *thread_data = get_thread_data();
  198. ssa_gpr_t *ssa_gpr = reinterpret_cast<ssa_gpr_t *>(thread_data->first_ssa_gpr);
  199. uintptr_t *addr = reinterpret_cast<uintptr_t *>(thread_data->last_sp);
  200. uintptr_t usp = *(addr - 3);
  201. if(!sgx_is_outside_enclave(reinterpret_cast<void *>(usp), sizeof(uintptr_t)))
  202. {
  203. abort();
  204. }
  205. ssa_gpr->REG(sp_u) = usp;
  206. }
  207. */
  208. #ifdef SE_SIM
  209. static sgx_spinlock_t g_seed_lock = SGX_SPINLOCK_INITIALIZER;
  210. static uint32_t get_rand_lcg()
  211. {
  212. sgx_spin_lock(&g_seed_lock);
  213. uint64_t& seed = g_global_data_sim.seed;
  214. seed = (uint64_t)(6364136223846793005ULL * seed + 1);
  215. uint32_t n = (uint32_t)(seed >> 32);
  216. sgx_spin_unlock(&g_seed_lock);
  217. return n;
  218. }
  219. #endif
  220. static sgx_status_t __do_get_rand32(uint32_t* rand_num)
  221. {
  222. #ifndef SE_SIM
  223. /* We expect the CPU has RDRAND support for HW mode. Otherwise, an exception will be thrown
  224. * do_rdrand() will try to call RDRAND for 10 times
  225. */
  226. if(0 == do_rdrand(rand_num))
  227. return SGX_ERROR_UNEXPECTED;
  228. #else
  229. /* use LCG in simulation mode */
  230. *rand_num = get_rand_lcg();
  231. #endif
  232. return SGX_SUCCESS;
  233. }
  234. sgx_status_t sgx_read_rand(unsigned char *rand, size_t length_in_bytes)
  235. {
  236. // check parameters
  237. //
  238. // rand can be within or outside the enclave
  239. if(!rand || !length_in_bytes)
  240. {
  241. return SGX_ERROR_INVALID_PARAMETER;
  242. }
  243. // if(!sgx_is_within_enclave(rand, length_in_bytes) && !sgx_is_outside_enclave(rand, length_in_bytes))
  244. // {
  245. // return SGX_ERROR_INVALID_PARAMETER;
  246. // }
  247. // loop to rdrand
  248. uint32_t rand_num = 0;
  249. while(length_in_bytes > 0)
  250. {
  251. sgx_status_t status = __do_get_rand32(&rand_num);
  252. if(status != SGX_SUCCESS)
  253. {
  254. return status;
  255. }
  256. size_t size = (length_in_bytes < sizeof(rand_num)) ? length_in_bytes : sizeof(rand_num);
  257. memcpy(rand, &rand_num, size);
  258. rand += size;
  259. length_in_bytes -= size;
  260. }
  261. memset_s(&rand_num, sizeof(rand_num), 0, sizeof(rand_num));
  262. return SGX_SUCCESS;
  263. }
  264. /*
  265. int sgx_is_enclave_crashed()
  266. {
  267. return get_enclave_state() == ENCLAVE_CRASHED;
  268. }
  269. extern uintptr_t __stack_chk_guard;
  270. int check_static_stack_canary(void *tcs)
  271. {
  272. size_t *canary = TCS2CANARY(tcs);
  273. if ( *canary != (size_t)__stack_chk_guard)
  274. {
  275. return -1;
  276. }
  277. return 0;
  278. }
  279. */