Skip to content

Commit 695657e

Browse files
authored
Refactoring of signal handling (#100)
* refactor signal handling for qemu usermode
1 parent 7e0dc68 commit 695657e

File tree

3 files changed

+91
-60
lines changed

3 files changed

+91
-60
lines changed

include/libafl/user.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,22 @@ struct libafl_mapinfo {
1616
bool is_valid;
1717
};
1818

19-
extern void (*libafl_dump_core_hook)(int host_sig);
19+
struct libafl_qemu_sig_ctx {
20+
bool in_qemu_sig_hdlr; // we were inside qemu native signal handler
21+
bool is_target_signal; // if we were in qemu signal handle, true -> is a
22+
// propagated target signal; false -> is a host qemu
23+
// signal.
24+
};
25+
2026
extern int libafl_force_dfl;
2127

22-
void libafl_dump_core_exec(int signal);
28+
void libafl_qemu_native_signal_handler(int host_sig, siginfo_t* info,
29+
void* puc);
30+
31+
struct libafl_qemu_sig_ctx* libafl_qemu_signal_context(void);
32+
void libafl_set_in_target_signal_ctx(void);
33+
void libafl_set_in_host_signal_ctx(void);
34+
void libafl_unset_in_signal_ctx(void);
2335

2436
void libafl_qemu_handle_crash(int host_sig, siginfo_t* info, void* puc);
2537

libafl/user.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,39 @@
44

55
#include "libafl/user.h"
66

7-
void (*libafl_dump_core_hook)(int host_sig) = NULL;
87
static struct image_info libafl_image_info;
98

9+
struct libafl_qemu_sig_ctx libafl_qemu_sig_ctx = {0};
10+
1011
extern abi_ulong target_brk, initial_target_brk;
1112

1213
void host_signal_handler(int host_sig, siginfo_t* info, void* puc);
1314

14-
void libafl_qemu_handle_crash(int host_sig, siginfo_t* info, void* puc)
15+
void libafl_qemu_native_signal_handler(int host_sig, siginfo_t* info, void* puc)
1516
{
1617
host_signal_handler(host_sig, info, puc);
1718
}
1819

19-
void libafl_dump_core_exec(int signal)
20+
void libafl_set_in_target_signal_ctx(void)
21+
{
22+
libafl_qemu_sig_ctx.in_qemu_sig_hdlr = true;
23+
libafl_qemu_sig_ctx.is_target_signal = true;
24+
}
25+
26+
void libafl_set_in_host_signal_ctx(void)
27+
{
28+
libafl_qemu_sig_ctx.in_qemu_sig_hdlr = true;
29+
libafl_qemu_sig_ctx.is_target_signal = false;
30+
}
31+
32+
void libafl_unset_in_signal_ctx(void)
33+
{
34+
libafl_qemu_sig_ctx.in_qemu_sig_hdlr = false;
35+
}
36+
37+
struct libafl_qemu_sig_ctx* libafl_qemu_signal_context(void)
2038
{
21-
if (libafl_dump_core_hook) {
22-
libafl_dump_core_hook(signal);
23-
}
39+
return &libafl_qemu_sig_ctx;
2440
}
2541

2642
uint64_t libafl_load_addr(void) { return libafl_image_info.load_addr; }

linux-user/signal.c

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,7 @@ void force_sigsegv(int oldsig)
679679
}
680680
#endif
681681

682+
// called when the signal is cause by the target, and is not because of the host
682683
void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
683684
MMUAccessType access_type, bool maperr, uintptr_t ra)
684685
{
@@ -709,13 +710,18 @@ void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr,
709710
cpu_loop_exit_restore(cpu, ra);
710711
}
711712

