QEMU-Nyx-fork/nyx/fast_vm_reload_sync.c
Sergej Schumilo 8a88edc2a1 auto-apply clang-format
- including vl.c & kvm-all.c
2022-10-16 23:51:13 +02:00

361 lines
11 KiB
C

#include "qemu/osdep.h"
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include "exec/memory.h"
#include "qapi/error.h"
#include "qapi/qapi-types-run-state.h"
#include "qemu/main-loop.h"
#include "qemu-common.h"
#include "sysemu/kvm.h"
#include "sysemu/kvm_int.h"
#include "sysemu/runstate.h"
#include "fast_vm_reload_sync.h"
#include "nyx/debug.h"
#include "nyx/fast_vm_reload.h"
#include "nyx/kvm_nested.h"
#include "nyx/state/state.h"
extern int save_snapshot(const char *name, Error **errp);
extern int load_snapshot(const char *name, Error **errp);
static void adjust_rip(CPUX86State *env, fast_reload_t *snapshot)
{
switch (fast_reload_get_mode(snapshot)) {
case RELOAD_MEMORY_MODE_DEBUG:
case RELOAD_MEMORY_MODE_DEBUG_QUIET:
env->eip -= 1; /* out */
break;
case RELOAD_MEMORY_MODE_FDL:
case RELOAD_MEMORY_MODE_FDL_DEBUG:
env->eip -= 3; /* vmcall */
break;
case RELOAD_MEMORY_MODE_DIRTY_RING:
case RELOAD_MEMORY_MODE_DIRTY_RING_DEBUG:
env->eip -= 1; /* out */
break;
}
}
fast_vm_reload_sync_t *init_fast_vm_reload_sync(void)
{
fast_vm_reload_sync_t *self = malloc(sizeof(fast_vm_reload_sync_t));
memset(self, 0, sizeof(fast_vm_reload_sync_t));
self->request_exists = false;
self->request_exists_pre = false;
self->current_request = REQUEST_VOID;
self->debug_mode = false;
/* TODO: only RELOAD_MODE_NO_BLOCK is supported for actual fuzzing */
self->mode = RELOAD_MODE_NO_BLOCK;
return self;
}
bool fast_snapshot_exists(fast_vm_reload_sync_t *self, FastReloadRequest type)
{
assert(self->mode != RELOAD_MODE_DEBUG);
switch (type) {
case REQUEST_PRE_EXISTS:
abort();
case REQUEST_ROOT_EXISTS:
return fast_reload_root_created(get_fast_reload_snapshot());
case REQUEST_TMP_EXISTS:
return fast_reload_tmp_created(get_fast_reload_snapshot());
default:
abort();
}
}
static inline void perform_task_debug_mode(fast_vm_reload_sync_t *self,
FastReloadRequest request)
{
struct Error *errp = NULL;
switch (request) {
case REQUEST_SAVE_SNAPSHOT_PRE_FIX_RIP:
abort();
case REQUEST_SAVE_SNAPSHOT_PRE:
vm_stop(RUN_STATE_SAVE_VM);
save_snapshot("pre_root", &errp);
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
return; /* return here to skip the vm_start call */
case REQUEST_SAVE_SNAPSHOT_ROOT_FIX_RIP:
abort();
case REQUEST_SAVE_SNAPSHOT_ROOT:
vm_stop(RUN_STATE_SAVE_VM);
save_snapshot("root", &errp);
break;
case REQUEST_SAVE_SNAPSHOT_TMP_FIX_RIP:
abort();
case REQUEST_SAVE_SNAPSHOT_TMP:
vm_stop(RUN_STATE_SAVE_VM);
save_snapshot("tmp", &errp);
break;
case REQUEST_LOAD_SNAPSHOT_PRE:
/* probably never called */
abort();
break;
case REQUEST_LOAD_SNAPSHOT_ROOT:
vm_stop(RUN_STATE_RESTORE_VM);
load_snapshot("root", &errp);
break;
case REQUEST_LOAD_SNAPSHOT_TMP:
vm_stop(RUN_STATE_RESTORE_VM);
load_snapshot("tmp", &errp);
break;
default:
abort();
}
if (errp) {
error_reportf_err(errp, "Error: ");
errp = NULL;
abort();
}
vm_start();
}
static inline void create_root_snapshot(void)
{
if (GET_GLOBAL_STATE()->fast_reload_enabled) {
nyx_debug("===> GET_GLOBAL_STATE()->fast_reload_enabled: TRUE\n");
if (GET_GLOBAL_STATE()->fast_reload_mode) {
nyx_debug("===> GET_GLOBAL_STATE()->fast_reload_mode: TRUE\n");
/* we've loaded an external snapshot folder - so do nothing and don't create any new snapshot files */
} else {
nyx_debug("===> GET_GLOBAL_STATE()->fast_reload_mode: FALSE\n");
/* store the current state as a snapshot folder */
fast_reload_create_in_memory(get_fast_reload_snapshot());
fast_reload_serialize_to_file(get_fast_reload_snapshot(),
GET_GLOBAL_STATE()->fast_reload_path, false);
}
} else {
nyx_debug("===> GET_GLOBAL_STATE()->fast_reload_enabled: FALSE\n");
/* so we haven't set a path for our snapshot files - just store everything in memory */
fast_reload_create_in_memory(get_fast_reload_snapshot());
}
}
static inline void perform_task_no_block_mode(fast_vm_reload_sync_t *self,
FastReloadRequest request)
{
CPUState *cpu = qemu_get_cpu(0);
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
qemu_mutex_lock_iothread();
switch (request) {
case REQUEST_SAVE_SNAPSHOT_PRE:
vm_stop(RUN_STATE_SAVE_VM);
fast_reload_create_in_memory(get_fast_reload_snapshot());
fast_reload_serialize_to_file(get_fast_reload_snapshot(),
GET_GLOBAL_STATE()->fast_reload_pre_path, true);
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
qemu_mutex_unlock_iothread();
return; /* return here to skip the vm_start call */
case REQUEST_SAVE_SNAPSHOT_ROOT_FIX_RIP:
adjust_rip(env, get_fast_reload_snapshot());
kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE);
case REQUEST_SAVE_SNAPSHOT_ROOT:
kvm_arch_get_registers(cpu);
vm_stop(RUN_STATE_SAVE_VM);
create_root_snapshot();
fast_reload_restore(get_fast_reload_snapshot());
break;
case REQUEST_SAVE_SNAPSHOT_TMP_FIX_RIP:
adjust_rip(env, get_fast_reload_snapshot());
kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE);
case REQUEST_SAVE_SNAPSHOT_TMP:
fast_reload_create_tmp_snapshot(get_fast_reload_snapshot());
fast_reload_restore(get_fast_reload_snapshot());
break;
case REQUEST_LOAD_SNAPSHOT_PRE:
abort();
break;
case REQUEST_LOAD_SNAPSHOT_ROOT:
case REQUEST_LOAD_SNAPSHOT_TMP:
fast_reload_restore(get_fast_reload_snapshot());
break;
case REQUEST_SAVE_SNAPSHOT_ROOT_NESTED_FIX_RIP:
kvm_arch_get_registers(cpu);
adjust_rip(env, get_fast_reload_snapshot());
set_nested_rip(cpu, env->eip);
kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE);
kvm_arch_get_registers(cpu);
vm_stop(RUN_STATE_SAVE_VM);
create_root_snapshot();
fast_reload_restore(get_fast_reload_snapshot());
break;
default:
abort();
}
vm_start();
cpu_resume(cpu);
qemu_mutex_unlock_iothread();
}
static inline void perform_task_block_mode(fast_vm_reload_sync_t *self,
FastReloadRequest request)
{
switch (request) {
case REQUEST_SAVE_SNAPSHOT_PRE_FIX_RIP:
case REQUEST_SAVE_SNAPSHOT_PRE:
vm_stop(RUN_STATE_SAVE_VM);
fast_reload_create_in_memory(get_fast_reload_snapshot());
fast_reload_serialize_to_file(get_fast_reload_snapshot(),
GET_GLOBAL_STATE()->fast_reload_pre_path, true);
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
return; /* return here to skip the vm_start call */
case REQUEST_SAVE_SNAPSHOT_ROOT_FIX_RIP:
case REQUEST_SAVE_SNAPSHOT_ROOT:
/* TODO: fix this */
vm_stop(RUN_STATE_SAVE_VM);
create_root_snapshot(); /* TODO: fix this -> broken in ahci mode */
break;
case REQUEST_SAVE_SNAPSHOT_TMP_FIX_RIP:
case REQUEST_SAVE_SNAPSHOT_TMP:
vm_stop(RUN_STATE_SAVE_VM);
fast_reload_create_tmp_snapshot(get_fast_reload_snapshot());
break;
case REQUEST_LOAD_SNAPSHOT_PRE:
abort();
break;
case REQUEST_LOAD_SNAPSHOT_ROOT:
case REQUEST_LOAD_SNAPSHOT_TMP:
vm_stop(RUN_STATE_RESTORE_VM);
fast_reload_restore(get_fast_reload_snapshot());
break;
default:
abort();
}
vm_start();
}
static inline void perform_task(fast_vm_reload_sync_t *self, FastReloadRequest request)
{
switch (self->mode) {
case RELOAD_MODE_DEBUG:
abort();
perform_task_debug_mode(self, request);
break;
case RELOAD_MODE_NO_BLOCK:
perform_task_no_block_mode(self, request);
break;
case RELOAD_MODE_BLOCK:
perform_task_block_mode(self, request);
break;
}
}
void request_fast_vm_reload(fast_vm_reload_sync_t *self, FastReloadRequest request)
{
assert(!self->request_exists);
assert(self->current_request == REQUEST_VOID);
if (self->mode == RELOAD_MODE_NO_BLOCK) {
CPUState *cpu = qemu_get_cpu(0);
kvm_arch_get_registers(cpu);
// perform_task(self, request);
perform_task_no_block_mode(self, request);
} else {
self->current_request = request;
self->request_exists = true;
self->request_exists_pre = true;
}
}
bool reload_request_exists(fast_vm_reload_sync_t *self)
{
return self->request_exists_pre;
}
void reload_request_discard_tmp(fast_vm_reload_sync_t *self)
{
fast_reload_discard_tmp_snapshot(get_fast_reload_snapshot());
}
bool check_if_relood_request_exists_pre(fast_vm_reload_sync_t *self)
{
/* TODO: always returns false or abort() ? */
if (self->request_exists_pre) {
self->request_exists_pre = false;
abort();
CPUState *cpu = qemu_get_cpu(0);
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
kvm_arch_get_registers(cpu);
switch (self->current_request) {
case REQUEST_VOID:
fprintf(stderr, "%s: REQUEST_VOID requested!\n", __func__);
abort();
case REQUEST_SAVE_SNAPSHOT_PRE_FIX_RIP:
case REQUEST_SAVE_SNAPSHOT_ROOT_FIX_RIP:
case REQUEST_SAVE_SNAPSHOT_TMP_FIX_RIP:
adjust_rip(env, get_fast_reload_snapshot());
kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE);
qemu_system_vmstop_request(RUN_STATE_SAVE_VM);
break;
case REQUEST_SAVE_SNAPSHOT_PRE:
case REQUEST_SAVE_SNAPSHOT_ROOT:
case REQUEST_SAVE_SNAPSHOT_TMP:
qemu_system_vmstop_request(RUN_STATE_SAVE_VM);
break;
case REQUEST_SAVE_SNAPSHOT_ROOT_NESTED_FIX_RIP:
case REQUEST_SAVE_SNAPSHOT_TMP_NESTED_FIX_RIP:
adjust_rip(env, get_fast_reload_snapshot());
set_nested_rip(cpu, env->eip);
kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE);
qemu_system_vmstop_request(RUN_STATE_SAVE_VM);
case REQUEST_LOAD_SNAPSHOT_PRE:
case REQUEST_LOAD_SNAPSHOT_ROOT:
case REQUEST_LOAD_SNAPSHOT_TMP:
qemu_system_vmstop_request(RUN_STATE_RESTORE_VM);
break;
default:
fprintf(stderr, "%s: Unkown request: %d\n", __func__,
self->current_request);
abort();
}
return true;
}
return false;
}
bool check_if_relood_request_exists_post(fast_vm_reload_sync_t *self)
{
if (self->request_exists) {
FastReloadRequest request = self->current_request;
self->request_exists = false;
assert(self->current_request != REQUEST_VOID);
self->current_request = REQUEST_VOID;
perform_task(self, request);
return true;
}
return false;
}