mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 02:40:08 +00:00
libc: add limited sigaltstack support
Allocate a Genode known stack via alloc_secondary_stack and register it as alternative stack via Signal:use_alternative_stack(). The original semantic of Posix, where the caller may choose arbitary stack pointers is currently not possible. Warn about the fact. Issue #5305
This commit is contained in:
parent
0c5df0036c
commit
a798f70284
@ -136,7 +136,6 @@ DUMMY(int , -1, sched_setparam, (pid_t, const sched_param *))
|
||||
DUMMY(int , -1, sched_setscheduler, (pid_t, int, const sched_param *))
|
||||
DUMMY(int , -1, sched_yield, (void))
|
||||
DUMMY(int , -1, __semctl, (void))
|
||||
DUMMY_SILENT(int , -1, sigaltstack, (const stack_t *, stack_t *))
|
||||
DUMMY(int , -1, setegid, (uid_t))
|
||||
DUMMY(int , -1, seteuid, (uid_t))
|
||||
DUMMY(int , -1, setgid, (gid_t))
|
||||
|
@ -61,8 +61,9 @@ struct Libc::Signal : Noncopyable
|
||||
|
||||
pid_t const _local_pid;
|
||||
|
||||
void * _signal_stack { };
|
||||
jmp_buf _signal_context { };
|
||||
void * _signal_stack_default { };
|
||||
void * _signal_stack_alternative { };
|
||||
jmp_buf _signal_context { };
|
||||
|
||||
struct Signal_arguments
|
||||
{
|
||||
@ -83,24 +84,31 @@ struct Libc::Signal : Noncopyable
|
||||
|
||||
void _execute_on_signal_stack(Pending &pending)
|
||||
{
|
||||
if (!_signal_stack) {
|
||||
bool const onstack = signal_action[pending.n].sa_flags & SA_ONSTACK;
|
||||
|
||||
void * signal_stack = (_signal_stack_alternative && onstack) ?
|
||||
_signal_stack_alternative :
|
||||
_signal_stack_default;
|
||||
|
||||
if (!signal_stack) {
|
||||
auto myself = Thread::myself();
|
||||
if (myself)
|
||||
_signal_stack = { myself->alloc_secondary_stack("signal", 16 * 1024) };
|
||||
_signal_stack_default = { myself->alloc_secondary_stack("signal", 16 * 1024) };
|
||||
|
||||
signal_stack = _signal_stack_default;
|
||||
}
|
||||
|
||||
if (!_signal_stack) {
|
||||
error("signal stack allocation failed");
|
||||
if (!signal_stack) {
|
||||
error(__func__, " signal stack allocation failed");
|
||||
return;
|
||||
}
|
||||
|
||||
Signal_arguments const arg(*this, pending);
|
||||
|
||||
/* save continuation of current stack */
|
||||
if (!_setjmp(_signal_context)) {
|
||||
|
||||
Signal_arguments arg(*this, pending);
|
||||
|
||||
/* _setjmp() returned directly -> switch to signal stack */
|
||||
call_func(_signal_stack, (void *)_signal_entry, (void *)&arg);
|
||||
call_func(signal_stack, (void *)_signal_entry, (void *)&arg);
|
||||
|
||||
/* never reached */
|
||||
}
|
||||
@ -120,6 +128,9 @@ struct Libc::Signal : Noncopyable
|
||||
_count++;
|
||||
}
|
||||
|
||||
void use_alternative_stack(void *ptr) {
|
||||
_signal_stack_alternative = ptr; }
|
||||
|
||||
void execute_signal_handlers()
|
||||
{
|
||||
/*
|
||||
|
@ -229,3 +229,40 @@ extern "C" int raise(int sig)
|
||||
return Libc::Errno(EINVAL);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
extern "C" int sigaltstack(stack_t const * const ss, stack_t * const old_ss)
|
||||
{
|
||||
if (!_signal_ptr)
|
||||
return Errno(EINVAL);
|
||||
|
||||
auto &signal = *_signal_ptr;
|
||||
|
||||
if (ss) {
|
||||
auto myself = Thread::myself();
|
||||
if (!myself)
|
||||
return Errno(EINVAL);
|
||||
|
||||
if (ss->ss_flags & SS_DISABLE) {
|
||||
/* on disable use the default signal stack */
|
||||
signal.use_alternative_stack(nullptr);
|
||||
|
||||
warning("leaking secondary stack memory");
|
||||
|
||||
} else {
|
||||
if (ss->ss_sp)
|
||||
warning(__func__, " using self chosen stack is not"
|
||||
" supported - stack ptr is ignored !!!");
|
||||
|
||||
void * stack = myself->alloc_secondary_stack("sigaltstack",
|
||||
ss->ss_size);
|
||||
|
||||
signal.use_alternative_stack(stack);
|
||||
}
|
||||
}
|
||||
|
||||
if (old_ss && ss && !(ss->ss_flags & SS_DISABLE))
|
||||
old_ss->ss_flags = SS_DISABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -32,8 +32,14 @@ extern "C" {
|
||||
#include <time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#include <pthread.h>
|
||||
}
|
||||
|
||||
static void test_sigalt();
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("--- libC test ---\n");
|
||||
@ -262,5 +268,92 @@ int main(int argc, char **argv)
|
||||
puts("Check mktime: success");
|
||||
} while (0);
|
||||
|
||||
test_sigalt();
|
||||
|
||||
exit(error_count);
|
||||
}
|
||||
|
||||
|
||||
static struct State {
|
||||
sigjmp_buf reenter;
|
||||
volatile sig_atomic_t called;
|
||||
} thread_state;
|
||||
|
||||
|
||||
static void test_signal_handler(int const signal)
|
||||
{
|
||||
thread_state.called = 1;
|
||||
|
||||
void * var = nullptr;
|
||||
printf("%s stack=%p\n", __func__, &var);
|
||||
|
||||
if (!sigsetjmp(thread_state.reenter, 0)) {
|
||||
/* do something useful here */
|
||||
|
||||
/* finally jump back */
|
||||
siglongjmp(thread_state.reenter, 1);
|
||||
}
|
||||
|
||||
printf("%s done\n", __func__);
|
||||
}
|
||||
|
||||
|
||||
static void test_sigalt()
|
||||
{
|
||||
struct sigaction sa { };
|
||||
struct sigaction sa_old { };
|
||||
stack_t ss { };
|
||||
stack_t ss_old { };
|
||||
sigset_t sigs { };
|
||||
|
||||
printf("%s stack=%p\n", __func__, &sa);
|
||||
|
||||
sa.sa_handler = test_signal_handler;
|
||||
sa.sa_flags = SA_ONSTACK;
|
||||
sigfillset(&sa.sa_mask);
|
||||
|
||||
if (sigaction(SIGUSR2, &sa, &sa_old) != 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Here the contrib code provides the self allocated stack pointer,
|
||||
* which we can not support by now. Ported software needs here to be
|
||||
* patched to use the nullptr.
|
||||
* XXX to be changed if it is clear how to support better XXX
|
||||
*/
|
||||
ss.ss_sp = 0; /* <-- patch contrib code here XXX */
|
||||
ss.ss_size = 64 * 1024; /* STACK_SIZE; */
|
||||
ss.ss_flags = 0;
|
||||
if (sigaltstack(&ss, &ss_old) < 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
/* trigger SIGUSR2 */
|
||||
thread_state.called = 0;
|
||||
kill(getpid(), SIGUSR2);
|
||||
|
||||
/* wait for signal executed */
|
||||
sigfillset(&sigs);
|
||||
sigdelset (&sigs, SIGUSR2);
|
||||
while (!thread_state.called) {
|
||||
sigsuspend(&sigs);
|
||||
}
|
||||
|
||||
/* disable alternative signal test */
|
||||
sigaltstack(NULL, &ss);
|
||||
ss.ss_flags = SS_DISABLE;
|
||||
if (sigaltstack(&ss, NULL) < 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
sigaltstack(NULL, &ss);
|
||||
if (!(ss_old.ss_flags & SS_DISABLE)) {
|
||||
sigaltstack(&ss_old, NULL);
|
||||
}
|
||||
|
||||
/* restore old sigusr2 signal handler */
|
||||
sigaction(SIGUSR2, &sa_old, NULL);
|
||||
|
||||
printf("%s done\n", __func__);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user