Skip to content

Commit c4e2299

Browse files
committed
refactor signal handling
1 parent 7e0dc68 commit c4e2299

File tree

3 files changed

+84
-60
lines changed

3 files changed

+84
-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: 48 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,25 @@ 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+
//// --- End LibAFL code ---
729736

730737
kill(getpid(), host_sig);
731738

732739
/* 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);
740+
//// --- Start LibAFL code ---
741+
// Unused as of now
742+
// sigdelset(&act.sa_mask, host_sig);
743+
// sigsuspend(&act.sa_mask);
744+
//// --- End LibAFL code ---
735745

736746
/* unreachable */
737747
_exit(EXIT_FAILURE);
738748
}
739749

750+
// target code signal handling.
751+
// transform target signal into host signal.
740752
static G_NORETURN
741753
void dump_core_and_abort(CPUArchState *env, int target_sig)
742754
{
@@ -771,15 +783,7 @@ void dump_core_and_abort(CPUArchState *env, int target_sig)
771783
}
772784

773785
preexit_cleanup(env, 128 + target_sig);
774-
775-
//// --- Begin LibAFL code ---
776-
777-
libafl_dump_core_exec(host_sig);
778-
779-
// die_with_signal_nodfl(host_sig); // to trigger LibAFL sig handler
780786

781-
//// --- End LibAFL code ---
782-
783787
die_with_signal(host_sig);
784788
}
785789

@@ -814,6 +818,7 @@ static inline void rewind_if_in_safe_syscall(void *puc)
814818
}
815819
}
816820

821+
// QEMU handler called when a real host signal is received (and not caused by the target)
817822
static G_NORETURN
818823
void die_from_signal(siginfo_t *info)
819824
{
@@ -893,12 +898,6 @@ void die_from_signal(siginfo_t *info)
893898
error_report("QEMU internal SIG%s {code=%s, addr=%p}",
894899
sig, code, info->si_addr);
895900

896-
//// --- Begin LibAFL code ---
897-
898-
libafl_dump_core_exec(info->si_signo);
899-
900-
//// --- End LibAFL code ---
901-
902901
die_with_signal(info->si_signo);
903902
}
904903

@@ -977,34 +976,10 @@ static uintptr_t host_sigbus_handler(CPUState *cpu, siginfo_t *info,
977976
return pc;
978977
}
979978

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-
1006979
//// --- Begin LibAFL code ---
1007980
/* static */
981+
// QEMU entrypoint for signal handling.
982+
// it will notably determine whether the incoming signal is caused by the host or the target.
1008983
//// --- End LibAFL code ---
1009984
void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
1010985
{
@@ -1019,6 +994,10 @@ void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
1019994
bool sync_sig = false;
1020995
void *sigmask;
1021996

997+
//// --- Start LibAFL code ---
998+
libafl_set_in_host_signal_ctx();
999+
//// --- End LibAFL code ---
1000+
10221001
/*
10231002
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
10241003
* handling wrt signal blocking and unwinding. Non-spoofed SIGILL,
@@ -1029,7 +1008,10 @@ void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
10291008
case SIGSEGV:
10301009
/* Only returns on handle_sigsegv_accerr_write success. */
10311010
host_sigsegv_handler(cpu, info, uc);
1032-
return;
1011+
//// --- Start LibAFL code ---
1012+
goto exit;
1013+
// return;
1014+
//// --- End LibAFL code ---
10331015
case SIGBUS:
10341016
pc = host_sigbus_handler(cpu, info, uc);
10351017
sync_sig = true;
@@ -1044,7 +1026,10 @@ void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
10441026
/* get target signal number */
10451027
guest_sig = host_to_target_signal(host_sig);
10461028
if (guest_sig < 1 || guest_sig > TARGET_NSIG) {
1047-
return;
1029+
//// --- Start LibAFL code ---
1030+
goto exit;
1031+
// return;
1032+
//// --- EndLibAFL code ---
10481033
}
10491034
trace_user_host_signal(env, host_sig, guest_sig);
10501035

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

10871072
/* interrupt the virtual CPU as soon as possible */
10881073
cpu_exit(thread_cpu);
1074+
//// --- Start LibAFL code ---
1075+
exit:
1076+
libafl_unset_in_signal_ctx();
1077+
//// --- End LibAFL code ---
10891078
}
10901079

10911080
/* do_sigaltstack() returns target values and errnos. */
@@ -1228,6 +1217,7 @@ int libafl_force_dfl = 0;
12281217

12291218
//// --- End LibAFL code ---
12301219

1220+
// Pending signal during target execution
12311221
static void handle_pending_signal(CPUArchState *cpu_env, int sig,
12321222
struct emulated_sigtable *k)
12331223
{
@@ -1239,6 +1229,10 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
12391229
struct target_sigaction *sa;
12401230
TaskState *ts = get_task_state(cpu);
12411231

1232+
//// --- Start LibAFL code ---
1233+
libafl_set_in_target_signal_ctx();
1234+
//// --- End LibAFL code ---
1235+
12421236
trace_user_handle_signal(cpu_env, sig);
12431237
/* dequeue signal */
12441238
k->pending = 0;
@@ -1269,8 +1263,7 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
12691263

12701264
//// --- Start LibAFL code ---
12711265

1272-
if (libafl_force_dfl && (sig == SIGABRT || sig == SIGABRT|| sig == SIGSEGV
1273-
|| sig == SIGILL || sig == SIGBUS)) {
1266+
if (libafl_force_dfl && (sig == SIGABRT || sig == SIGSEGV || sig == SIGILL || sig == SIGBUS)) {
12741267
handler = TARGET_SIG_DFL;
12751268
}
12761269

@@ -1333,6 +1326,9 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
13331326
sa->_sa_handler = TARGET_SIG_DFL;
13341327
}
13351328
}
1329+
//// --- Start LibAFL code ---
1330+
libafl_unset_in_signal_ctx();
1331+
//// --- End LibAFL code ---
13361332
}
13371333

13381334
void process_pending_signals(CPUArchState *cpu_env)

0 commit comments

Comments
 (0)