diff --git a/repos/base-linux/src/base/thread/thread_env.cc b/repos/base-linux/src/base/thread/thread_env.cc index d1548c8adb..e4ab816417 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 cabb4ad4ce..d2184f2abf 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 a30f704825..eac6cd635d 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 e71ef90114..482265b2d2 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 0a8e82c8f4..1e6eed9911 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