diff --git a/include/libafl/user.h b/include/libafl/user.h index db2073c328..b05139b887 100644 --- a/include/libafl/user.h +++ b/include/libafl/user.h @@ -16,10 +16,22 @@ struct libafl_mapinfo { bool is_valid; }; -extern void (*libafl_dump_core_hook)(int host_sig); +struct libafl_qemu_sig_ctx { + bool in_qemu_sig_hdlr; // we were inside qemu native signal handler + bool is_target_signal; // if we were in qemu signal handle, true -> is a + // propagated target signal; false -> is a host qemu + // signal. +}; + extern int libafl_force_dfl; -void libafl_dump_core_exec(int signal); +void libafl_qemu_native_signal_handler(int host_sig, siginfo_t* info, + void* puc); + +struct libafl_qemu_sig_ctx* libafl_qemu_signal_context(void); +void libafl_set_in_target_signal_ctx(void); +void libafl_set_in_host_signal_ctx(void); +void libafl_unset_in_signal_ctx(void); void libafl_qemu_handle_crash(int host_sig, siginfo_t* info, void* puc); diff --git a/libafl/user.c b/libafl/user.c index 0002190d53..ca6019eba6 100644 --- a/libafl/user.c +++ b/libafl/user.c @@ -4,23 +4,39 @@ #include "libafl/user.h" -void (*libafl_dump_core_hook)(int host_sig) = NULL; static struct image_info libafl_image_info; +struct libafl_qemu_sig_ctx libafl_qemu_sig_ctx = {0}; + extern abi_ulong target_brk, initial_target_brk; void host_signal_handler(int host_sig, siginfo_t* info, void* puc); -void libafl_qemu_handle_crash(int host_sig, siginfo_t* info, void* puc) +void libafl_qemu_native_signal_handler(int host_sig, siginfo_t* info, void* puc) { host_signal_handler(host_sig, info, puc); } -void libafl_dump_core_exec(int signal) +void libafl_set_in_target_signal_ctx(void) +{ + libafl_qemu_sig_ctx.in_qemu_sig_hdlr = true; + libafl_qemu_sig_ctx.is_target_signal = true; +} + +void libafl_set_in_host_signal_ctx(void) +{ + libafl_qemu_sig_ctx.in_qemu_sig_hdlr = true; + libafl_qemu_sig_ctx.is_target_signal = false; +} + +void libafl_unset_in_signal_ctx(void) +{ + libafl_qemu_sig_ctx.in_qemu_sig_hdlr = false; +} + +struct libafl_qemu_sig_ctx* libafl_qemu_signal_context(void) { - if (libafl_dump_core_hook) { - libafl_dump_core_hook(signal); - } + return &libafl_qemu_sig_ctx; } uint64_t libafl_load_addr(void) { return libafl_image_info.load_addr; } diff --git a/linux-user/signal.c b/linux-user/signal.c index c5c9cec9b8..728325ff1c 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -679,6 +679,7 @@ void force_sigsegv(int oldsig) } #endif +// called when the signal is cause by the target, and is not because of the host void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, MMUAccessType access_type, bool maperr, uintptr_t ra) { @@ -709,13 +710,18 @@ void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, cpu_loop_exit_restore(cpu, ra); } -/* abort execution with signal */ +/* abort host execution with signal */ static G_NORETURN void die_with_signal(int host_sig) { - struct sigaction act = { - .sa_handler = SIG_DFL, - }; +//// --- Start LibAFL code --- + // We don't want to give back the signal to default handler. + // Instead, LibAFL is gonna catch the signal if it has put a handler for it + // and decide what to do + + // struct sigaction act = { + // .sa_handler = SIG_DFL, + // }; /* * The proper exit code for dying from an uncaught signal is -. @@ -724,19 +730,32 @@ void die_with_signal(int host_sig) * signal. Here the default signal handler is installed, we send * the signal and we wait for it to arrive. */ - sigfillset(&act.sa_mask); - sigaction(host_sig, &act, NULL); + // sigfillset(&act.sa_mask); + // sigaction(host_sig, &act, NULL); + + // make sure signal is not blocked + sigset_t host_sig_set; + sigemptyset(&host_sig_set); + sigaddset(&host_sig_set, host_sig); + + sigprocmask(SIG_UNBLOCK, &host_sig_set, NULL); +//// --- End LibAFL code --- kill(getpid(), host_sig); /* Make sure the signal isn't masked (reusing the mask inside of act). */ - sigdelset(&act.sa_mask, host_sig); - sigsuspend(&act.sa_mask); +//// --- Start LibAFL code --- + // Unused as of now + // sigdelset(&act.sa_mask, host_sig); + // sigsuspend(&act.sa_mask); +//// --- End LibAFL code --- /* unreachable */ _exit(EXIT_FAILURE); } +// target code signal handling. +// transform target signal into host signal. static G_NORETURN void dump_core_and_abort(CPUArchState *env, int target_sig) { @@ -771,15 +790,7 @@ void dump_core_and_abort(CPUArchState *env, int target_sig) } preexit_cleanup(env, 128 + target_sig); - - //// --- Begin LibAFL code --- - - libafl_dump_core_exec(host_sig); - // die_with_signal_nodfl(host_sig); // to trigger LibAFL sig handler - - //// --- End LibAFL code --- - die_with_signal(host_sig); } @@ -814,6 +825,7 @@ static inline void rewind_if_in_safe_syscall(void *puc) } } +// QEMU handler called when a real host signal is received (and not caused by the target) static G_NORETURN void die_from_signal(siginfo_t *info) { @@ -893,12 +905,6 @@ void die_from_signal(siginfo_t *info) error_report("QEMU internal SIG%s {code=%s, addr=%p}", sig, code, info->si_addr); - //// --- Begin LibAFL code --- - - libafl_dump_core_exec(info->si_signo); - - //// --- End LibAFL code --- - die_with_signal(info->si_signo); } @@ -977,34 +983,10 @@ static uintptr_t host_sigbus_handler(CPUState *cpu, siginfo_t *info, return pc; } -//// --- Begin LibAFL code --- - -// int libafl_qemu_is_tb_protected_write(int host_sig, siginfo_t *info, -// host_sigcontext *uc); - -/* int libafl_qemu_is_tb_protected_write(int host_sig, siginfo_t *info, - host_sigcontext *uc) -{ - CPUState *cpu = thread_cpu; - uintptr_t host_addr = (uintptr_t)info->si_addr; - - bool is_valid = h2g_valid(host_addr); - abi_ptr guest_addr = h2g_nocheck(host_addr); - uintptr_t pc = host_signal_pc(uc); - bool is_write = host_signal_write(info, uc); - MMUAccessType access_type = adjust_signal_pc(&pc, is_write); - - return is_write - && is_valid - && info->si_code == SEGV_ACCERR - && handle_sigsegv_accerr_write(cpu, host_signal_mask(uc), - pc, guest_addr); -} */ - -//// --- End LibAFL code --- - //// --- Begin LibAFL code --- /* static */ +// QEMU entrypoint for signal handling. +// it will notably determine whether the incoming signal is caused by the host or the target. //// --- End LibAFL code --- void host_signal_handler(int host_sig, siginfo_t *info, void *puc) { @@ -1019,6 +1001,10 @@ void host_signal_handler(int host_sig, siginfo_t *info, void *puc) bool sync_sig = false; void *sigmask; +//// --- Start LibAFL code --- + libafl_set_in_host_signal_ctx(); +//// --- End LibAFL code --- + /* * Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special * handling wrt signal blocking and unwinding. Non-spoofed SIGILL, @@ -1029,7 +1015,10 @@ void host_signal_handler(int host_sig, siginfo_t *info, void *puc) case SIGSEGV: /* Only returns on handle_sigsegv_accerr_write success. */ host_sigsegv_handler(cpu, info, uc); - return; +//// --- Start LibAFL code --- + goto exit; + // return; +//// --- End LibAFL code --- case SIGBUS: pc = host_sigbus_handler(cpu, info, uc); sync_sig = true; @@ -1044,7 +1033,10 @@ void host_signal_handler(int host_sig, siginfo_t *info, void *puc) /* get target signal number */ guest_sig = host_to_target_signal(host_sig); if (guest_sig < 1 || guest_sig > TARGET_NSIG) { - return; +//// --- Start LibAFL code --- + goto exit; + // return; +//// --- EndLibAFL code --- } trace_user_host_signal(env, host_sig, guest_sig); @@ -1086,6 +1078,10 @@ void host_signal_handler(int host_sig, siginfo_t *info, void *puc) /* interrupt the virtual CPU as soon as possible */ cpu_exit(thread_cpu); +//// --- Start LibAFL code --- +exit: + libafl_unset_in_signal_ctx(); +//// --- End LibAFL code --- } /* do_sigaltstack() returns target values and errnos. */ @@ -1228,6 +1224,7 @@ int libafl_force_dfl = 0; //// --- End LibAFL code --- +// Pending signal during target execution static void handle_pending_signal(CPUArchState *cpu_env, int sig, struct emulated_sigtable *k) { @@ -1239,6 +1236,10 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, struct target_sigaction *sa; TaskState *ts = get_task_state(cpu); +//// --- Start LibAFL code --- + libafl_set_in_target_signal_ctx(); +//// --- End LibAFL code --- + trace_user_handle_signal(cpu_env, sig); /* dequeue signal */ k->pending = 0; @@ -1269,8 +1270,7 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, //// --- Start LibAFL code --- - if (libafl_force_dfl && (sig == SIGABRT || sig == SIGABRT|| sig == SIGSEGV - || sig == SIGILL || sig == SIGBUS)) { + if (libafl_force_dfl && (sig == SIGABRT || sig == SIGSEGV || sig == SIGILL || sig == SIGBUS)) { handler = TARGET_SIG_DFL; } @@ -1333,6 +1333,9 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, sa->_sa_handler = TARGET_SIG_DFL; } } +//// --- Start LibAFL code --- + libafl_unset_in_signal_ctx(); +//// --- End LibAFL code --- } void process_pending_signals(CPUArchState *cpu_env)