unixint.d: unblock SIGSEGV before undoing wirte protection on envinronment

Doing it the other way around leads to race conditions, since an
unlucky interrupt arriving just after the mprotect call (but before
the the_env->disable_interrupts = 0 write) will write protect the
environment again, leading to a segfault. This is no problem if
SIGSEGV is unblocked (in which case we will just enter sigsegv_handler
again and arrive at the same point). However if SIGSEGV is blocked (and
another segfault arises) the whole process will die.
This commit is contained in:
Marius Gerbershagen 2020-04-12 19:53:50 +02:00
parent d8fbbb213e
commit 8d2b8d0ce1

View file

@ -789,17 +789,17 @@ handler_fn_prototype(sigsegv_handler, int sig, siginfo_t *info, void *aux)
if (((char*)&the_env->disable_interrupts <= (char*)info->si_addr) &&
((char*)info->si_addr < (char*)(&the_env->disable_interrupts+1)))
{
unblock_signal(the_env, sig);
mprotect(the_env, sizeof(*the_env), PROT_READ | PROT_WRITE);
the_env->disable_interrupts = 0;
unblock_signal(the_env, sig);
handle_all_queued_interrupt_safe(the_env);
return;
} else if (the_env->disable_interrupts &&
((char*)(&the_env->disable_interrupts+1) <= (char*)info->si_addr) &&
((char*)info->si_addr < (char*)(the_env+1))) {
unblock_signal(the_env, sig);
mprotect(the_env, sizeof(*the_env), PROT_READ | PROT_WRITE);
the_env->disable_interrupts = 0;
unblock_signal(the_env, sig);
ecl_unrecoverable_error(the_env, interrupt_msg);
return;
}