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

       1                 : /*
       2                 :  * Copyright (c) 2012 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 <stdio.h>
       8                 : #include <stdlib.h>
       9                 : #include <string.h>
      10                 : 
      11                 : #include "native_client/src/include/nacl_base.h"
      12                 : #include "native_client/src/include/portability_io.h"
      13                 : #include "native_client/src/shared/platform/nacl_check.h"
      14                 : #include "native_client/src/shared/platform/nacl_exit.h"
      15                 : #include "native_client/src/shared/platform/nacl_log.h"
      16                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      17                 : #include "native_client/src/trusted/service_runtime/nacl_exception.h"
      18                 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
      19                 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
      20                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      21                 : 
      22                 : #if NACL_WINDOWS
      23                 : #include <io.h>
      24                 : #define write _write
      25                 : #else
      26                 : #include <unistd.h>
      27                 : #endif
      28                 : 
      29                 : 
      30               0 : ssize_t NaClSignalErrorMessage(const char *msg) {
      31                 :   /*
      32                 :    * We cannot use NaClLog() in the context of a signal handler: it is
      33                 :    * too complex.  However, write() is signal-safe.
      34                 :    */
      35               0 :   size_t len_t = strlen(msg);
      36               0 :   int len = (int) len_t;
      37                 : 
      38                 :   /*
      39                 :    * Write uses int not size_t, so we may wrap the length and/or
      40                 :    * generate a negative value.  Only print if it matches.
      41                 :    */
      42               0 :   if ((len > 0) && (len_t == (size_t) len)) {
      43               0 :     return (ssize_t) write(2, msg, len);
      44                 :   }
      45                 : 
      46               0 :   return 0;
      47               0 : }
      48                 : 
      49                 : /*
      50                 :  * This function takes the register state (sig_ctx) for a thread
      51                 :  * (natp) that has been suspended and returns whether the thread was
      52                 :  * suspended while executing untrusted code.
      53                 :  */
      54           11674 : int NaClSignalContextIsUntrusted(struct NaClAppThread *natp,
      55           11674 :                                  const struct NaClSignalContext *sig_ctx) {
      56           11674 :   uint32_t prog_ctr;
      57                 : 
      58                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
      59                 :   /*
      60                 :    * Note that we do not check "sig_ctx != NaClGetGlobalCs()".  On Mac
      61                 :    * OS X, if a thread is suspended while in a syscall,
      62                 :    * thread_get_state() returns cs=0x7 rather than cs=0x17 (the normal
      63                 :    * cs value for trusted code).
      64                 :    */
      65                 :   if (sig_ctx->cs != natp->user.cs)
      66                 :     return 0;
      67                 : #elif (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64) || \
      68                 :       NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm || \
      69                 :       NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
      70           11674 :   if (!NaClIsUserAddr(natp->nap, sig_ctx->prog_ctr))
      71           11498 :     return 0;
      72                 : #else
      73                 : # error Unsupported architecture
      74                 : #endif
      75                 : 
      76             176 :   prog_ctr = (uint32_t) sig_ctx->prog_ctr;
      77             528 :   return (prog_ctr < NACL_TRAMPOLINE_START ||
      78                 :           prog_ctr >= NACL_TRAMPOLINE_END);
      79           11674 : }
      80                 : 
      81                 : /*
      82                 :  * Sanity checks: Reject unsafe register state that untrusted code
      83                 :  * should not be able to set unless there is a sandbox hole.  We do
      84                 :  * this in an attempt to prevent such a hole from being exploitable.
      85                 :  */
      86           14923 : int NaClSignalCheckSandboxInvariants(const struct NaClSignalContext *regs,
      87           14923 :                                      struct NaClAppThread *natp) {
      88                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
      89                 :   if (regs->cs != natp->user.cs ||
      90                 :       regs->ds != natp->user.ds ||
      91                 :       regs->es != natp->user.es ||
      92                 :       regs->fs != natp->user.fs ||
      93                 :       regs->gs != natp->user.gs ||
      94                 :       regs->ss != natp->user.ss) {
      95                 :     return 0;
      96                 :   }
      97                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
      98                 :   /*
      99                 :    * Untrusted code can temporarily set %rsp/%rbp to be in the 0..4GB
     100                 :    * range but it should not be able to generate a fault while in that
     101                 :    * state.
     102                 :    */
     103           14923 :   if (regs->r15 != natp->user.r15 ||
     104           14923 :       !NaClIsUserAddr(natp->nap, regs->stack_ptr) ||
     105           14923 :       !NaClIsUserAddr(natp->nap, regs->rbp)) {
     106               0 :     return 0;
     107                 :   }
     108                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
     109                 :   if (!NaClIsUserAddr(natp->nap, regs->stack_ptr) ||
     110                 :       regs->r9 != (uintptr_t) &natp->user.tls_value1) {
     111                 :     return 0;
     112                 :   }
     113                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
     114                 :   if (!NaClIsUserAddr(natp->nap, regs->stack_ptr) ||
     115                 :       regs->t6 != NACL_CONTROL_FLOW_MASK ||
     116                 :       regs->t7 != NACL_DATA_FLOW_MASK) {
     117                 :     return 0;
     118                 :   }
     119                 : #else
     120                 : # error Unsupported architecture
     121                 : #endif
     122           14923 :   return 1;
     123           14923 : }
     124                 : 
     125               0 : void NaClSignalHandleUntrusted(int signal,
     126               0 :                                const struct NaClSignalContext *regs,
     127               0 :                                int is_untrusted) {
     128               0 :   char tmp[128];
     129                 :   /*
     130                 :    * Return an 8 bit error code which is -signal to
     131                 :    * simulate normal OS behavior
     132                 :    */
     133               0 :   if (is_untrusted) {
     134               0 :     SNPRINTF(tmp, sizeof(tmp), "\n** Signal %d from untrusted code: "
     135                 :              "pc=%" NACL_PRIxNACL_REG "\n", signal, regs->prog_ctr);
     136               0 :     NaClSignalErrorMessage(tmp);
     137               0 :     NaClExit((-signal) & 0xFF);
     138               0 :   } else {
     139               0 :     SNPRINTF(tmp, sizeof(tmp), "\n** Signal %d from trusted code: "
     140                 :              "pc=%" NACL_PRIxNACL_REG "\n", signal, regs->prog_ctr);
     141               0 :     NaClSignalErrorMessage(tmp);
     142                 :     /*
     143                 :      * Continue the search for another handler so that trusted crashes
     144                 :      * can be handled by the Breakpad crash reporter.
     145                 :      */
     146                 :   }
     147               0 : }
     148                 : 
     149                 : 
     150                 : /*
     151                 :  * This is a separate function to make it obvious from the crash
     152                 :  * reports that this crash is deliberate and for testing purposes.
     153                 :  */
     154                 : void NaClSignalTestCrashOnStartup(void) {
     155             265 :   if (getenv("NACL_CRASH_TEST") != NULL) {
     156               0 :     NaClSignalErrorMessage("[CRASH_TEST] Causing crash in NaCl "
     157                 :                            "trusted code...\n");
     158                 :     /*
     159                 :      * Clang transmutes a NULL pointer reference into a generic
     160                 :      * "undefined" case.  That code crashes with a different signal
     161                 :      * than an actual bad pointer reference, violating the tests'
     162                 :      * expectations.  A pointer that is known bad but is not literally
     163                 :      * NULL does not get this treatment.
     164                 :      */
     165               0 :     *(volatile int *) 1 = 0;
     166               0 :   }
     167             265 : }
     168                 : 
     169                 : static void NaClUserRegisterStateFromSignalContext(
     170           14923 :     volatile NaClUserRegisterState *dest,
     171           14923 :     const struct NaClSignalContext *src) {
     172                 : #define COPY_REG(reg) dest->reg = src->reg
     173                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
     174                 :   COPY_REG(eax);
     175                 :   COPY_REG(ecx);
     176                 :   COPY_REG(edx);
     177                 :   COPY_REG(ebx);
     178                 :   COPY_REG(stack_ptr);
     179                 :   COPY_REG(ebp);
     180                 :   COPY_REG(esi);
     181                 :   COPY_REG(edi);
     182                 :   COPY_REG(prog_ctr);
     183                 :   COPY_REG(flags);
     184                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
     185           14923 :   COPY_REG(rax);
     186           14923 :   COPY_REG(rcx);
     187           14923 :   COPY_REG(rdx);
     188           14923 :   COPY_REG(rbx);
     189           14923 :   COPY_REG(stack_ptr);
     190           14923 :   COPY_REG(rbp);
     191           14923 :   COPY_REG(rsi);
     192           14923 :   COPY_REG(rdi);
     193           14923 :   COPY_REG(r8);
     194           14923 :   COPY_REG(r9);
     195           14923 :   COPY_REG(r10);
     196           14923 :   COPY_REG(r11);
     197           14923 :   COPY_REG(r12);
     198           14923 :   COPY_REG(r13);
     199           14923 :   COPY_REG(r14);
     200           14923 :   COPY_REG(r15);
     201           14923 :   COPY_REG(prog_ctr);
     202           14923 :   COPY_REG(flags);
     203                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
     204                 :   COPY_REG(r0);
     205                 :   COPY_REG(r1);
     206                 :   COPY_REG(r2);
     207                 :   COPY_REG(r3);
     208                 :   COPY_REG(r4);
     209                 :   COPY_REG(r5);
     210                 :   COPY_REG(r6);
     211                 :   COPY_REG(r7);
     212                 :   COPY_REG(r8);
     213                 :   /* Don't leak the address of NaClAppThread by reporting r9's value here. */
     214                 :   dest->r9 = -1;
     215                 :   COPY_REG(r10);
     216                 :   COPY_REG(r11);
     217                 :   COPY_REG(r12);
     218                 :   COPY_REG(stack_ptr);
     219                 :   COPY_REG(lr);
     220                 :   COPY_REG(prog_ctr);
     221                 :   COPY_REG(cpsr);
     222                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
     223                 :   COPY_REG(zero);
     224                 :   COPY_REG(at);
     225                 :   COPY_REG(v0);
     226                 :   COPY_REG(v1);
     227                 :   COPY_REG(a0);
     228                 :   COPY_REG(a1);
     229                 :   COPY_REG(a2);
     230                 :   COPY_REG(a3);
     231                 :   COPY_REG(t0);
     232                 :   COPY_REG(t1);
     233                 :   COPY_REG(t2);
     234                 :   COPY_REG(t3);
     235                 :   COPY_REG(t4);
     236                 :   COPY_REG(t5);
     237                 :   COPY_REG(t6);
     238                 :   COPY_REG(t7);
     239                 :   COPY_REG(s0);
     240                 :   COPY_REG(s1);
     241                 :   COPY_REG(s2);
     242                 :   COPY_REG(s3);
     243                 :   COPY_REG(s4);
     244                 :   COPY_REG(s5);
     245                 :   COPY_REG(s6);
     246                 :   COPY_REG(s7);
     247                 :   COPY_REG(t8);
     248                 :   COPY_REG(t9);
     249                 :   COPY_REG(k0);
     250                 :   COPY_REG(k1);
     251                 :   COPY_REG(global_ptr);
     252                 :   COPY_REG(stack_ptr);
     253                 :   COPY_REG(frame_ptr);
     254                 :   COPY_REG(return_addr);
     255                 :   COPY_REG(prog_ctr);
     256                 : #else
     257                 : # error Unsupported architecture
     258                 : #endif
     259                 : #undef COPY_REG
     260           14923 : }
     261                 : 
     262                 : /*
     263                 :  * The |frame| argument is volatile because this function writes
     264                 :  * directly into untrusted address space on Linux.
     265                 :  */
     266           14923 : void NaClSignalSetUpExceptionFrame(volatile struct NaClExceptionFrame *frame,
     267           14923 :                                    const struct NaClSignalContext *regs,
     268           14923 :                                    uint32_t context_user_addr) {
     269           14923 :   unsigned i;
     270                 : 
     271                 :   /*
     272                 :    * Use the end of frame->portable for the size, avoiding padding
     273                 :    * added after it within NaClExceptionFrame.
     274                 :    */
     275           14923 :   frame->context.size =
     276                 :       (uint32_t) ((uintptr_t) (&frame->portable + 1) -
     277                 :                   (uintptr_t) &frame->context);
     278           14923 :   frame->context.portable_context_offset =
     279                 :       (uint32_t) ((uintptr_t) &frame->portable -
     280                 :                   (uintptr_t) &frame->context);
     281           14923 :   frame->context.portable_context_size = sizeof(frame->portable);
     282           14923 :   frame->context.arch = NACL_ELF_E_MACHINE;
     283           14923 :   frame->context.regs_size = sizeof(frame->context.regs);
     284                 : 
     285                 :   /* Avoid memset() here because |frame| is volatile. */
     286          358152 :   for (i = 0; i < NACL_ARRAY_SIZE(frame->context.reserved); i++) {
     287          164153 :     frame->context.reserved[i] = 0;
     288          164153 :   }
     289                 : 
     290           14923 :   NaClUserRegisterStateFromSignalContext(&frame->context.regs, regs);
     291                 : 
     292           14923 :   frame->portable.prog_ctr = (uint32_t) regs->prog_ctr;
     293           14923 :   frame->portable.stack_ptr = (uint32_t) regs->stack_ptr;
     294                 : 
     295                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
     296                 :   frame->context_ptr = context_user_addr;
     297                 :   frame->portable.frame_ptr = (uint32_t) regs->ebp;
     298                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
     299           29846 :   UNREFERENCED_PARAMETER(context_user_addr);
     300           14923 :   frame->portable.frame_ptr = (uint32_t) regs->rbp;
     301                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
     302                 :   UNREFERENCED_PARAMETER(context_user_addr);
     303                 :   frame->portable.frame_ptr = regs->r11;
     304                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
     305                 :   UNREFERENCED_PARAMETER(context_user_addr);
     306                 :   frame->portable.frame_ptr = regs->frame_ptr;
     307                 : #else
     308                 : # error Unsupported architecture
     309                 : #endif
     310                 : 
     311                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
     312                 :   /*
     313                 :    * Returning from the exception handler is not possible, so to avoid
     314                 :    * any confusion that might arise from jumping to an uninitialised
     315                 :    * address, we set the return address to zero.
     316                 :    */
     317           14923 :   frame->return_addr = 0;
     318                 : #endif
     319           14923 : }

Generated by: LCOV version 1.7