LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - nacl_signal_common.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 79 47 59.5 %
Date: 2012-02-16 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_globals.h"
      18                 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
      19                 : #include "native_client/src/trusted/service_runtime/nacl_tls.h"
      20                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      21                 : 
      22                 : #ifdef WIN32
      23                 : #include <io.h>
      24                 : #define write _write
      25                 : #else
      26                 : #include <unistd.h>
      27                 : #endif
      28                 : 
      29                 : #define MAX_NACL_HANDLERS 16
      30                 : 
      31                 : struct NaClSignalNode {
      32                 :   struct NaClSignalNode *next;
      33                 :   NaClSignalHandler func;
      34                 :   int id;
      35                 : };
      36                 : 
      37                 : 
      38                 : static struct NaClSignalNode *s_FirstHandler = NULL;
      39                 : static struct NaClSignalNode *s_FreeList = NULL;
      40                 : static struct NaClSignalNode s_SignalNodes[MAX_NACL_HANDLERS];
      41                 : 
      42               3 : ssize_t NaClSignalErrorMessage(const char *msg) {
      43                 :   /*
      44                 :    * We cannot use NaClLog() in the context of a signal handler: it is
      45                 :    * too complex.  However, write() is signal-safe.
      46                 :    */
      47               3 :   size_t len_t = strlen(msg);
      48               3 :   int len = (int) len_t;
      49                 : 
      50                 :   /*
      51                 :    * Write uses int not size_t, so we may wrap the length and/or
      52                 :    * generate a negative value.  Only print if it matches.
      53                 :    */
      54               3 :   if ((len > 0) && (len_t == (size_t) len)) {
      55               3 :     return (ssize_t) write(2, msg, len);
      56                 :   }
      57                 : 
      58               0 :   return 0;
      59                 : }
      60                 : 
      61                 : /*
      62                 :  * Returns (via is_untrusted) whether the signal happened while
      63                 :  * executing untrusted code.  If the signal was from untrusted code,
      64                 :  * this function also returns (via result_thread) the NaClAppThread
      65                 :  * that untrusted code was running in; otherwise *result_thread is
      66                 :  * undefined.
      67                 :  *
      68                 :  * Note that this should only be called from the thread in which the
      69                 :  * signal occurred, because on x86-64 it reads a thread-local variable
      70                 :  * (nacl_thread_index).
      71                 :  */
      72                 : void NaClSignalContextGetCurrentThread(const struct NaClSignalContext *sigCtx,
      73                 :                                        int *is_untrusted,
      74               4 :                                        struct NaClAppThread **result_thread) {
      75                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
      76                 :   /* For x86-32, if %cs does not match, it is untrusted code. */
      77               4 :   *is_untrusted = (NaClGetGlobalCs() != sigCtx->cs);
      78               4 :   if (*is_untrusted) {
      79               0 :     *result_thread = nacl_thread[sigCtx->gs >> 3];
      80                 :   }
      81                 : #elif (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64) || \
      82                 :       NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
      83                 :   uint32_t current_thread_index = NaClTlsGetIdx();
      84                 :   if (NACL_TLS_INDEX_INVALID == current_thread_index) {
      85                 :     *is_untrusted = 0;
      86                 :   } else {
      87                 :     struct NaClAppThread *thread = nacl_thread[current_thread_index];
      88                 :     /*
      89                 :      * Get the address of an arbitrary local, stack-allocated variable,
      90                 :      * just for the purpose of doing a sanity check.
      91                 :      */
      92                 :     void *pointer_into_stack = &thread;
      93                 :     /*
      94                 :      * Sanity check: Make sure the stack we are running on is not
      95                 :      * allocated in untrusted memory.  This checks that the alternate
      96                 :      * signal stack is correctly set up, because otherwise, if it is
      97                 :      * not set up, the test case would not detect that.
      98                 :      *
      99                 :      * There is little point in doing a CHECK instead of a DCHECK,
     100                 :      * because if we are running off an untrusted stack, we have already
     101                 :      * lost.
     102                 :      *
     103                 :      * We do not do the check on Windows because Windows does not have
     104                 :      * an equivalent of sigaltstack() and this signal handler is
     105                 :      * insecure there.
     106                 :      */
     107                 :     if (!NACL_WINDOWS) {
     108                 :       DCHECK(!NaClIsUserAddr(thread->nap, (uintptr_t) pointer_into_stack));
     109                 :     }
     110                 :     *is_untrusted = NaClIsUserAddr(thread->nap, sigCtx->prog_ctr);
     111                 :     *result_thread = thread;
     112                 :   }
     113                 : #else
     114                 : # error Unsupported architecture
     115                 : #endif
     116               4 : }
     117                 : 
     118                 : /*
     119                 :  * Returns whether the signal happened while executing untrusted code.
     120                 :  *
     121                 :  * Like NaClSignalContextGetCurrentThread(), this should only be
     122                 :  * called from the thread in which the signal occurred.
     123                 :  */
     124               2 : int NaClSignalContextIsUntrusted(const struct NaClSignalContext *sigCtx) {
     125                 :   struct NaClAppThread *thread_unused;
     126                 :   int is_untrusted;
     127               2 :   NaClSignalContextGetCurrentThread(sigCtx, &is_untrusted, &thread_unused);
     128               2 :   return is_untrusted;
     129                 : }
     130                 : 
     131               0 : enum NaClSignalResult NaClSignalHandleNone(int signal, void *ctx) {
     132                 :   UNREFERENCED_PARAMETER(signal);
     133                 :   UNREFERENCED_PARAMETER(ctx);
     134                 : 
     135                 :   /* Don't do anything, just pass it to the OS. */
     136               0 :   return NACL_SIGNAL_SKIP;
     137                 : }
     138                 : 
     139               2 : enum NaClSignalResult NaClSignalHandleAll(int signal, void *ctx) {
     140                 :   struct NaClSignalContext sigCtx;
     141                 :   char tmp[128];
     142                 : 
     143                 :   /*
     144                 :    * Return an 8 bit error code which is -signal to
     145                 :    * simulate normal OS behavior
     146                 :    */
     147                 : 
     148               2 :   NaClSignalContextFromHandler(&sigCtx, ctx);
     149               2 :   if (NaClSignalContextIsUntrusted(&sigCtx)) {
     150               0 :     SNPRINTF(tmp, sizeof(tmp), "\n** Signal %d from untrusted code: Halting "
     151                 :              "at %" NACL_PRIXNACL_REG "h\n", signal, sigCtx.prog_ctr);
     152               0 :     NaClSignalErrorMessage(tmp);
     153               0 :     NaClExit((-signal) & 0xFF);
     154                 :   }
     155                 :   else {
     156               2 :     SNPRINTF(tmp, sizeof(tmp), "\n** Signal %d from trusted code: Halting "
     157                 :              "at %" NACL_PRIXNACL_REG "h\n", signal, sigCtx.prog_ctr);
     158               2 :     NaClSignalErrorMessage(tmp);
     159               2 :     NaClExit((-signal) & 0xFF);
     160                 :   }
     161               0 :   return NACL_SIGNAL_RETURN;
     162                 : }
     163                 : 
     164               0 : enum NaClSignalResult NaClSignalHandleUntrusted(int signal, void *ctx) {
     165                 :   struct NaClSignalContext sigCtx;
     166                 :   char tmp[128];
     167                 :   /*
     168                 :    * Return an 8 bit error code which is -signal to
     169                 :    * simulate normal OS behavior
     170                 :    */
     171               0 :   NaClSignalContextFromHandler(&sigCtx, ctx);
     172               0 :   if (NaClSignalContextIsUntrusted(&sigCtx)) {
     173               0 :     SNPRINTF(tmp, sizeof(tmp), "\n** Signal %d from untrusted code: Halting "
     174                 :              "at %" NACL_PRIXNACL_REG "h\n", signal, sigCtx.prog_ctr);
     175               0 :     NaClSignalErrorMessage(tmp);
     176               0 :     NaClExit((-signal) & 0xFF);
     177                 :   }
     178                 :   else {
     179               0 :     SNPRINTF(tmp, sizeof(tmp), "\n** Signal %d from trusted code: Continuing "
     180                 :              "from %" NACL_PRIXNACL_REG "h\n", signal, sigCtx.prog_ctr);
     181               0 :     NaClSignalErrorMessage(tmp);
     182                 :   }
     183               0 :   return NACL_SIGNAL_SEARCH;
     184                 : }
     185                 : 
     186                 : 
     187              14 : int NaClSignalHandlerAdd(NaClSignalHandler func) {
     188              14 :   int id = 0;
     189                 : 
     190              14 :   CHECK(func != NULL);
     191                 : 
     192                 :   /* If we have room... */
     193              14 :   if (s_FreeList) {
     194                 :     /* Update the free list. */
     195              14 :     struct NaClSignalNode *add = s_FreeList;
     196              14 :     s_FreeList = add->next;
     197                 : 
     198                 :     /* Construct the node. */
     199              14 :     add->func = func;
     200              14 :     add->next = s_FirstHandler;
     201                 : 
     202                 :     /* Add node to the head. */
     203              14 :     s_FirstHandler = add;
     204              14 :     id = add->id;
     205                 :   }
     206                 : 
     207              14 :   return id;
     208                 : }
     209                 : 
     210                 : 
     211               0 : int NaClSignalHandlerRemove(int id) {
     212                 :   /* The first node pointer is the first "next" pointer. */
     213               0 :   struct NaClSignalNode **ppNode = &s_FirstHandler;
     214                 : 
     215                 :   /* While the "next" pointer is valid, process what it points to. */
     216               0 :   while (*ppNode) {
     217                 :     /* If the next item has a matching ID */
     218               0 :     if ((*ppNode)->id == id) {
     219                 :       /* then we will free that item. */
     220               0 :       struct NaClSignalNode *freeNode = *ppNode;
     221                 : 
     222                 :       /* First, skip past it. */
     223               0 :       *ppNode = (*ppNode)->next;
     224                 : 
     225                 :       /* Then add this node to the head of the free list. */
     226               0 :       freeNode->next = s_FreeList;
     227               0 :       s_FreeList = freeNode;
     228               0 :       return 1;
     229                 :     }
     230               0 :     ppNode = &(*ppNode)->next;
     231                 :   }
     232                 : 
     233               0 :   return 0;
     234                 : }
     235                 : 
     236               2 : enum NaClSignalResult NaClSignalHandlerFind(int signal, void *ctx) {
     237               2 :   enum NaClSignalResult result = NACL_SIGNAL_SEARCH;
     238                 :   struct NaClSignalNode *pNode;
     239                 : 
     240                 :   /* Iterate through handlers */
     241               2 :   pNode = s_FirstHandler;
     242               4 :   while (pNode) {
     243               2 :     result = pNode->func(signal, ctx);
     244                 : 
     245                 :     /* If we are not asking for the search to continue... */
     246               0 :     if (NACL_SIGNAL_SEARCH != result) break;
     247                 : 
     248               0 :     pNode = pNode->next;
     249                 :   }
     250                 : 
     251               0 :   return result;
     252                 : }
     253                 : 
     254              14 : void NaClSignalHandlerInit() {
     255                 :   int a;
     256                 : 
     257                 :   /* Build the free list */
     258             238 :   for (a = 0; a < MAX_NACL_HANDLERS; a++) {
     259             224 :     s_SignalNodes[a].next = s_FreeList;
     260             224 :     s_SignalNodes[a].id = a + 1;
     261             224 :     s_FreeList = &s_SignalNodes[a];
     262                 :   }
     263                 : 
     264              14 :   NaClSignalHandlerInitPlatform();
     265                 : #ifdef NACL_STANDALONE
     266                 :   /* In stand-alone mode (sel_ldr) we handle all signals. */
     267              14 :   NaClSignalHandlerAdd(NaClSignalHandleAll);
     268                 : #else
     269                 :   /*
     270                 :    * When run in Chrome we handle only signals in untrusted code.
     271                 :    * Signals in trusted code are allowed to pass back to Chrome so
     272                 :    * that Breakpad can create a minidump when applicable.
     273                 :    */
     274                 :   NaClSignalHandlerAdd(NaClSignalHandleUntrusted);
     275                 : #endif
     276              14 :   if (getenv("NACL_CRASH_TEST") != NULL) {
     277               1 :     NaClSignalErrorMessage("[CRASH_TEST] Causing crash in NaCl "
     278                 :                            "trusted code...\n");
     279                 :     /*
     280                 :      * Clang transmutes a NULL pointer reference into a generic "undefined"
     281                 :      * case.  That code crashes with a different signal than an actual bad
     282                 :      * pointer reference, violating the tests' expectations.  A pointer that
     283                 :      * is known bad but is not literally NULL does not get this treatment.
     284                 :      */
     285               0 :     *(volatile int *) 1 = 0;
     286                 :   }
     287              13 : }
     288                 : 
     289              12 : void NaClSignalHandlerFini() {
     290                 :   /* We try to lock, but since we are shutting down, we ignore failures. */
     291              12 :   NaClSignalHandlerFiniPlatform();
     292              12 : }

Generated by: LCOV version 1.7