LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - thread_suspension_unwind.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 50 30 60.0 %
Date: 2014-06-18 Functions: 0 0 -

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

Generated by: LCOV version 1.7