712-
/* abort execution with signal */
713+
/* abort host execution with signal */
713714
static G_NORETURN
714715
void die_with_signal(int host_sig)
715716
{
716-
struct sigaction act = {
717-
.sa_handler = SIG_DFL,
718-
};
717+
//// --- Start LibAFL code ---
718+
// We don't want to give back the signal to default handler.
719+
// Instead, LibAFL is gonna catch the signal if it has put a handler for it
720+
// and decide what to do
721+
722+
// struct sigaction act = {
723+
// .sa_handler = SIG_DFL,
724+
// };
719725

720726
/*
721727
* The proper exit code for dying from an uncaught signal is -<signal>.
@@ -724,19 +730,32 @@ void die_with_signal(int host_sig)
724730
* signal. Here the default signal handler is installed, we send
725731
* the signal and we wait for it to arrive.
726732
*/
727-
sigfillset(&act.sa_mask);
728-
sigaction(host_sig, &act, NULL);
733+
// sigfillset(&act.sa_mask);
734+
// sigaction(host_sig, &act, NULL);
735+
736+
// make sure signal is not blocked
737+
sigset_t host_sig_set;
738+
sigemptyset(&host_sig_set);
739+
sigaddset(&host_sig_set, host_sig);
740+
741+
sigprocmask(SIG_UNBLOCK, &host_sig_set, NULL);
742+
//// --- End LibAFL code ---
729743

730744
kill(getpid(), host_sig);
731745

732746
/* Make sure the signal isn't masked (reusing the mask inside of act). */
733-
sigdelset(&act.sa_mask, host_sig);
734-
sigsuspend(&act.sa_mask);
747+
//// --- Start LibAFL code ---
748+
// Unused as of now
749+
// sigdelset(&act.sa_mask, host_sig);
750+
// sigsuspend(&act.sa_mask);
751+
//// --- End LibAFL code ---
735752

736753
/* unreachable */
737754
_exit(EXIT_FAILURE);
738755
}
739756

757+
// target code signal handling.
758+
// transform target signal into host signal.
740759
static G_NORETURN
741760
void dump_core_and_abort(CPUArchState *env, int target_sig)
742761
{
@@ -771,15 +790,7 @@ void dump_core_and_abort(CPUArchState *env, int target_sig)
771790
}
772791

773792
preexit_cleanup(env, 128 + target_sig);
774-
775-
//// --- Begin LibAFL code ---
776-
777-
libafl_dump_core_exec(host_sig);
778793

779-
// die_with_signal_nodfl(host_sig); // to trigger LibAFL sig handler
780-
781-
//// --- End LibAFL code ---
782-
783794
die_with_signal(host_sig);
784795
}
785796

@@ -814,6 +825,7 @@ static inline void rewind_if_in_safe_syscall(void *puc)
814825
}
815826
}
816827

828+
// QEMU handler called when a real host signal is received (and not caused by the target)
817829
static G_NORETURN
818830
void die_from_signal(siginfo_t *info)
819831
{
@@ -893,12 +905,6 @@ void die_from_signal(siginfo_t *info)
893905
error_report("QEMU internal SIG%s {code=%s, addr=%p}",
894906
sig, code, info->si_addr);
895907

896-
//// --- Begin LibAFL code ---
897-
898-
libafl_dump_core_exec(info->si_signo);
899-
900-
//// --- End LibAFL code ---
901-
902908
die_with_signal(info->si_signo);
903909
}
904910

@@ -977,34 +983,10 @@ static uintptr_t host_sigbus_handler(CPUState *cpu, siginfo_t *info,
977983
return pc;
978984
}
979985

