Multiple fixes for systemmode (#13)

* Systemmode: handle breakpoints natively

* systemmode: buffer snapshot name

fixes a bug where the name pointer becomes stale.

* systemmode: allow synchronous snapshotting

Add a flag to take snapshots synchronosly.
This should be used to take or load snapshots while the emulator is not
running.

Co-authored-by: Alwin Berger <alwin.berger@tu-dortmund.de>
This commit is contained in:
Alwin Berger 2022-11-14 14:23:59 +01:00 committed by GitHub
parent ddb71cf438
commit 668fc28b05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 6 deletions

View File

@ -40,9 +40,11 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include <stdlib.h>
#include <string.h>
void libafl_save_qemu_snapshot(char *name); void libafl_save_qemu_snapshot(char *name, bool sync);
void libafl_load_qemu_snapshot(char *name); void libafl_load_qemu_snapshot(char *name, bool sync);
static void save_snapshot_cb(void* opaque) static void save_snapshot_cb(void* opaque)
{ {
@ -52,11 +54,26 @@ static void save_snapshot_cb(void* opaque)
error_report_err(err); error_report_err(err);
error_report("Could not save snapshot"); error_report("Could not save snapshot");
} }
free(opaque);
} }
void libafl_save_qemu_snapshot(char *name) void libafl_save_qemu_snapshot(char *name, bool sync)
{ {
aio_bh_schedule_oneshot_full(qemu_get_aio_context(), save_snapshot_cb, (void*)name, "save_snapshot"); // use snapshots synchronously, use if main loop is not running
if (sync) {
//TODO: eliminate this code duplication
//by passing a heap-allocated buffer from rust to c,
//which c needs to free
Error *err = NULL;
if(!save_snapshot(name, true, NULL, false, NULL, &err)) {
error_report_err(err);
error_report("Could not save snapshot");
}
return;
}
char* name_buffer = malloc(strlen(name)+1);
strcpy(name_buffer, name);
aio_bh_schedule_oneshot_full(qemu_get_aio_context(), save_snapshot_cb, (void*)name_buffer, "save_snapshot");
} }
static void load_snapshot_cb(void* opaque) static void load_snapshot_cb(void* opaque)
@ -76,11 +93,33 @@ static void load_snapshot_cb(void* opaque)
if (loaded && saved_vm_running) { if (loaded && saved_vm_running) {
vm_start(); vm_start();
} }
free(opaque);
} }
void libafl_load_qemu_snapshot(char *name) void libafl_load_qemu_snapshot(char *name, bool sync)
{ {
aio_bh_schedule_oneshot_full(qemu_get_aio_context(), load_snapshot_cb, (void*)name, "load_snapshot"); // use snapshots synchronously, use if main loop is not running
if (sync) {
//TODO: see libafl_save_qemu_snapshot
Error *err = NULL;
int saved_vm_running = runstate_is_running();
vm_stop(RUN_STATE_RESTORE_VM);
bool loaded = load_snapshot(name, NULL, false, NULL, &err);
if(!loaded) {
error_report_err(err);
error_report("Could not load snapshot");
}
if (loaded && saved_vm_running) {
vm_start();
}
return;
}
char* name_buffer = malloc(strlen(name)+1);
strcpy(name_buffer, name);
aio_bh_schedule_oneshot_full(qemu_get_aio_context(), load_snapshot_cb, (void*)name_buffer, "load_snapshot");
} }
#endif #endif
@ -93,12 +132,16 @@ void libafl_qemu_trigger_breakpoint(CPUState* cpu);
void libafl_qemu_trigger_breakpoint(CPUState* cpu) void libafl_qemu_trigger_breakpoint(CPUState* cpu)
{ {
#ifndef CONFIG_USER_ONLY
qemu_system_debug_request();
#else
if (cpu->running) { if (cpu->running) {
cpu->exception_index = EXCP_LIBAFL_BP; cpu->exception_index = EXCP_LIBAFL_BP;
cpu_loop_exit(cpu); cpu_loop_exit(cpu);
} else { } else {
libafl_qemu_break_asap = 1; libafl_qemu_break_asap = 1;
} }
#endif
} }
void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env) void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env)

View File

@ -670,6 +670,9 @@ static bool main_loop_should_exit(int *status)
if (qemu_debug_requested()) { if (qemu_debug_requested()) {
vm_stop(RUN_STATE_DEBUG); vm_stop(RUN_STATE_DEBUG);
//// --- Begin LibAFL code ---
return true; // exit back to fuzzing harness
//// --- End LibAFL code ---
} }
if (qemu_suspend_requested()) { if (qemu_suspend_requested()) {
qemu_system_suspend(); qemu_system_suspend();