db_exception.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /* Copyright (C) 2014 Stony Brook University
  2. This file is part of Graphene Library OS.
  3. Graphene Library OS is free software: you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public License
  5. as published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. Graphene Library OS is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /*
  14. * db_signal.c
  15. *
  16. * This file contains APIs to set up handlers of exceptions issued by the
  17. * host, and the methods to pass the exceptions to the upcalls.
  18. */
  19. #include "pal_defs.h"
  20. #include "pal_linux_defs.h"
  21. #include "pal.h"
  22. #include "pal_internal.h"
  23. #include "pal_linux.h"
  24. #include "pal_error.h"
  25. #include "pal_security.h"
  26. #include "api.h"
  27. #include "ecall_types.h"
  28. #include <atomic.h>
  29. #include <sigset.h>
  30. #include <linux/signal.h>
  31. #include <ucontext.h>
  32. static bool
  33. _DkGenericSignalHandle(int event_num, PAL_NUM arg, PAL_CONTEXT* context) {
  34. PAL_EVENT_HANDLER upcall = _DkGetExceptionHandler(event_num);
  35. if (upcall) {
  36. (*upcall)(NULL, arg, context);
  37. return true;
  38. }
  39. return false;
  40. }
  41. #define ADDR_IN_PAL(addr) \
  42. ((void*)(addr) > TEXT_START && (void*)(addr) < TEXT_END)
  43. /*
  44. * Restore an sgx_cpu_context_t as generated by .Lhandle_exception. Execution will
  45. * continue as specified by the rip in the context.
  46. */
  47. noreturn static void restore_sgx_context(sgx_cpu_context_t* uc,
  48. PAL_XREGS_STATE* xregs_state) {
  49. if (xregs_state == NULL)
  50. xregs_state = (PAL_XREGS_STATE*)xsave_reset_state;
  51. _restore_sgx_context(uc, xregs_state);
  52. }
  53. noreturn static void restore_pal_context(sgx_cpu_context_t* uc, PAL_CONTEXT* ctx) {
  54. uc->rax = ctx->rax;
  55. uc->rbx = ctx->rbx;
  56. uc->rcx = ctx->rcx;
  57. uc->rdx = ctx->rdx;
  58. uc->rsp = ctx->rsp;
  59. uc->rbp = ctx->rbp;
  60. uc->rsi = ctx->rsi;
  61. uc->rdi = ctx->rdi;
  62. uc->r8 = ctx->r8;
  63. uc->r9 = ctx->r9;
  64. uc->r10 = ctx->r10;
  65. uc->r11 = ctx->r11;
  66. uc->r12 = ctx->r12;
  67. uc->r13 = ctx->r13;
  68. uc->r14 = ctx->r14;
  69. uc->r15 = ctx->r15;
  70. uc->rflags = ctx->efl;
  71. uc->rip = ctx->rip;
  72. restore_sgx_context(uc, ctx->fpregs);
  73. }
  74. static void save_pal_context(PAL_CONTEXT* ctx, sgx_cpu_context_t* uc,
  75. PAL_XREGS_STATE* xregs_state) {
  76. memset(ctx, 0, sizeof(*ctx));
  77. ctx->rax = uc->rax;
  78. ctx->rbx = uc->rbx;
  79. ctx->rcx = uc->rcx;
  80. ctx->rdx = uc->rdx;
  81. ctx->rsp = uc->rsp;
  82. ctx->rbp = uc->rbp;
  83. ctx->rsi = uc->rsi;
  84. ctx->rdi = uc->rdi;
  85. ctx->r8 = uc->r8;
  86. ctx->r9 = uc->r9;
  87. ctx->r10 = uc->r10;
  88. ctx->r11 = uc->r11;
  89. ctx->r12 = uc->r12;
  90. ctx->r13 = uc->r13;
  91. ctx->r14 = uc->r14;
  92. ctx->r15 = uc->r15;
  93. ctx->efl = uc->rflags;
  94. ctx->rip = uc->rip;
  95. union pal_csgsfs csgsfs = {
  96. .cs = 0x33, // __USER_CS(5) | 0(GDT) | 3(RPL)
  97. .fs = 0,
  98. .gs = 0,
  99. .ss = 0x2b, // __USER_DS(6) | 0(GDT) | 3(RPL)
  100. };
  101. ctx->csgsfs = csgsfs.csgsfs;
  102. assert(xregs_state);
  103. ctx->fpregs = xregs_state;
  104. /* Emulate format for fp registers Linux sets up as signal frame.
  105. * https://elixir.bootlin.com/linux/v5.4.13/source/arch/x86/kernel/fpu/signal.c#L86
  106. * https://elixir.bootlin.com/linux/v5.4.13/source/arch/x86/kernel/fpu/signal.c#L459
  107. */
  108. PAL_FPX_SW_BYTES* fpx_sw = &xregs_state->fpstate.sw_reserved;
  109. fpx_sw->magic1 = PAL_FP_XSTATE_MAGIC1;
  110. fpx_sw->extended_size = xsave_size;
  111. fpx_sw->xfeatures = xsave_features;
  112. memset(fpx_sw->padding, 0, sizeof(fpx_sw->padding));
  113. if (xsave_enabled) {
  114. fpx_sw->xstate_size = xsave_size + PAL_FP_XSTATE_MAGIC2_SIZE;
  115. *(__typeof__(PAL_FP_XSTATE_MAGIC2)*)((void*)xregs_state + xsave_size) =
  116. PAL_FP_XSTATE_MAGIC2;
  117. } else {
  118. fpx_sw->xstate_size = xsave_size;
  119. }
  120. }
  121. /*
  122. * return value:
  123. * true: #UD is handled.
  124. * the execution can be continued without propagating #UD.
  125. * false: #UD is not handled.
  126. * the exception needs to be raised up to LibOS or user application.
  127. */
  128. static bool handle_ud(sgx_cpu_context_t * uc)
  129. {
  130. uint8_t * instr = (uint8_t *) uc->rip;
  131. if (instr[0] == 0xcc) { /* skip int 3 */
  132. uc->rip++;
  133. return true;
  134. } else if (instr[0] == 0x0f && instr[1] == 0xa2) {
  135. /* cpuid */
  136. unsigned int values[4];
  137. if (!_DkCpuIdRetrieve(uc->rax & 0xffffffff,
  138. uc->rcx & 0xffffffff, values)) {
  139. uc->rip += 2;
  140. uc->rax = values[0];
  141. uc->rbx = values[1];
  142. uc->rcx = values[2];
  143. uc->rdx = values[3];
  144. return true;
  145. }
  146. } else if (instr[0] == 0x0f && instr[1] == 0x31) {
  147. /* rdtsc */
  148. uc->rip += 2;
  149. uc->rdx = 0;
  150. uc->rax = 0;
  151. return true;
  152. } else if (instr[0] == 0x0f && instr[1] == 0x05) {
  153. /* syscall: LibOS may know how to handle this */
  154. return false;
  155. }
  156. SGX_DBG(DBG_E, "Unknown or illegal instruction at RIP 0x%016lx\n", uc->rip);
  157. return false;
  158. }
  159. void _DkExceptionHandler(
  160. unsigned int exit_info, sgx_cpu_context_t* uc, PAL_XREGS_STATE* xregs_state) {
  161. assert(IS_ALIGNED_PTR(xregs_state, PAL_XSTATE_ALIGN));
  162. union {
  163. sgx_arch_exit_info_t info;
  164. unsigned int intval;
  165. } ei = { .intval = exit_info };
  166. int event_num;
  167. if (!ei.info.valid) {
  168. event_num = exit_info;
  169. } else {
  170. switch (ei.info.vector) {
  171. case SGX_EXCEPTION_VECTOR_BR:
  172. event_num = PAL_EVENT_NUM_BOUND;
  173. break;
  174. case SGX_EXCEPTION_VECTOR_UD:
  175. if (handle_ud(uc)) {
  176. restore_sgx_context(uc, xregs_state);
  177. /* NOTREACHED */
  178. }
  179. event_num = PAL_EVENT_ILLEGAL;
  180. break;
  181. case SGX_EXCEPTION_VECTOR_DE:
  182. case SGX_EXCEPTION_VECTOR_MF:
  183. case SGX_EXCEPTION_VECTOR_XM:
  184. event_num = PAL_EVENT_ARITHMETIC_ERROR;
  185. break;
  186. case SGX_EXCEPTION_VECTOR_AC:
  187. event_num = PAL_EVENT_MEMFAULT;
  188. break;
  189. case SGX_EXCEPTION_VECTOR_DB:
  190. case SGX_EXCEPTION_VECTOR_BP:
  191. default:
  192. restore_sgx_context(uc, xregs_state);
  193. /* NOTREACHED */
  194. }
  195. }
  196. if (ADDR_IN_PAL(uc->rip) &&
  197. /* event isn't asynchronous */
  198. (event_num != PAL_EVENT_QUIT &&
  199. event_num != PAL_EVENT_SUSPEND &&
  200. event_num != PAL_EVENT_RESUME)) {
  201. printf("*** An unexpected AEX vector occurred inside PAL. "
  202. "Exiting the thread. *** \n"
  203. "(vector = 0x%x, type = 0x%x valid = %d, RIP = +0x%08lx)\n"
  204. "rax: 0x%08lx rcx: 0x%08lx rdx: 0x%08lx rbx: 0x%08lx\n"
  205. "rsp: 0x%08lx rbp: 0x%08lx rsi: 0x%08lx rdi: 0x%08lx\n"
  206. "r8 : 0x%08lx r9 : 0x%08lx r10: 0x%08lx r11: 0x%08lx\n"
  207. "r12: 0x%08lx r13: 0x%08lx r14: 0x%08lx r15: 0x%08lx\n"
  208. "rflags: 0x%08lx rip: 0x%08lx\n",
  209. ei.info.vector, ei.info.exit_type, ei.info.valid,
  210. uc->rip - (uintptr_t) TEXT_START,
  211. uc->rax, uc->rcx, uc->rdx, uc->rbx,
  212. uc->rsp, uc->rbp, uc->rsi, uc->rdi,
  213. uc->r8, uc->r9, uc->r10, uc->r11,
  214. uc->r12, uc->r13, uc->r14, uc->r15,
  215. uc->rflags, uc->rip);
  216. #ifdef DEBUG
  217. printf("pausing for debug\n");
  218. while (true)
  219. __asm__ volatile("pause");
  220. #endif
  221. _DkThreadExit(/*clear_child_tid=*/NULL);
  222. }
  223. PAL_CONTEXT ctx;
  224. save_pal_context(&ctx, uc, xregs_state);
  225. /* TODO: save EXINFO from MISC region and populate below fields */
  226. ctx.err = 0;
  227. ctx.trapno = ei.info.valid ? ei.info.vector : event_num;
  228. ctx.oldmask = 0;
  229. ctx.cr2 = 0;
  230. PAL_NUM arg = 0;
  231. switch (event_num) {
  232. case PAL_EVENT_ILLEGAL:
  233. arg = uc->rip;
  234. break;
  235. case PAL_EVENT_MEMFAULT:
  236. /* TODO
  237. * SGX1 doesn't provide fault address.
  238. * SGX2 gives providing page. (lower address bits are masked)
  239. */
  240. break;
  241. default:
  242. /* nothing */
  243. break;
  244. }
  245. _DkGenericSignalHandle(event_num, arg, &ctx);
  246. restore_pal_context(uc, &ctx);
  247. }
  248. void _DkRaiseFailure(int error) {
  249. _DkGenericSignalHandle(PAL_EVENT_FAILURE, error, /*context=*/NULL);
  250. }
  251. void _DkExceptionReturn(void* event) {
  252. __UNUSED(event);
  253. }
  254. noreturn void _DkHandleExternalEvent(
  255. PAL_NUM event, sgx_cpu_context_t* uc, PAL_XREGS_STATE* xregs_state) {
  256. assert(event);
  257. assert(IS_ALIGNED_PTR(xregs_state, PAL_XSTATE_ALIGN));
  258. /* We only end up in _DkHandleExternalEvent() if interrupted during
  259. * host syscall; Inform LibOS layer that PAL was interrupted (by setting PAL_ERRNO). */
  260. _DkRaiseFailure(PAL_ERROR_INTERRUPTED);
  261. PAL_CONTEXT ctx;
  262. save_pal_context(&ctx, uc, xregs_state);
  263. ctx.err = 0;
  264. /* TODO: event is a PAL event; is that what LibOS/app wants to see? */
  265. ctx.trapno = event;
  266. ctx.oldmask = 0;
  267. ctx.cr2 = 0;
  268. if (!_DkGenericSignalHandle(event, 0, &ctx) && event != PAL_EVENT_RESUME) {
  269. _DkThreadExit(/*clear_child_tid=*/NULL);
  270. }
  271. /*
  272. * The modification to PAL_CONTEXT is discarded.
  273. * It is assumed that LibOS won't change context (GPRs, fp registers)
  274. * if RIP is in PAL.
  275. *
  276. * TODO: in long term, record the signal and trigger the signal handler
  277. * when returning from PAL by the use of
  278. * ENTER_PAL_CALL/LEAVE_PAL_CALL/LEAVE_PAL_CALL_RETURN.
  279. */
  280. restore_sgx_context(uc, xregs_state);
  281. }