980-
//// --- Begin LibAFL code ---
981-
982-
// int libafl_qemu_is_tb_protected_write(int host_sig, siginfo_t *info,
983-
// host_sigcontext *uc);
984-
985-
/* int libafl_qemu_is_tb_protected_write(int host_sig, siginfo_t *info,
986-
host_sigcontext *uc)
987-
{
988-
CPUState *cpu = thread_cpu;
989-
uintptr_t host_addr = (uintptr_t)info->si_addr;
990-
991-
bool is_valid = h2g_valid(host_addr);
992-
abi_ptr guest_addr = h2g_nocheck(host_addr);
993-
uintptr_t pc = host_signal_pc(uc);
994-
bool is_write = host_signal_write(info, uc);
995-
MMUAccessType access_type = adjust_signal_pc(&pc, is_write);
996-
997-
return is_write
998-
&& is_valid
999-
&& info->si_code == SEGV_ACCERR
1000-
&& handle_sigsegv_accerr_write(cpu, host_signal_mask(uc),
1001-
pc, guest_addr);
1002-
} */
1003-
1004-
//// --- End LibAFL code ---
1005-
1006986
//// --- Begin LibAFL code ---
1007987
/* static */
988+
// QEMU entrypoint for signal handling.
989+
// it will notably determine whether the incoming signal is caused by the host or the target.
1008990
//// --- End LibAFL code ---
1009991
void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
1010992
{
@@ -1019,6 +1001,10 @@ void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
10191001
bool sync_sig = false;
10201002
void *sigmask;
10211003

1004+
//// --- Start LibAFL code ---
1005+
libafl_set_in_host_signal_ctx();
1006+
//// --- End LibAFL code ---
1007+
10221008
/*
10231009
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
10241010
* 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)
10291015
case SIGSEGV:
10301016
/* Only returns on handle_sigsegv_accerr_write success. */
10311017
host_sigsegv_handler(cpu, info, uc);
1032-
return;
1018+
//// --- Start LibAFL code ---
1019+
goto exit;
1020+
// return;
1021+
//// --- End LibAFL code ---
10331022
case SIGBUS:
10341023
pc = host_sigbus_handler(cpu, info, uc);
10351024
sync_sig = true;
@@ -1044,7 +1033,10 @@ void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
10441033
/* get target signal number */
10451034
guest_sig = host_to_target_signal(host_sig);
10461035
if (guest_sig < 1 || guest_sig > TARGET_NSIG) {
1047-
return;
1036+
//// --- Start LibAFL code ---
1037+
goto exit;
1038+
// return;
1039+
//// --- EndLibAFL code ---
10481040
}
10491041
trace_user_host_signal(env, host_sig, guest_sig);
10501042

@@ -1086,6 +1078,10 @@ void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
10861078

10871079
/* interrupt the virtual CPU as soon as possible */
10881080
cpu_exit(thread_cpu);
1081+
//// --- Start LibAFL code ---
1082+
exit:
1083+
libafl_unset_in_signal_ctx();
1084+
//// --- End LibAFL code ---
10891085
}
10901086

10911087
/* do_sigaltstack() returns target values and errnos. */
@@ -1228,6 +1224,7 @@ int libafl_force_dfl = 0;
12281224

12291225
//// --- End LibAFL code ---
12301226

1227+
// Pending signal during target execution
12311228
static void handle_pending_signal(CPUArchState *cpu_env, int sig,
12321229
struct emulated_sigtable *k)
12331230
{
@@ -1239,6 +1236,10 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
12391236
struct target_sigaction *sa;
12401237
TaskState *ts = get_task_state(cpu);
12411238

1239+
//// --- Start LibAFL code ---
1240+
libafl_set_in_target_signal_ctx();
1241+
//// --- End LibAFL code ---
1242+
12421243
trace_user_handle_signal(cpu_env, sig);
12431244
/* dequeue signal */
12441245
k->pending = 0;
@@ -1269,8 +1270,7 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
12691270

12701271
//// --- Start LibAFL code ---
12711272

1272-
if (libafl_force_dfl && (sig == SIGABRT || sig == SIGABRT|| sig == SIGSEGV
1273-
|| sig == SIGILL || sig == SIGBUS)) {
1273+
if (libafl_force_dfl && (sig == SIGABRT || sig == SIGSEGV || sig == SIGILL || sig == SIGBUS)) {
12741274
handler = TARGET_SIG_DFL;
12751275
}
12761276

@@ -1333,6 +1333,9 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
13331333
sa->_sa_handler = TARGET_SIG_DFL;
13341334
}
13351335
}
1336+
//// --- Start LibAFL code ---
1337+
libafl_unset_in_signal_ctx();
1338+
//// --- End LibAFL code ---
13361339
}
13371340

13381341
void process_pending_signals(CPUArchState *cpu_env)

0 commit comments

Comments
 (0)