Fix race between main thread and a vCPU thread (#102)
* afl-bridge: fix race between main thread and a vCPU thread In some cases qemu_main_loop() can exit before libafl_sync_exit_cpu() completes. This will case race between Rust code that restarts QEMU and vCPU thread that updates last_exit_reason. What I observed is libafl_exit_signal_vm_start() from a new iteration cleared last_exit_reason.cpu before libafl_sync_exit_cpu() tried to access *last_exit_reason.cpu. This caused NULL pointer dereference. Fix this by not setting cpu->exit in prepare_qemu_exit() and updating it only in rr_cpu_thread_fn() and MTTCG counterpart. This will ensure that qemu_main_loop() waits for vCPU thread to actually stop before returning control to the Rust code. Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com> --------- Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com> Co-authored-by: Romain Malmain <romain.malmain@pm.me>
This commit is contained in:
parent
a86bd6bbcb
commit
0b9d8266e4
@ -56,6 +56,12 @@ static void mttcg_force_rcu(Notifier *notify, void *data)
|
|||||||
async_run_on_cpu(cpu, do_nothing, RUN_ON_CPU_NULL);
|
async_run_on_cpu(cpu, do_nothing, RUN_ON_CPU_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
|
||||||
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the multi-threaded case each vCPU has its own thread. The TLS
|
* In the multi-threaded case each vCPU has its own thread. The TLS
|
||||||
* variable current_cpu can be used deep in the code to find the
|
* variable current_cpu can be used deep in the code to find the
|
||||||
@ -104,6 +110,11 @@ static void *mttcg_cpu_thread_fn(void *arg)
|
|||||||
* reset by another thread by the time we arrive here.
|
* reset by another thread by the time we arrive here.
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
case EXCP_LIBAFL_EXIT:
|
||||||
|
cpu->stopped = true;
|
||||||
|
break;
|
||||||
|
//// --- End LibAFL code ---
|
||||||
case EXCP_ATOMIC:
|
case EXCP_ATOMIC:
|
||||||
bql_unlock();
|
bql_unlock();
|
||||||
cpu_exec_step_atomic(cpu);
|
cpu_exec_step_atomic(cpu);
|
||||||
|
@ -169,6 +169,12 @@ static int rr_cpu_count(void)
|
|||||||
return cpu_count;
|
return cpu_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
|
||||||
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the single-threaded case each vCPU is simulated in turn. If
|
* In the single-threaded case each vCPU is simulated in turn. If
|
||||||
* there is more than a single vCPU we create a simple timer to kick
|
* there is more than a single vCPU we create a simple timer to kick
|
||||||
@ -273,6 +279,12 @@ static void *rr_cpu_thread_fn(void *arg)
|
|||||||
bql_lock();
|
bql_lock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
else if (r == EXCP_LIBAFL_EXIT) {
|
||||||
|
cpu->stopped = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//// --- End LibAFL code ---
|
||||||
} else if (cpu->stop) {
|
} else if (cpu->stop) {
|
||||||
if (cpu->unplug) {
|
if (cpu->unplug) {
|
||||||
cpu = CPU_NEXT(cpu);
|
cpu = CPU_NEXT(cpu);
|
||||||
|
@ -78,7 +78,6 @@ static void prepare_qemu_exit(CPUState* cpu, target_ulong next_pc)
|
|||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
qemu_system_debug_request();
|
qemu_system_debug_request();
|
||||||
cpu->stopped = true; // TODO check if still needed
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// in usermode, this may be called from the syscall hook, thus already out
|
// in usermode, this may be called from the syscall hook, thus already out
|
||||||
|
Loading…
x
Reference in New Issue
Block a user