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