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
15namespace nacl {
16namespace nonsfi {
17namespace {
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.
27const int kSignals[] = {
28#if !defined(__mips__)
29  // This signal does not exist on MIPS.
30  SIGSTKFLT,
31#endif
32  SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV,
33  // Handle SIGABRT in case someone sends it asynchronously using kill().
34  SIGABRT
35};
36
37pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
38NaClExceptionHandler signal_handler_function_pointer = NULL;
39
40// Signal handler, responsible for calling the registered handler.
41void SignalCatch(int sig, siginfo_t* info, void* uc) {
42  if (signal_handler_function_pointer) {
43    NaClSignalContext signal_context;
44    NaClSignalContextFromHandler(&signal_context, uc);
45    NaClExceptionFrame exception_frame;
46    NaClSignalSetUpExceptionFrame(&exception_frame,
47                                  &signal_context,
48                                  0 /* context_user_addr,
49                                       not useful for NonSFI NaCl. */);
50    signal_handler_function_pointer(&exception_frame.context);
51  }
52  _exit(-1);
53}
54
55int IrtExceptionHandler(NaClExceptionHandler handler,
56                               NaClExceptionHandler* old_handler) {
57  pthread_mutex_lock(&mutex);
58  if (old_handler)
59    *old_handler = signal_handler_function_pointer;
60  signal_handler_function_pointer = handler;
61  pthread_mutex_unlock(&mutex);
62  return 0;
63}
64
65int IrtExceptionStack(void* stack, size_t size) {
66  // TODO(uekawa): Implement this function so that the exception stack
67  // actually gets used for running an exception handler.  Currently
68  // we don't switch stack, which means we can't handle stack overflow
69  // exceptions.
70  return 0;
71}
72
73int IrtExceptionClearFlag(void) {
74  // TODO(uekawa): Implement clear_flag() to behave like SFI NaCl's
75  // implementation, so that a thread can handle a second exception
76  // after handling a first exception
77  return ENOSYS;
78}
79
80}  // namespace
81
82const struct nacl_irt_exception_handling kIrtExceptionHandling = {
83  IrtExceptionHandler,
84  IrtExceptionStack,
85  IrtExceptionClearFlag,
86};
87
88void InitializeSignalHandler() {
89  struct sigaction sa;
90  unsigned int a;
91
92  memset(&sa, 0, sizeof(sa));
93  sigemptyset(&sa.sa_mask);
94  sa.sa_sigaction = SignalCatch;
95  sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
96
97  // Mask all signals we catch to prevent re-entry.
98  for (a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) {
99    sigaddset(&sa.sa_mask, kSignals[a]);
100  }
101
102  // Install all handlers.
103  for (a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) {
104    if (sigaction(kSignals[a], &sa, NULL) != 0)
105      NaClLog(LOG_FATAL, "sigaction to register signals failed.\n");
106  }
107}
108
109}  // namespace nonsfi
110}  // namespace nacl
111