Skip to content

Commit 0b9d826

Browse files
lorcrmalmain
andauthored
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>
1 parent a86bd6b commit 0b9d826

File tree

3 files changed

+23
-1
lines changed

3 files changed

+23
-1
lines changed

Diff for: accel/tcg/tcg-accel-ops-mttcg.c

+11
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ static void mttcg_force_rcu(Notifier *notify, void *data)
5656
async_run_on_cpu(cpu, do_nothing, RUN_ON_CPU_NULL);
5757
}
5858

59+
//// --- Begin LibAFL code ---
60+
61+
#include "libafl/exit.h"
62+
63+
//// --- End LibAFL code ---
64+
5965
/*
6066
* In the multi-threaded case each vCPU has its own thread. The TLS
6167
* 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)
104110
* reset by another thread by the time we arrive here.
105111
*/
106112
break;
113+
//// --- Begin LibAFL code ---
114+
case EXCP_LIBAFL_EXIT:
115+
cpu->stopped = true;
116+
break;
117+
//// --- End LibAFL code ---
107118
case EXCP_ATOMIC:
108119
bql_unlock();
109120
cpu_exec_step_atomic(cpu);

Diff for: accel/tcg/tcg-accel-ops-rr.c

+12
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ static int rr_cpu_count(void)
169169
return cpu_count;
170170
}
171171

172+
//// --- Begin LibAFL code ---
173+
174+
#include "libafl/exit.h"
175+
176+
//// --- End LibAFL code ---
177+
172178
/*
173179
* In the single-threaded case each vCPU is simulated in turn. If
174180
* 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)
273279
bql_lock();
274280
break;
275281
}
282+
//// --- Begin LibAFL code ---
283+
else if (r == EXCP_LIBAFL_EXIT) {
284+
cpu->stopped = true;
285+
break;
286+
}
287+
//// --- End LibAFL code ---
276288
} else if (cpu->stop) {
277289
if (cpu->unplug) {
278290
cpu = CPU_NEXT(cpu);

Diff for: libafl/exit.c

-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ static void prepare_qemu_exit(CPUState* cpu, target_ulong next_pc)
7878

7979
#ifndef CONFIG_USER_ONLY
8080
qemu_system_debug_request();
81-
cpu->stopped = true; // TODO check if still needed
8281
#endif
8382

8483
// in usermode, this may be called from the syscall hook, thus already out

0 commit comments

Comments
 (0)