CRASH: xstate_query_signal_handler does not return properly on 32-bit builds
Created by: alpire
What version of DynamoRIO are you using?
Master ( 5a646683)
What operating system version are you running on?
Ubuntu 16.04.3 LTS on 4.4.0-93-generic amd64 kernel
What application are you running?
#include <stdio.h>
int main() {
printf("It works\n");
return 0;
}
Is your application 32-bit or 64-bit?
32-bit
How are you running the application under DynamoRIO?
./drrun -- ./32-bit-application
(note that this happens with and without any clients)
What happens when you run with debug build?
It crashes as well and prints <ERROR: master_signal_handler with no siginfo (i#26?): tid=23649, sig=11>
What steps will reproduce the problem?
- Compile 5a646683 for 32 bit
- Run
./drrun -- ./32-bit-application
What is the expected output? What do you see instead? Is this an application crash, a DynamoRIO crash, a DynamoRIO assert, or a hang?
I expect to see It works!
printed on stdout. Instead, I see:
<Starting application /home/.../a.out (8286)>
<ERROR: master_signal_handler with no siginfo (i#26?): tid=8286, sig=11>
<Application /home/.../a.out (8286). Cannot correctly handle a received signal.>
It is a DynamoRIO crash
Additional information below.
The bug was introduced at https://github.com/DynamoRIO/dynamorio/commit/474e93b3b8798bcdc336d523425412b889d335bf. In https://github.com/DynamoRIO/dynamorio/blob/master/core/unix/signal_linux_x86.c#L548, DynamoRIO sets up a SIGILL signal handler and triggers a SIGILL to run the handler. The handler runs, but triggers a segfault after returning. You can see this happening in the syscall trace:
rt_sigaction(SIGILL, {0xf769bb35, ~[SEGV USR2], SA_STACK|SA_RESTART|SA_SIGINFO}, {SIG_DFL, [], 0}, 8) = 0
gettid() = 8327
getpid() = 8327
tgkill(8327, 8327, SIGILL) = 0
--- SIGILL {si_signo=SIGILL, si_code=SI_TKILL, si_pid=8327, si_uid=1000} ---
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xbd0} ---
The same segfault can be triggered with this reduced C program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/syscall.h>
struct kernel_sigaction {
void * k_sa_handler;
int sa_mask;
unsigned long sa_flags;
void (*sa_restorer) (void);
};
static void xstate_query_signal_handler(int sig, siginfo_t *siginfo, void *ucxt) {
printf("Helllo\n");
}
void
set_handler_sigact(struct kernel_sigaction *act, int sig, void* handler)
{
act->k_sa_handler = handler;
act->sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
memset(&act->sa_mask, 0xff, 4);
sigdelset((sigset_t*)&act->sa_mask, SIGSEGV);
sigdelset((sigset_t*)&act->sa_mask, SIGUSR2);
}
int
main(void)
{
int rc;
struct kernel_sigaction act ;
memset(&act, 0, sizeof(struct kernel_sigaction));
set_handler_sigact(&act, SIGILL, xstate_query_signal_handler);
rc = syscall(SYS_sigaction, SIGILL, &act, NULL, 4);
syscall(SYS_tgkill, getpid(), getpid(), SIGILL);
printf("It works\n");
return rc;
}
My kernel requires the SA_RESTORER
flag to be set. sa_restorer
should point to a signal trampoline code (You can see it done in libc at https://github.com/lattera/glibc/blob/master/sysdeps/unix/sysv/linux/i386/sigaction.c#L65). Note that this is done conditionally based on GLRO(dl_sysinfo_dso)
. I am not sure what an equivalent check in DynamoRIO would be, or if that check is even necessary. Adding the SA_RESTORER
flag and the sa_restorer
callbacks fixes the segfault in the above C program.