1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <errno.h> 6 #include <pthread.h> 7 #include <signal.h> 8 9 #include "components/nacl/loader/nonsfi/irt_interfaces.h" 10 #include "native_client/src/include/nacl_macros.h" 11 #include "native_client/src/shared/platform/nacl_log.h" 12 #include "native_client/src/trusted/service_runtime/nacl_exception.h" 13 #include "native_client/src/trusted/service_runtime/nacl_signal.h" 14 15 namespace nacl { 16 namespace nonsfi { 17 namespace { 18 19 // This is NonSFI version of exception handling codebase, NaCl side of 20 // things resides in: 21 // native_client/src/trusted/service_runtime/linux/nacl_signal.c 22 // native_client/src/trusted/service_runtime/sys_exception.c 23 24 // Crash signals to handle. The differences from SFI NaCl are that 25 // NonSFI NaCl does not use NACL_THREAD_SUSPEND_SIGNAL (==SIGUSR1), 26 // and SIGSYS is reserved for seccomp-bpf. 27 const int kSignals[] = { 28 SIGSTKFLT, 29 SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV, 30 // Handle SIGABRT in case someone sends it asynchronously using kill(). 31 SIGABRT 32 }; 33 34 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 35 NaClExceptionHandler signal_handler_function_pointer = NULL; 36 37 // Signal handler, responsible for calling the registered handler. 38 void SignalCatch(int sig, siginfo_t* info, void* uc) { 39 if (signal_handler_function_pointer) { 40 NaClSignalContext signal_context; 41 NaClSignalContextFromHandler(&signal_context, uc); 42 NaClExceptionFrame exception_frame; 43 NaClSignalSetUpExceptionFrame(&exception_frame, 44 &signal_context, 45 0 /* context_user_addr, 46 not useful for NonSFI NaCl. */); 47 signal_handler_function_pointer(&exception_frame.context); 48 } 49 _exit(-1); 50 } 51 52 int IrtExceptionHandler(NaClExceptionHandler handler, 53 NaClExceptionHandler* old_handler) { 54 pthread_mutex_lock(&mutex); 55 if (old_handler) 56 *old_handler = signal_handler_function_pointer; 57 signal_handler_function_pointer = handler; 58 pthread_mutex_unlock(&mutex); 59 return 0; 60 } 61 62 int IrtExceptionStack(void* stack, size_t size) { 63 // TODO(uekawa): Implement this function so that the exception stack 64 // actually gets used for running an exception handler. Currently 65 // we don't switch stack, which means we can't handle stack overflow 66 // exceptions. 67 return 0; 68 } 69 70 int IrtExceptionClearFlag(void) { 71 // TODO(uekawa): Implement clear_flag() to behave like SFI NaCl's 72 // implementation, so that a thread can handle a second exception 73 // after handling a first exception 74 return ENOSYS; 75 } 76 77 } // namespace 78 79 const struct nacl_irt_exception_handling kIrtExceptionHandling = { 80 IrtExceptionHandler, 81 IrtExceptionStack, 82 IrtExceptionClearFlag, 83 }; 84 85 void InitializeSignalHandler() { 86 struct sigaction sa; 87 unsigned int a; 88 89 memset(&sa, 0, sizeof(sa)); 90 sigemptyset(&sa.sa_mask); 91 sa.sa_sigaction = SignalCatch; 92 sa.sa_flags = SA_ONSTACK | SA_SIGINFO; 93 94 // Mask all signals we catch to prevent re-entry. 95 for (a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) { 96 sigaddset(&sa.sa_mask, kSignals[a]); 97 } 98 99 // Install all handlers. 100 for (a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) { 101 if (sigaction(kSignals[a], &sa, NULL) != 0) 102 NaClLog(LOG_FATAL, "sigaction to register signals failed.\n"); 103 } 104 } 105 106 } // namespace nonsfi 107 } // namespace nacl 108