LCOV - code coverage report
Current view: directory - src/trusted/service_runtime/linux - nacl_signal.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 116 96 82.8 %
Date: 2014-10-23 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 <errno.h>
       8                 : #include <signal.h>
       9                 : #include <stddef.h>
      10                 : #include <string.h>
      11                 : 
      12                 : #include "native_client/src/include/nacl_macros.h"
      13                 : #include "native_client/src/include/portability_io.h"
      14                 : #include "native_client/src/shared/platform/nacl_check.h"
      15                 : #include "native_client/src/shared/platform/nacl_exit.h"
      16                 : #include "native_client/src/shared/platform/nacl_log.h"
      17                 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
      18                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      19                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      20                 : #include "native_client/src/trusted/service_runtime/nacl_exception.h"
      21                 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
      22                 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
      23                 : #include "native_client/src/trusted/service_runtime/nacl_tls.h"
      24                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      25                 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
      26                 : #include "native_client/src/trusted/service_runtime/thread_suspension.h"
      27                 : 
      28                 : 
      29                 : /*
      30                 :  * This module is based on the Posix signal model.  See:
      31                 :  * http://www.opengroup.org/onlinepubs/009695399/functions/sigaction.html
      32                 :  */
      33                 : 
      34                 : /*
      35                 :  * The signals listed here should either be handled by NaCl (or otherwise
      36                 :  * trusted code).
      37                 :  */
      38                 : static int s_Signals[] = {
      39                 : #if NACL_ARCH(NACL_BUILD_ARCH) != NACL_mips
      40                 :   /* This signal does not exist on MIPS. */
      41                 :   SIGSTKFLT,
      42                 : #endif
      43                 :   SIGSYS, /* Used to support a seccomp-bpf sandbox. */
      44                 :   NACL_THREAD_SUSPEND_SIGNAL,
      45                 :   SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV,
      46                 :   /* Handle SIGABRT in case someone sends it asynchronously using kill(). */
      47                 :   SIGABRT
      48                 : };
      49                 : 
      50                 : static struct sigaction s_OldActions[NACL_ARRAY_SIZE_UNSAFE(s_Signals)];
      51                 : 
      52                 : static NaClSignalHandler g_handler_func;
      53                 : 
      54               2 : void NaClSignalHandlerSet(NaClSignalHandler func) {
      55               2 :   g_handler_func = func;
      56               2 : }
      57                 : 
      58                 : /*
      59                 :  * Returns, via is_untrusted, whether the signal happened while
      60                 :  * executing untrusted code.
      61                 :  *
      62                 :  * Returns, via result_thread, the NaClAppThread that untrusted code
      63                 :  * was running in.
      64                 :  *
      65                 :  * Note that this should only be called from the thread in which the
      66                 :  * signal occurred, because on x86-64 it reads a thread-local variable
      67                 :  * (nacl_current_thread).
      68                 :  */
      69          292091 : static void GetCurrentThread(const struct NaClSignalContext *sig_ctx,
      70                 :                              int *is_untrusted,
      71                 :                              struct NaClAppThread **result_thread) {
      72                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
      73                 :   /*
      74                 :    * For x86-32, if %cs does not match, it is untrusted code.
      75                 :    *
      76                 :    * Note that this check might not be valid on Mac OS X, because
      77                 :    * thread_get_state() does not return the value of NaClGetGlobalCs()
      78                 :    * for a thread suspended inside a syscall.  However, this code is
      79                 :    * not used on Mac OS X.
      80                 :    */
      81                 :   *is_untrusted = (NaClGetGlobalCs() != sig_ctx->cs);
      82                 :   *result_thread = NaClAppThreadGetFromIndex(sig_ctx->gs >> 3);
      83                 : #elif (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64) || \
      84                 :       NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm || \
      85                 :       NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
      86          292091 :   struct NaClAppThread *natp = NaClTlsGetCurrentThread();
      87          292091 :   if (natp == NULL) {
      88               1 :     *is_untrusted = 0;
      89               1 :     *result_thread = NULL;
      90                 :   } else {
      91                 :     /*
      92                 :      * Get the address of an arbitrary local, stack-allocated variable,
      93                 :      * just for the purpose of doing a sanity check.
      94                 :      */
      95          292090 :     void *pointer_into_stack = &natp;
      96                 :     /*
      97                 :      * Sanity check: Make sure the stack we are running on is not
      98                 :      * allocated in untrusted memory.  This checks that the alternate
      99                 :      * signal stack is correctly set up, because otherwise, if it is
     100                 :      * not set up, the test case would not detect that.
     101                 :      *
     102                 :      * There is little point in doing a CHECK instead of a DCHECK,
     103                 :      * because if we are running off an untrusted stack, we have already
     104                 :      * lost.
     105                 :      */
     106          292090 :     DCHECK(!NaClIsUserAddr(natp->nap, (uintptr_t) pointer_into_stack));
     107          292090 :     *is_untrusted = NaClIsUserAddr(natp->nap, sig_ctx->prog_ctr);
     108          292090 :     *result_thread = natp;
     109                 :   }
     110                 : #else
     111                 : # error Unsupported architecture
     112                 : #endif
     113                 : 
     114                 :   /*
     115                 :    * Trusted code could accidentally jump into sandbox address space,
     116                 :    * so don't rely on prog_ctr on its own for determining whether a
     117                 :    * crash comes from untrusted code.  We don't want to restore
     118                 :    * control to an untrusted exception handler if trusted code
     119                 :    * crashes.
     120                 :    */
     121          568172 :   if (*is_untrusted &&
     122          276081 :       ((*result_thread)->suspend_state & NACL_APP_THREAD_UNTRUSTED) == 0) {
     123               0 :     *is_untrusted = 0;
     124                 :   }
     125          292091 : }
     126                 : 
     127               2 : static void FindAndRunHandler(int sig, siginfo_t *info, void *uc) {
     128                 :   unsigned int a;
     129                 : 
     130                 :   /* If we need to keep searching, try the old signal handler. */
     131              20 :   for (a = 0; a < NACL_ARRAY_SIZE(s_Signals); a++) {
     132                 :     /* If we handle this signal */
     133              20 :     if (s_Signals[a] == sig) {
     134                 :       /* If this is a real sigaction pointer... */
     135               2 :       if ((s_OldActions[a].sa_flags & SA_SIGINFO) != 0) {
     136                 :         /*
     137                 :          * On Mac OS X, sigaction() can return a "struct sigaction"
     138                 :          * with SA_SIGINFO set but with a NULL sa_sigaction if no
     139                 :          * signal handler was previously registered.  This is allowed
     140                 :          * by POSIX, which does not require a struct returned by
     141                 :          * sigaction() to be intelligible.  We check for NULL here to
     142                 :          * avoid a crash.
     143                 :          */
     144               0 :         if (s_OldActions[a].sa_sigaction != NULL) {
     145                 :           /* then call the old handler. */
     146               0 :           s_OldActions[a].sa_sigaction(sig, info, uc);
     147               0 :           break;
     148                 :         }
     149                 :       } else {
     150                 :         /* otherwise check if it is a real signal pointer */
     151               2 :         if ((s_OldActions[a].sa_handler != SIG_DFL) &&
     152               0 :             (s_OldActions[a].sa_handler != SIG_IGN)) {
     153                 :           /* and call the old signal. */
     154               0 :           s_OldActions[a].sa_handler(sig);
     155               0 :           break;
     156                 :         }
     157                 :       }
     158                 :       /*
     159                 :        * We matched the signal, but didn't handle it, so we emulate
     160                 :        * the default behavior which is to exit the app with the signal
     161                 :        * number as the error code.
     162                 :        */
     163               2 :       NaClExit(-sig);
     164                 :     }
     165                 :   }
     166               0 : }
     167                 : 
     168                 : /*
     169                 :  * This function checks whether we can dispatch the signal to an
     170                 :  * untrusted exception handler.  If we can, it modifies the register
     171                 :  * state to call the handler and writes a stack frame into into
     172                 :  * untrusted address space, and returns true.  Otherwise, it returns
     173                 :  * false.
     174                 :  */
     175          266383 : static int DispatchToUntrustedHandler(struct NaClAppThread *natp,
     176                 :                                       struct NaClSignalContext *regs) {
     177          266383 :   struct NaClApp *nap = natp->nap;
     178                 :   uintptr_t frame_addr;
     179                 :   volatile struct NaClExceptionFrame *frame;
     180                 :   uint32_t new_stack_ptr;
     181                 :   uintptr_t context_user_addr;
     182                 : 
     183          266383 :   if (!NaClSignalCheckSandboxInvariants(regs, natp)) {
     184               0 :     return 0;
     185                 :   }
     186          266383 :   if (nap->exception_handler == 0) {
     187               8 :     return 0;
     188                 :   }
     189          266375 :   if (natp->exception_flag) {
     190               1 :     return 0;
     191                 :   }
     192                 : 
     193          266374 :   natp->exception_flag = 1;
     194                 : 
     195          266374 :   if (natp->exception_stack == 0) {
     196          266333 :     new_stack_ptr = regs->stack_ptr - NACL_STACK_RED_ZONE;
     197                 :   } else {
     198              41 :     new_stack_ptr = natp->exception_stack;
     199                 :   }
     200                 :   /* Allocate space for the stack frame, and ensure its alignment. */
     201          266374 :   new_stack_ptr -=
     202                 :       sizeof(struct NaClExceptionFrame) - NACL_STACK_PAD_BELOW_ALIGN;
     203          266374 :   new_stack_ptr = new_stack_ptr & ~NACL_STACK_ALIGN_MASK;
     204          266374 :   new_stack_ptr -= NACL_STACK_ARGS_SIZE;
     205          266374 :   new_stack_ptr -= NACL_STACK_PAD_BELOW_ALIGN;
     206          266374 :   frame_addr = NaClUserToSysAddrRange(nap, new_stack_ptr,
     207                 :                                       sizeof(struct NaClExceptionFrame));
     208          266374 :   if (frame_addr == kNaClBadAddress) {
     209                 :     /* We cannot write the stack frame. */
     210               0 :     return 0;
     211                 :   }
     212          266374 :   context_user_addr = new_stack_ptr + offsetof(struct NaClExceptionFrame,
     213                 :                                                context);
     214                 : 
     215          266374 :   frame = (struct NaClExceptionFrame *) frame_addr;
     216          266374 :   NaClSignalSetUpExceptionFrame(frame, regs, context_user_addr);
     217                 : 
     218                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
     219                 :   regs->prog_ctr = nap->exception_handler;
     220                 :   regs->stack_ptr = new_stack_ptr;
     221                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
     222          266374 :   regs->rdi = context_user_addr; /* Argument 1 */
     223          266374 :   regs->prog_ctr = NaClUserToSys(nap, nap->exception_handler);
     224          266374 :   regs->stack_ptr = NaClUserToSys(nap, new_stack_ptr);
     225                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
     226                 :   /*
     227                 :    * Returning from the exception handler is not possible, so to avoid
     228                 :    * any confusion that might arise from jumping to an uninitialised
     229                 :    * address, we set the return address to zero.
     230                 :    */
     231                 :   regs->lr = 0;
     232                 :   regs->r0 = context_user_addr;  /* Argument 1 */
     233                 :   regs->prog_ctr = NaClUserToSys(nap, nap->exception_handler);
     234                 :   regs->stack_ptr = NaClUserToSys(nap, new_stack_ptr);
     235                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
     236                 :   regs->return_addr = 0;
     237                 :   regs->a0 = context_user_addr;
     238                 :   regs->prog_ctr = NaClUserToSys(nap, nap->exception_handler);
     239                 :   regs->stack_ptr = NaClUserToSys(nap, new_stack_ptr);
     240                 :   /*
     241                 :    * Per Linux/MIPS convention, PIC functions assume that t9 holds
     242                 :    * the function's address on entry.
     243                 :    */
     244                 :   regs->t9 = regs->prog_ctr;
     245                 : #else
     246                 : # error Unsupported architecture
     247                 : #endif
     248                 : 
     249                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
     250          266374 :   regs->flags &= ~NACL_X86_DIRECTION_FLAG;
     251                 : #endif
     252                 : 
     253          266374 :   return 1;
     254                 : }
     255                 : 
     256          292091 : static void SignalCatch(int sig, siginfo_t *info, void *uc) {
     257                 :   struct NaClSignalContext sig_ctx;
     258                 :   int is_untrusted;
     259                 :   struct NaClAppThread *natp;
     260                 : 
     261                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
     262                 :   /*
     263                 :    * Reset the x86 direction flag.  New versions of gcc and libc
     264                 :    * assume that the direction flag is clear on entry to a function,
     265                 :    * as the x86 ABI requires.  However, untrusted code can set this
     266                 :    * flag, and versions of Linux before 2.6.25 do not clear the flag
     267                 :    * before running the signal handler, so we clear it here for safety.
     268                 :    * See http://code.google.com/p/nativeclient/issues/detail?id=1495
     269                 :    */
     270          292091 :   __asm__("cld");
     271                 : #endif
     272                 : 
     273          292091 :   NaClSignalContextFromHandler(&sig_ctx, uc);
     274          292091 :   GetCurrentThread(&sig_ctx, &is_untrusted, &natp);
     275                 : 
     276                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
     277                 :   /*
     278                 :    * On Linux, the kernel does not restore %gs when entering the
     279                 :    * signal handler, so we must do that here.  We need to do this for
     280                 :    * TLS to work and for glibc's syscall wrappers to work, because
     281                 :    * some builds of glibc fetch a syscall function pointer from the
     282                 :    * static TLS area.  There is the potential for vulnerabilities if
     283                 :    * we call glibc without restoring %gs (such as
     284                 :    * http://code.google.com/p/nativeclient/issues/detail?id=1607),
     285                 :    * although the risk is reduced because the untrusted %gs segment
     286                 :    * has an extent of only 4 bytes (see
     287                 :    * http://code.google.com/p/nativeclient/issues/detail?id=2176).
     288                 :    *
     289                 :    * Note that, in comparison, Breakpad tries to avoid using libc
     290                 :    * calls at all when a crash occurs.
     291                 :    *
     292                 :    * For comparison, on Mac OS X, the kernel *does* restore the
     293                 :    * original %gs when entering the signal handler.  On Mac, our
     294                 :    * assignment to %gs here wouldn't be necessary, but it wouldn't be
     295                 :    * harmful either.  However, this code is not currently used on Mac
     296                 :    * OS X.
     297                 :    *
     298                 :    * Both Linux and Mac OS X necessarily restore %cs, %ds, and %ss
     299                 :    * otherwise we would have a hard time handling signals generated by
     300                 :    * untrusted code at all.
     301                 :    *
     302                 :    * Note that we check natp (which is based on %gs) rather than
     303                 :    * is_untrusted (which is based on %cs) because we need to handle
     304                 :    * the case where %gs is set to the untrusted-code value but %cs is
     305                 :    * not.
     306                 :    *
     307                 :    * GCC's stack protector (-fstack-protector) will make use of %gs even before
     308                 :    * we have a chance to restore it. It is important that this function is not
     309                 :    * compiled with -fstack-protector.
     310                 :    */
     311                 :   if (natp != NULL) {
     312                 :     NaClSetGs(natp->user.trusted_gs);
     313                 :   }
     314                 : #endif
     315                 : 
     316          292091 :   if (sig != SIGINT && sig != SIGQUIT) {
     317          292091 :     if (NaClThreadSuspensionSignalHandler(sig, &sig_ctx, is_untrusted, natp)) {
     318           10099 :       NaClSignalContextToHandler(uc, &sig_ctx);
     319                 :       /* Resume untrusted code using possibly modified register state. */
     320           10099 :       return;
     321                 :     }
     322                 :   }
     323                 : 
     324          281976 :   if (is_untrusted &&
     325            9508 :       (sig == SIGSEGV || sig == SIGILL || sig == SIGFPE ||
     326                 :        (NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips && sig == SIGTRAP))) {
     327          266383 :     if (DispatchToUntrustedHandler(natp, &sig_ctx)) {
     328          266374 :       NaClSignalContextToHandler(uc, &sig_ctx);
     329                 :       /* Resume untrusted code using the modified register state. */
     330          266374 :       return;
     331                 :     }
     332                 :   }
     333                 : 
     334           15602 :   if (g_handler_func != NULL) {
     335           15591 :     g_handler_func(sig, &sig_ctx, is_untrusted);
     336           15591 :     return;
     337                 :   }
     338                 : 
     339              11 :   NaClSignalHandleUntrusted(sig, &sig_ctx, is_untrusted);
     340                 : 
     341               2 :   FindAndRunHandler(sig, info, uc);
     342                 : }
     343                 : 
     344                 : 
     345                 : /*
     346                 :  * Check that the current process has no signal handlers registered
     347                 :  * that we won't override with safe handlers.
     348                 :  *
     349                 :  * We want to discourage Chrome or libraries from registering signal
     350                 :  * handlers themselves, because those signal handlers are often not
     351                 :  * safe when triggered from untrusted code.  For background, see:
     352                 :  * http://code.google.com/p/nativeclient/issues/detail?id=1607
     353                 :  */
     354             290 : static void AssertNoOtherSignalHandlers(void) {
     355                 :   unsigned int index;
     356                 :   int signum;
     357                 :   char handled_by_nacl[NSIG];
     358                 : 
     359                 :   /* 0 is not a valid signal number. */
     360           18850 :   for (signum = 1; signum < NSIG; signum++) {
     361           18560 :     handled_by_nacl[signum] = 0;
     362                 :   }
     363            3480 :   for (index = 0; index < NACL_ARRAY_SIZE(s_Signals); index++) {
     364            3190 :     signum = s_Signals[index];
     365            3190 :     CHECK(signum > 0);
     366            3190 :     CHECK(signum < NSIG);
     367            3190 :     handled_by_nacl[signum] = 1;
     368                 :   }
     369           18850 :   for (signum = 1; signum < NSIG; signum++) {
     370                 :     struct sigaction sa;
     371                 : 
     372           18560 :     if (handled_by_nacl[signum])
     373            3190 :       continue;
     374                 : 
     375           15370 :     if (sigaction(signum, NULL, &sa) != 0) {
     376                 :       /*
     377                 :        * Don't complain if the kernel does not consider signum to be a
     378                 :        * valid signal number, which produces EINVAL.
     379                 :        */
     380             580 :       if (errno != EINVAL) {
     381               0 :         NaClLog(LOG_FATAL, "AssertNoOtherSignalHandlers: "
     382                 :                 "sigaction() call failed for signal %d: errno=%d\n",
     383               0 :                 signum, errno);
     384                 :       }
     385                 :     } else {
     386           14790 :       if ((sa.sa_flags & SA_SIGINFO) == 0) {
     387           14790 :         if (sa.sa_handler == SIG_DFL || sa.sa_handler == SIG_IGN)
     388           14790 :           continue;
     389                 :       } else {
     390                 :         /*
     391                 :          * It is not strictly legal for sa_sigaction to contain NULL
     392                 :          * or SIG_IGN, but Valgrind reports SIG_IGN for signal 64, so
     393                 :          * we allow it here.
     394                 :          */
     395               0 :         if (sa.sa_sigaction == NULL ||
     396               0 :             sa.sa_sigaction == (void (*)(int, siginfo_t *, void *)) SIG_IGN)
     397               0 :           continue;
     398                 :       }
     399               0 :       NaClLog(LOG_FATAL, "AssertNoOtherSignalHandlers: "
     400                 :               "A signal handler is registered for signal %d\n", signum);
     401                 :     }
     402                 :   }
     403             290 : }
     404                 : 
     405             290 : void NaClSignalHandlerInit(void) {
     406                 :   struct sigaction sa;
     407                 :   unsigned int a;
     408                 : 
     409                 :   /*
     410                 :    * Android adds a handler for SIGPIPE in the dynamic linker.
     411                 :    */
     412                 :   if (NACL_ANDROID)
     413                 :     CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
     414                 : 
     415             290 :   AssertNoOtherSignalHandlers();
     416                 : 
     417             290 :   memset(&sa, 0, sizeof(sa));
     418             290 :   sigemptyset(&sa.sa_mask);
     419             290 :   sa.sa_sigaction = SignalCatch;
     420             290 :   sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
     421                 : 
     422                 :   /*
     423                 :    * Mask all signals we catch to prevent re-entry.
     424                 :    *
     425                 :    * In particular, NACL_THREAD_SUSPEND_SIGNAL must be masked while we
     426                 :    * are handling a fault from untrusted code, otherwise the
     427                 :    * suspension signal will interrupt the trusted fault handler.  That
     428                 :    * would cause NaClAppThreadGetSuspendedRegisters() to report
     429                 :    * trusted-code register state rather than untrusted-code register
     430                 :    * state from the point where the fault occurred.
     431                 :    */
     432            3480 :   for (a = 0; a < NACL_ARRAY_SIZE(s_Signals); a++) {
     433            3190 :     sigaddset(&sa.sa_mask, s_Signals[a]);
     434                 :   }
     435                 : 
     436                 :   /* Install all handlers */
     437            3480 :   for (a = 0; a < NACL_ARRAY_SIZE(s_Signals); a++) {
     438            3190 :     if (sigaction(s_Signals[a], &sa, &s_OldActions[a]) != 0) {
     439               0 :       NaClLog(LOG_FATAL, "Failed to install handler for %d.\n\tERR:%s\n",
     440               0 :                           s_Signals[a], strerror(errno));
     441                 :     }
     442                 :   }
     443             290 : }
     444                 : 
     445               8 : void NaClSignalHandlerFini(void) {
     446                 :   unsigned int a;
     447                 : 
     448                 :   /* Remove all handlers */
     449              96 :   for (a = 0; a < NACL_ARRAY_SIZE(s_Signals); a++) {
     450              88 :     if (sigaction(s_Signals[a], &s_OldActions[a], NULL) != 0) {
     451               0 :       NaClLog(LOG_FATAL, "Failed to unregister handler for %d.\n\tERR:%s\n",
     452               0 :                           s_Signals[a], strerror(errno));
     453                 :     }
     454                 :   }
     455               8 : }

Generated by: LCOV version 1.7