LCOV - code coverage report
Current view: directory - src/trusted/service_runtime/posix - nacl_signal_stack.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 40 24 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 <errno.h>
       8                 : #include <signal.h>
       9                 : #include <string.h>
      10                 : #include <sys/mman.h>
      11                 : 
      12                 : #include "native_client/src/shared/platform/nacl_check.h"
      13                 : #include "native_client/src/shared/platform/nacl_log.h"
      14                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      15                 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
      16                 : 
      17                 : 
      18                 : /*
      19                 :  * NaCl uses POSIX signal handling on Linux, but not on Mac OS X.  We
      20                 :  * register a signal stack on Mac OS X anyway, though, for safety, to
      21                 :  * prevent a signal handler from running on an untrusted stack just in
      22                 :  * case a signal handler gets left registered.
      23                 :  */
      24                 : 
      25                 : /* Use 4K more than the minimum to allow breakpad to run. */
      26                 : static uint32_t g_signal_stack_size = SIGSTKSZ + 4096;
      27                 : 
      28                 : #define STACK_GUARD_SIZE NACL_PAGESIZE
      29                 : 
      30               0 : void NaClSignalStackSetSize(uint32_t size) {
      31               0 :   g_signal_stack_size = size;
      32               0 : }
      33                 : 
      34           20878 : int NaClSignalStackAllocate(void **result) {
      35                 :   /*
      36                 :    * We use mmap() to allocate the signal stack for two reasons:
      37                 :    *
      38                 :    * 1) By page-aligning the memory allocation (which malloc() does
      39                 :    * not do for small allocations), we avoid allocating any real
      40                 :    * memory in the common case in which the signal handler is never
      41                 :    * run.
      42                 :    *
      43                 :    * 2) We get to create a guard page, to guard against the unlikely
      44                 :    * occurrence of the signal handler both overrunning and doing so in
      45                 :    * an exploitable way.
      46                 :    */
      47           20878 :   uint8_t *stack = mmap(NULL, g_signal_stack_size + STACK_GUARD_SIZE,
      48                 :                         PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
      49                 :                         -1, 0);
      50           20878 :   if (stack == MAP_FAILED) {
      51               0 :     return 0;
      52                 :   }
      53                 :   /* We assume that the stack grows downwards. */
      54           20878 :   if (mprotect(stack, STACK_GUARD_SIZE, PROT_NONE) != 0) {
      55               0 :     NaClLog(LOG_FATAL, "Failed to mprotect() the stack guard page:\n\t%s\n",
      56               0 :             strerror(errno));
      57               0 :   }
      58           20878 :   *result = stack;
      59           20878 :   return 1;
      60           20878 : }
      61                 : 
      62           20694 : void NaClSignalStackFree(void *stack) {
      63           62082 :   CHECK(stack != NULL);
      64           20694 :   if (munmap(stack, g_signal_stack_size + STACK_GUARD_SIZE) != 0) {
      65               0 :     NaClLog(LOG_FATAL, "Failed to munmap() signal stack:\n\t%s\n",
      66               0 :             strerror(errno));
      67               0 :   }
      68           20694 : }
      69                 : 
      70           20878 : void NaClSignalStackRegister(void *stack) {
      71                 :   /*
      72                 :    * If we set up signal handlers, we must ensure that any thread that
      73                 :    * runs untrusted code has an alternate signal stack set up.  The
      74                 :    * default for a new thread is to use the stack pointer from the
      75                 :    * point at which the fault occurs, but it would not be safe to use
      76                 :    * untrusted code's %esp/%rsp value.
      77                 :    */
      78           20878 :   stack_t st;
      79           20878 :   st.ss_size = g_signal_stack_size;
      80           20878 :   st.ss_sp = ((uint8_t *) stack) + STACK_GUARD_SIZE;
      81           20878 :   st.ss_flags = 0;
      82           20878 :   if (sigaltstack(&st, NULL) != 0) {
      83               0 :     NaClLog(LOG_FATAL, "Failed to register signal stack:\n\t%s\n",
      84               0 :             strerror(errno));
      85               0 :   }
      86           20878 : }
      87                 : 
      88                 : void NaClSignalStackUnregister(void) {
      89                 :   /*
      90                 :    * Unregister the signal stack in case a fault occurs between the
      91                 :    * thread deallocating the signal stack and exiting.  Such a fault
      92                 :    * could be unsafe if the address space were reallocated before the
      93                 :    * fault, although that is unlikely.
      94                 :    */
      95           20694 :   stack_t st;
      96                 : #if NACL_OSX
      97                 :   /*
      98                 :    * This is a workaround for a bug in Mac OS X's libc, in which new
      99                 :    * versions of the sigaltstack() wrapper return ENOMEM if ss_size is
     100                 :    * less than MINSIGSTKSZ, even when ss_size should be ignored
     101                 :    * because we are unregistering the signal stack.
     102                 :    * See http://code.google.com/p/nativeclient/issues/detail?id=1053
     103                 :    */
     104           20694 :   st.ss_size = MINSIGSTKSZ;
     105                 : #else
     106                 :   st.ss_size = 0;
     107                 : #endif
     108           20694 :   st.ss_sp = NULL;
     109           20694 :   st.ss_flags = SS_DISABLE;
     110           20694 :   if (sigaltstack(&st, NULL) != 0) {
     111               0 :     NaClLog(LOG_FATAL, "Failed to unregister signal stack:\n\t%s\n",
     112               0 :             strerror(errno));
     113               0 :   }
     114           20694 : }

Generated by: LCOV version 1.7