GoogleGit

blob: 0ccf1d20d83975a276921609a8a82f96ff020169 [file] [log] [blame]
  1. /*
  2. * Copyright (c) 2013 The Native Client Authors. All rights reserved.
  3. * Use of this source code is governed by a BSD-style license that can be
  4. * found in the LICENSE file.
  5. */
  6. #include "native_client/src/include/build_config.h"
  7. #include "native_client/src/trusted/service_runtime/thread_suspension_unwind.h"
  8. #include "native_client/src/trusted/cpu_features/arch/x86/cpu_x86.h"
  9. #include "native_client/src/trusted/service_runtime/arch/arm/tramp_arm.h"
  10. #include "native_client/src/trusted/service_runtime/arch/x86_64/tramp_64.h"
  11. #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
  12. #include "native_client/src/trusted/service_runtime/nacl_config.h"
  13. #include "native_client/src/trusted/service_runtime/nacl_copy.h"
  14. #include "native_client/src/trusted/service_runtime/sel_ldr.h"
  15. static void GetNaClSyscallSeg(struct NaClApp *nap,
  16. uintptr_t *nacl_syscall_seg,
  17. uintptr_t *nacl_syscall_seg_regs_saved) {
  18. #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
  19. NaClCPUFeaturesX86 *features = (NaClCPUFeaturesX86 *) nap->cpu_features;
  20. if (NaClGetCPUFeatureX86(features, NaClCPUFeatureX86_SSE)) {
  21. *nacl_syscall_seg = (uintptr_t) &NaClSyscallSegSSE;
  22. *nacl_syscall_seg_regs_saved = (uintptr_t) &NaClSyscallSegRegsSavedSSE;
  23. } else {
  24. *nacl_syscall_seg = (uintptr_t) &NaClSyscallSegNoSSE;
  25. *nacl_syscall_seg_regs_saved = (uintptr_t) &NaClSyscallSegRegsSavedNoSSE;
  26. }
  27. #else
  28. UNREFERENCED_PARAMETER(nap);
  29. *nacl_syscall_seg = (uintptr_t) &NaClSyscallSeg;
  30. *nacl_syscall_seg_regs_saved = (uintptr_t) &NaClSyscallSegRegsSaved;
  31. #endif
  32. }
  33. /*
  34. * This returns 0 if |regs| indicates that the thread's register state
  35. * has already been saved in NaClThreadContext. Otherwise, it adjusts
  36. * |regs| to undo the effects of calling the syscall trampoline and
  37. * returns 1.
  38. */
  39. static int Unwind(struct NaClAppThread *natp, struct NaClSignalContext *regs,
  40. enum NaClUnwindCase *unwind_case) {
  41. struct NaClApp *nap = natp->nap;
  42. uintptr_t nacl_syscall_seg;
  43. uintptr_t nacl_syscall_seg_regs_saved;
  44. #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
  45. if (regs->cs == natp->user.cs &&
  46. regs->prog_ctr >= nap->syscall_return_springboard.start_addr &&
  47. regs->prog_ctr < nap->syscall_return_springboard.end_addr) {
  48. *unwind_case = NACL_UNWIND_in_springboard;
  49. return 0;
  50. }
  51. if (regs->cs == natp->user.cs &&
  52. regs->prog_ctr >= NACL_TRAMPOLINE_START &&
  53. regs->prog_ctr < NACL_TRAMPOLINE_END) {
  54. *unwind_case = NACL_UNWIND_in_trampoline;
  55. regs->stack_ptr += 4; /* Pop user return address */
  56. return 1;
  57. }
  58. #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
  59. if (regs->prog_ctr >= NaClUserToSys(nap, NACL_TRAMPOLINE_START) &&
  60. regs->prog_ctr < NaClUserToSys(nap, NACL_TRAMPOLINE_END)) {
  61. *unwind_case = NACL_UNWIND_in_trampoline;
  62. regs->stack_ptr += 8; /* Pop user return address */
  63. return 1;
  64. }
  65. #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
  66. if (regs->prog_ctr >= NACL_TRAMPOLINE_START &&
  67. regs->prog_ctr < NACL_TRAMPOLINE_END) {
  68. *unwind_case = NACL_UNWIND_in_trampoline;
  69. regs->prog_ctr = NaClSandboxCodeAddr(nap, regs->lr);
  70. return 1;
  71. }
  72. #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
  73. if (regs->prog_ctr >= NACL_TRAMPOLINE_START &&
  74. regs->prog_ctr < NACL_TRAMPOLINE_END) {
  75. *unwind_case = NACL_UNWIND_in_trampoline;
  76. regs->prog_ctr = NaClSandboxCodeAddr(nap, regs->return_addr);
  77. return 1;
  78. }
  79. #endif
  80. #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
  81. if (regs->cs == NaClGetGlobalCs() &&
  82. regs->prog_ctr >= nap->pcrel_thunk &&
  83. regs->prog_ctr < nap->pcrel_thunk_end) {
  84. *unwind_case = NACL_UNWIND_in_pcrel_thunk;
  85. regs->stack_ptr += 4 + 8; /* Pop user + trampoline return addresses */
  86. return 1;
  87. }
  88. #endif
  89. #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
  90. if (regs->prog_ctr >= (uintptr_t) &NaClGetTlsFastPath1 &&
  91. regs->prog_ctr < (uintptr_t) &NaClGetTlsFastPath1End) {
  92. *unwind_case = NACL_UNWIND_in_tls_fast_path;
  93. if (regs->prog_ctr < (uintptr_t) &NaClGetTlsFastPath1RspRestored) {
  94. regs->stack_ptr += 8; /* Pop user return address */
  95. }
  96. return 1;
  97. }
  98. if (regs->prog_ctr >= (uintptr_t) &NaClGetTlsFastPath2 &&
  99. regs->prog_ctr < (uintptr_t) &NaClGetTlsFastPath2End) {
  100. *unwind_case = NACL_UNWIND_in_tls_fast_path;
  101. if (regs->prog_ctr < (uintptr_t) &NaClGetTlsFastPath2RspRestored) {
  102. regs->stack_ptr += 8; /* Pop user return address */
  103. }
  104. return 1;
  105. }
  106. #endif
  107. GetNaClSyscallSeg(nap, &nacl_syscall_seg, &nacl_syscall_seg_regs_saved);
  108. if (regs->prog_ctr >= nacl_syscall_seg &&
  109. regs->prog_ctr < nacl_syscall_seg_regs_saved) {
  110. *unwind_case = NACL_UNWIND_in_syscallseg;
  111. #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
  112. /* Pop user + trampoline return addresses */
  113. regs->stack_ptr += 4 + 8;
  114. #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
  115. /* Pop user return address. */
  116. regs->stack_ptr += 8;
  117. #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
  118. /*
  119. * On MIPS, $ra is not modified from the start of the trampoline to the
  120. * point where registers are saved.
  121. */
  122. regs->prog_ctr = NaClSandboxCodeAddr(nap, regs->return_addr);
  123. #endif
  124. return 1;
  125. }
  126. *unwind_case = NACL_UNWIND_after_saving_regs;
  127. return 0;
  128. }
  129. /*
  130. * Given that thread |natp| has been suspended during a
  131. * trusted/untrusted context switch and has trusted register state
  132. * |regs|, this modifies |regs| to contain untrusted register state
  133. * (that is, the state the syscall will return with).
  134. */
  135. void NaClGetRegistersForContextSwitch(struct NaClAppThread *natp,
  136. struct NaClSignalContext *regs,
  137. enum NaClUnwindCase *unwind_case) {
  138. if (Unwind(natp, regs, unwind_case)) {
  139. NaClSignalContextUnsetClobberedRegisters(regs);
  140. } else {
  141. NaClThreadContextToSignalContext(&natp->user, regs);
  142. }
  143. if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 ||
  144. (NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm &&
  145. *unwind_case != NACL_UNWIND_in_trampoline) ||
  146. (NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips &&
  147. *unwind_case != NACL_UNWIND_in_trampoline &&
  148. *unwind_case != NACL_UNWIND_in_syscallseg)) {
  149. /*
  150. * Read the return address from the untrusted stack.
  151. * NaClCopyInFromUser() can fault or return an error here, but only
  152. * if the thread was suspended just before it was about to crash.
  153. * This can happen if untrusted code JMP'd to the trampoline with a
  154. * bad stack pointer or if the thread was racing with an munmap().
  155. */
  156. nacl_reg_t user_ret = 0;
  157. if (!NaClCopyInFromUser(natp->nap, &user_ret,
  158. (uint32_t) (regs->stack_ptr + NACL_USERRET_FIX),
  159. sizeof(user_ret))) {
  160. NaClLog(LOG_WARNING, "NaClGetRegistersForContextSwitch: "
  161. "Failed to read return address; using dummy value\n");
  162. }
  163. regs->prog_ctr = NaClSandboxCodeAddr(natp->nap, user_ret);
  164. }
  165. }