From d7ddc83fa9db57cd32ffd8b2200688d3728926ef Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Wed, 22 Jun 2016 16:14:18 +0200 Subject: [PATCH] linux: place alternate signal stack in stack area The alternate stack must use the stack area as, e.g., Thread::myself() depends on this property. Hybrid components do not depend on this property and, therefore, use a static stack buffer. Fixes #1935 --- repos/base-linux/src/core/platform.cc | 4 ++-- repos/base-linux/src/core/thread_linux.cc | 12 +++++++++--- repos/base-linux/src/lib/base/thread_env.cc | 11 ++++++----- repos/base-linux/src/lib/base/thread_linux.cc | 16 +++++++++------- repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc | 6 +++--- .../base-linux/src/lib/syscall/linux_syscalls.h | 10 +++++++--- 6 files changed, 36 insertions(+), 23 deletions(-) diff --git a/repos/base-linux/src/core/platform.cc b/repos/base-linux/src/core/platform.cc index 566699e121..13199bd510 100644 --- a/repos/base-linux/src/core/platform.cc +++ b/repos/base-linux/src/core/platform.cc @@ -90,10 +90,10 @@ Platform::Platform() : _core_mem_alloc(nullptr) { /* catch control-c */ - lx_sigaction(LX_SIGINT, sigint_handler); + lx_sigaction(LX_SIGINT, sigint_handler, false); /* catch SIGCHLD */ - lx_sigaction(LX_SIGCHLD, sigchld_handler); + lx_sigaction(LX_SIGCHLD, sigchld_handler, false); /* create resource directory under /tmp */ lx_mkdir(resource_path(), S_IRWXU); diff --git a/repos/base-linux/src/core/thread_linux.cc b/repos/base-linux/src/core/thread_linux.cc index f0478b5b93..79939e921c 100644 --- a/repos/base-linux/src/core/thread_linux.cc +++ b/repos/base-linux/src/core/thread_linux.cc @@ -17,6 +17,7 @@ /* base-internal includes */ #include +#include /* Linux syscall bindings */ #include @@ -26,17 +27,22 @@ using namespace Genode; static void empty_signal_handler(int) { } -static char signal_stack[0x2000] __attribute__((aligned(0x1000))); void Thread::_thread_start() { - lx_sigaltstack(signal_stack, sizeof(signal_stack)); + Thread * const thread = Thread::myself(); + + /* use primary stack as alternate stack for fatal signals (exceptions) */ + void *stack_base = (void *)thread->_stack->base(); + size_t stack_size = thread->_stack->top() - thread->_stack->base(); + + lx_sigaltstack(stack_base, stack_size); /* * Set signal handler such that canceled system calls get not transparently * retried after a signal gets received. */ - lx_sigaction(LX_SIGUSR1, empty_signal_handler); + lx_sigaction(LX_SIGUSR1, empty_signal_handler, false); /* * Deliver SIGCHLD signals to no thread other than the main thread. Core's diff --git a/repos/base-linux/src/lib/base/thread_env.cc b/repos/base-linux/src/lib/base/thread_env.cc index 44cee672c5..113865b9db 100644 --- a/repos/base-linux/src/lib/base/thread_env.cc +++ b/repos/base-linux/src/lib/base/thread_env.cc @@ -78,17 +78,18 @@ void exception_signal_handler(int signum) * We reset the signal handler to SIG_DFL and trigger exception again, * i.e., terminate the process. */ - lx_sigaction(signum, nullptr); + lx_sigaction(signum, nullptr, false); return; } 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); + /* use alternate stack in fatal-signal handlers */ + lx_sigaction(LX_SIGILL, exception_signal_handler, true); + lx_sigaction(LX_SIGBUS, exception_signal_handler, true); + lx_sigaction(LX_SIGFPE, exception_signal_handler, true); + lx_sigaction(LX_SIGSEGV, exception_signal_handler, true); } diff --git a/repos/base-linux/src/lib/base/thread_linux.cc b/repos/base-linux/src/lib/base/thread_linux.cc index 06be634fd6..17c074fde3 100644 --- a/repos/base-linux/src/lib/base/thread_linux.cc +++ b/repos/base-linux/src/lib/base/thread_linux.cc @@ -46,19 +46,21 @@ static Lock &startup_lock() static void thread_exit_signal_handler(int) { lx_exit(0); } -static char signal_stack[0x2000] __attribute__((aligned(0x1000))); - void Thread::_thread_start() { - lx_sigaltstack(signal_stack, sizeof(signal_stack)); + Thread * const thread = Thread::myself(); + + /* use primary stack as alternate stack for fatal signals (exceptions) */ + void *stack_base = (void *)thread->_stack->base(); + size_t stack_size = thread->_stack->top() - thread->_stack->base(); + + lx_sigaltstack(stack_base, stack_size); /* * Set signal handler such that canceled system calls get not * transparently retried after a signal gets received. */ - lx_sigaction(LX_SIGUSR1, empty_signal_handler); - - Thread * const thread = Thread::myself(); + lx_sigaction(LX_SIGUSR1, empty_signal_handler, false); /* inform core about the new thread and process ID of the new thread */ Linux_native_cpu_client native_cpu(thread->_cpu_session->native_cpu()); @@ -141,7 +143,7 @@ void Thread::start() */ static bool threadlib_initialized = false; if (!threadlib_initialized) { - lx_sigaction(LX_SIGCANCEL, thread_exit_signal_handler); + lx_sigaction(LX_SIGCANCEL, thread_exit_signal_handler, false); threadlib_initialized = true; } 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 a3ddd54a18..df99981049 100644 --- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc +++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc @@ -71,7 +71,7 @@ __attribute__((constructor(101))) void lx_hybrid_init() * Set signal handler such that canceled system calls get not * transparently retried after a signal gets received. */ - lx_sigaction(LX_SIGUSR1, empty_signal_handler); + lx_sigaction(LX_SIGUSR1, empty_signal_handler, false); } namespace Genode { @@ -345,12 +345,12 @@ static void adopt_thread(Native_thread::Meta_data *meta_data) * Set signal handler such that canceled system calls get not * transparently retried after a signal gets received. */ - lx_sigaction(LX_SIGUSR1, empty_signal_handler); + lx_sigaction(LX_SIGUSR1, empty_signal_handler, false); /* * Prevent children from becoming zombies. (SIG_IGN = 1) */ - lx_sigaction(LX_SIGCHLD, (void (*)(int))1); + lx_sigaction(LX_SIGCHLD, (void (*)(int))1, false); /* assign 'Native_thread::Meta_data' pointer to TLS entry */ pthread_setspecific(tls_key(), meta_data); diff --git a/repos/base-linux/src/lib/syscall/linux_syscalls.h b/repos/base-linux/src/lib/syscall/linux_syscalls.h index 2c0fb6d5be..a22f2bb4a0 100644 --- a/repos/base-linux/src/lib/syscall/linux_syscalls.h +++ b/repos/base-linux/src/lib/syscall/linux_syscalls.h @@ -245,7 +245,7 @@ extern "C" void lx_restore_rt (void); /** * Simplified binding for sigaction system call */ -inline int lx_sigaction(int signum, void (*handler)(int)) +inline int lx_sigaction(int signum, void (*handler)(int), bool altstack) { struct kernel_sigaction act; act.handler = handler; @@ -258,12 +258,16 @@ 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 | SA_ONSTACK; + act.flags = SA_RESTORER; act.restorer = lx_restore_rt; #else - act.flags = SA_ONSTACK; + act.flags = 0; act.restorer = 0; #endif + + /* use alternate signal stack if requested */ + act.flags |= altstack ? SA_ONSTACK : 0; + lx_sigemptyset(&act.mask); return lx_syscall(SYS_rt_sigaction, signum, &act, 0UL, _NSIG/8);