From 14f1ac497efc9f4f1fa4d92f8a720e9a0be5403e Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Fri, 8 Apr 2016 18:24:15 +0200 Subject: [PATCH] linux: improve exception-signal handling First, we use an alternate stack for signal handling now. The stack is shared among all threads of the component, which is okay as we only handle exceptions with log output and pass on to the default handler (that terminates the execution). The primary motivation for the alternate stack is the detection of SIGSEGV due to stack overflows. Also, hybrid components now handle exception signals by logging and the support for multi-threaded applications was improved. Fixes #1935 --- repos/base-linux/src/base/thread/thread_env.cc | 16 +++++++++++----- repos/base-linux/src/base/thread/thread_linux.cc | 4 ++++ repos/base-linux/src/core/thread_linux.cc | 3 +++ repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc | 9 +++++++++ .../base-linux/src/lib/syscall/linux_syscalls.h | 15 +++++++++++++-- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/repos/base-linux/src/base/thread/thread_env.cc b/repos/base-linux/src/base/thread/thread_env.cc index d1548c8ad..e4ab81641 100644 --- a/repos/base-linux/src/base/thread/thread_env.cc +++ b/repos/base-linux/src/base/thread/thread_env.cc @@ -47,7 +47,7 @@ extern "C" __attribute__((weak)) int stdout_write(char const *s) /** * Signal handler for exceptions like segmentation faults */ -static void exception_signal_handler(int signum) +void exception_signal_handler(int signum) { char const *reason = nullptr; @@ -81,6 +81,15 @@ static void exception_signal_handler(int signum) } +void lx_exception_signal_handlers() +{ + lx_sigaction(LX_SIGILL, exception_signal_handler); + lx_sigaction(LX_SIGBUS, exception_signal_handler); + lx_sigaction(LX_SIGFPE, exception_signal_handler); + lx_sigaction(LX_SIGSEGV, exception_signal_handler); +} + + /***************************** ** Startup library support ** *****************************/ @@ -98,8 +107,5 @@ void prepare_init_main_thread() */ lx_environ = (char**)&__initial_sp[3]; - lx_sigaction(LX_SIGILL, exception_signal_handler); - lx_sigaction(LX_SIGBUS, exception_signal_handler); - lx_sigaction(LX_SIGFPE, exception_signal_handler); - lx_sigaction(LX_SIGSEGV, exception_signal_handler); + lx_exception_signal_handlers(); } diff --git a/repos/base-linux/src/base/thread/thread_linux.cc b/repos/base-linux/src/base/thread/thread_linux.cc index cabb4ad4c..d2184f2ab 100644 --- a/repos/base-linux/src/base/thread/thread_linux.cc +++ b/repos/base-linux/src/base/thread/thread_linux.cc @@ -45,8 +45,12 @@ static Lock &startup_lock() static void thread_exit_signal_handler(int) { lx_exit(0); } +static char signal_stack[0x2000] __attribute__((aligned(0x1000))); + void Thread_base::_thread_start() { + lx_sigaltstack(signal_stack, sizeof(signal_stack)); + /* * Set signal handler such that canceled system calls get not * transparently retried after a signal gets received. diff --git a/repos/base-linux/src/core/thread_linux.cc b/repos/base-linux/src/core/thread_linux.cc index a30f70482..eac6cd635 100644 --- a/repos/base-linux/src/core/thread_linux.cc +++ b/repos/base-linux/src/core/thread_linux.cc @@ -26,9 +26,12 @@ using namespace Genode; static void empty_signal_handler(int) { } +static char signal_stack[0x2000] __attribute__((aligned(0x1000))); void Thread_base::_thread_start() { + lx_sigaltstack(signal_stack, sizeof(signal_stack)); + /* * Set signal handler such that canceled system calls get not transparently * retried after a signal gets received. diff --git a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc index e71ef9011..482265b2d 100644 --- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc +++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc @@ -50,8 +50,12 @@ int genode___cxa_atexit(void (*func)(void*), void *arg, void *dso) extern char **environ; extern char **lx_environ; +static char signal_stack[0x2000] __attribute__((aligned(0x1000))); + static void empty_signal_handler(int) { } +extern void lx_exception_signal_handlers(); + /* * This function must be called before any other static constructor in the Genode * application, so it gets the highest priority (lowest priority number >100) @@ -60,6 +64,9 @@ __attribute__((constructor(101))) void lx_hybrid_init() { lx_environ = environ; + lx_sigaltstack(signal_stack, sizeof(signal_stack)); + lx_exception_signal_handlers(); + /* * Set signal handler such that canceled system calls get not * transparently retried after a signal gets received. @@ -348,6 +355,8 @@ Linux_cpu_session *cpu_session(Cpu_session * cpu_session) static void adopt_thread(Native_thread::Meta_data *meta_data) { + lx_sigaltstack(signal_stack, sizeof(signal_stack)); + /* * Set signal handler such that canceled system calls get not * transparently retried after a signal gets received. diff --git a/repos/base-linux/src/lib/syscall/linux_syscalls.h b/repos/base-linux/src/lib/syscall/linux_syscalls.h index 0a8e82c8f..1e6eed991 100644 --- a/repos/base-linux/src/lib/syscall/linux_syscalls.h +++ b/repos/base-linux/src/lib/syscall/linux_syscalls.h @@ -258,10 +258,10 @@ inline int lx_sigaction(int signum, void (*handler)(int)) * when leaving the signal handler and it should call the rt_sigreturn syscall. */ enum { SA_RESTORER = 0x04000000 }; - act.flags = SA_RESTORER; + act.flags = SA_RESTORER | SA_ONSTACK; act.restorer = lx_restore_rt; #else - act.flags = 0; + act.flags = SA_ONSTACK; act.restorer = 0; #endif lx_sigemptyset(&act.mask); @@ -282,6 +282,17 @@ inline int lx_tgkill(int pid, int tid, int signal) } +/** + * Alternate signal stack (handles also SIGSEGV in a safe way) + */ +inline int lx_sigaltstack(void *signal_stack, Genode::size_t stack_size) +{ + stack_t stack { signal_stack, 0, stack_size }; + + return lx_syscall(SYS_sigaltstack, &stack, nullptr); +} + + inline int lx_create_thread(void (*entry)(), void *stack, void *arg) { int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND