Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions include/libafl/user.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
28 changes: 22 additions & 6 deletions libafl/user.c
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
107 changes: 55 additions & 52 deletions linux-user/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 -<signal>.
Expand All @@ -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)
{
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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)
{
Expand All @@ -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,
Expand All @@ -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;
Expand All @@ -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);

Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
Expand Down
Loading