diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c index d852381c60..7a1a189cdd 100644 --- a/accel/tcg/tcg-runtime.c +++ b/accel/tcg/tcg-runtime.c @@ -39,99 +39,6 @@ #include "libafl/exit.h" -#ifndef CONFIG_USER_ONLY - -#include "sysemu/runstate.h" -#include "migration/snapshot.h" -#include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/main-loop.h" -#include "hw/core/cpu.h" -#include "sysemu/hw_accel.h" -#include -#include - -void libafl_save_qemu_snapshot(char *name, bool sync); -void libafl_load_qemu_snapshot(char *name, bool sync); - -static void save_snapshot_cb(void* opaque) -{ - char* name = (char*)opaque; - Error *err = NULL; - if(!save_snapshot(name, true, NULL, false, NULL, &err)) { - error_report_err(err); - error_report("Could not save snapshot"); - } - free(opaque); -} - -void libafl_save_qemu_snapshot(char *name, bool sync) -{ - // 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) -{ - char* name = (char*)opaque; - 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(); - } - free(opaque); -} - -void libafl_load_qemu_snapshot(char *name, bool sync) -{ - // 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 - void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env, uint64_t pc) { CPUState* cpu = env_cpu(env); diff --git a/cpu-target.c b/cpu-target.c index b6233f6bd1..a6a4f73abb 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -47,139 +47,10 @@ //// --- Begin LibAFL code --- -#include "exec/gdbstub.h" - -#include "libafl/exit.h" -#include "libafl/hook.h" - -int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg); - -static __thread GByteArray *libafl_qemu_mem_buf = NULL; - -target_ulong libafl_page_from_addr(target_ulong addr); - -CPUState* libafl_qemu_get_cpu(int cpu_index); -int libafl_qemu_num_cpus(void); -CPUState* libafl_qemu_current_cpu(void); -int libafl_qemu_cpu_index(CPUState*); - -int libafl_qemu_write_reg(CPUState* cpu, int reg, uint8_t* val); -int libafl_qemu_read_reg(CPUState* cpu, int reg, uint8_t* val); -int libafl_qemu_num_regs(CPUState* cpu); - #ifndef CONFIG_USER_ONLY -hwaddr libafl_qemu_current_paging_id(CPUState* cpu); +#include "libafl/syx-snapshot/device-save.h" #endif -void libafl_flush_jit(void); - -extern int libafl_restoring_devices; - -/* -void* libafl_qemu_g2h(CPUState *cpu, target_ulong x); -target_ulong libafl_qemu_h2g(CPUState *cpu, void* x); - -void* libafl_qemu_g2h(CPUState *cpu, target_ulong x) -{ - return g2h(cpu, x); -} - -target_ulong libafl_qemu_h2g(CPUState *cpu, void* x) -{ - return h2g(cpu, x); -} -*/ - -target_ulong libafl_page_from_addr(target_ulong addr) { - return addr & TARGET_PAGE_MASK; -} - -CPUState* libafl_qemu_get_cpu(int cpu_index) -{ - CPUState *cpu; - CPU_FOREACH(cpu) { - if (cpu->cpu_index == cpu_index) - return cpu; - } - return NULL; -} - -int libafl_qemu_num_cpus(void) -{ - CPUState *cpu; - int num = 0; - CPU_FOREACH(cpu) { - num++; - } - return num; -} - -CPUState* libafl_qemu_current_cpu(void) -{ -#ifndef CONFIG_USER_ONLY - if (current_cpu == NULL) { - return libafl_last_exit_cpu(); - } -#endif - return current_cpu; -} - -int libafl_qemu_cpu_index(CPUState* cpu) -{ - if (cpu) return cpu->cpu_index; - return -1; -} - -int libafl_qemu_write_reg(CPUState* cpu, int reg, uint8_t* val) -{ - return gdb_write_register(cpu, val, reg); -} - -int libafl_qemu_read_reg(CPUState* cpu, int reg, uint8_t* val) -{ - int len; - - if (libafl_qemu_mem_buf == NULL) { - libafl_qemu_mem_buf = g_byte_array_sized_new(64); - } - - g_byte_array_set_size(libafl_qemu_mem_buf, 0); - - len = gdb_read_register(cpu, libafl_qemu_mem_buf, reg); - - if (len > 0) { - memcpy(val, libafl_qemu_mem_buf->data, len); - } - - return len; -} - -int libafl_qemu_num_regs(CPUState* cpu) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - return cc->gdb_num_core_regs; -} - -#ifndef CONFIG_USER_ONLY -hwaddr libafl_qemu_current_paging_id(CPUState* cpu) -{ - CPUClass* cc = CPU_GET_CLASS(cpu); - if (cc->sysemu_ops && cc->sysemu_ops->get_paging_id) { - return cc->sysemu_ops->get_paging_id(cpu); - } else { - return 0; - } -} -#endif - -void libafl_flush_jit(void) -{ - CPUState *cpu; - CPU_FOREACH(cpu) { - tb_flush(cpu); - } -} - //// --- End LibAFL code --- #ifndef CONFIG_USER_ONLY @@ -203,7 +74,9 @@ static int cpu_common_post_load(void *opaque, int version_id) // flushing the TBs every restore makes it really slow // TODO handle writes to X code with specific calls to tb_invalidate_phys_addr - if (!libafl_restoring_devices) tb_flush(cpu); + if (!libafl_devices_is_restoring()) { + tb_flush(cpu); + } //// --- End LibAFL code --- @@ -462,23 +335,6 @@ void list_cpus(void) cpu_list(); } -//// --- Begin LibAFL code --- -#if defined(CONFIG_USER_ONLY) -void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc) -{ - mmap_lock(); - tb_invalidate_phys_range(pc, pc + 1); - mmap_unlock(); -} -#else -void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc) -{ - // TODO invalidate only the virtual pages related to the TB - tb_flush(cpu); -} -#endif -//// --- End LibAFL code --- - /* enable or disable single step mode. EXCP_DEBUG is returned by the CPU loop after each instruction */ void cpu_single_step(CPUState *cpu, int enabled) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 0e10f53fad..2e6efe4d76 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -1648,30 +1648,6 @@ static void handle_query_thread_extra(GArray *params, void *user_ctx) gdb_put_strbuf(); } -//// --- Begin LibAFL code --- - -struct libafl_custom_gdb_cmd* libafl_qemu_gdb_cmds; - -void libafl_qemu_add_gdb_cmd(int (*callback)(void*, uint8_t*, size_t), void* data); -void libafl_qemu_add_gdb_cmd(int (*callback)(void*, uint8_t*, size_t), void* data) -{ - struct libafl_custom_gdb_cmd* c = malloc(sizeof(struct libafl_custom_gdb_cmd)); - c->callback = callback; - c->data = data; - c->next = libafl_qemu_gdb_cmds; - libafl_qemu_gdb_cmds = c; -} - -void libafl_qemu_gdb_reply(const char* buf, size_t len); -void libafl_qemu_gdb_reply(const char* buf, size_t len) -{ - g_autoptr(GString) hex_buf = g_string_new("O"); - gdb_memtohex(hex_buf, (const uint8_t *) buf, len); - gdb_put_packet(hex_buf->str); -} - -//// --- End LibAFL code --- - static void handle_query_supported(GArray *params, void *user_ctx) { CPUClass *cc; diff --git a/gdbstub/internals.h b/gdbstub/internals.h index 79148ab542..32f9f63297 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -240,16 +240,4 @@ void gdb_breakpoint_remove_all(CPUState *cs); int gdb_target_memory_rw_debug(CPUState *cs, hwaddr addr, uint8_t *buf, int len, bool is_write); -//// --- Begin LibAFL code --- - -struct libafl_custom_gdb_cmd { - int (*callback)(void*, uint8_t*, size_t); - void* data; - struct libafl_custom_gdb_cmd* next; -}; - -extern struct libafl_custom_gdb_cmd* libafl_qemu_gdb_cmds; - -//// --- End LibAFL code --- - #endif /* GDBSTUB_INTERNALS_H */ diff --git a/gdbstub/system.c b/gdbstub/system.c index 0d126569b3..de0ae3fce6 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -30,6 +30,10 @@ #include "trace.h" #include "internals.h" +//// --- Begin LibAFL code --- +#include "libafl/gdb.h" +//// --- End LibAFL code --- + /* System emulation specific state */ typedef struct { CharBackend chr; @@ -531,14 +535,7 @@ void gdb_handle_query_rcmd(GArray *params, void *ctx) //// --- Begin LibAFL code --- - struct libafl_custom_gdb_cmd** c = &libafl_qemu_gdb_cmds; - int recognized = 0; - while (*c) { - recognized |= (*c)->callback((*c)->data, gdbserver_state.mem_buf->data, gdbserver_state.mem_buf->len); - c = &(*c)->next; - } - - if (recognized) { + if (libafl_qemu_gdb_exec()) { gdb_put_packet("OK"); return; } diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c index 6ef29ecbee..d8e0f01866 100644 --- a/gdbstub/user-target.c +++ b/gdbstub/user-target.c @@ -14,6 +14,11 @@ #ifdef CONFIG_LINUX #include "linux-user/loader.h" #include "linux-user/qemu.h" + +//// --- Begin LibAFL code --- +#include "libafl/gdb.h" +//// --- End LibAFL code --- + #endif /* @@ -305,27 +310,17 @@ void gdb_handle_query_rcmd(GArray *params, void *user_ctx) g_assert(gdbserver_state.mem_buf->len == 0); len = len / 2; gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len); - - //// --- Begin LibAFL code --- - - struct libafl_custom_gdb_cmd** c = &libafl_qemu_gdb_cmds; - int recognized = 0; - while (*c) { - recognized |= (*c)->callback((*c)->data, gdbserver_state.mem_buf->data, gdbserver_state.mem_buf->len); - c = &(*c)->next; - } - if (recognized) { + if (libafl_qemu_gdb_exec()) { gdb_put_packet("OK"); } else { gdb_put_packet(""); } } +#endif //// --- End LibAFL code --- -#endif - static const char *get_filename_param(GArray *params, int i) { const char *hex_filename = get_param(params, i)->data; diff --git a/include/libafl/cpu.h b/include/libafl/cpu.h new file mode 100644 index 0000000000..856a745593 --- /dev/null +++ b/include/libafl/cpu.h @@ -0,0 +1,31 @@ +#pragma once + +#include "qemu/osdep.h" + +#ifndef CONFIG_USER_ONLY +#include "exec/memory.h" +#include "qemu/rcu.h" +#include "cpu.h" +#endif + +#ifndef CONFIG_USER_ONLY +uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write); +hwaddr libafl_qemu_current_paging_id(CPUState* cpu); +#endif + +target_ulong libafl_page_from_addr(target_ulong addr); +CPUState* libafl_qemu_get_cpu(int cpu_index); +int libafl_qemu_num_cpus(void); +CPUState* libafl_qemu_current_cpu(void); +int libafl_qemu_cpu_index(CPUState*); +int libafl_qemu_write_reg(CPUState* cpu, int reg, uint8_t* val); +int libafl_qemu_read_reg(CPUState* cpu, int reg, uint8_t* val); +int libafl_qemu_num_regs(CPUState* cpu); +void libafl_flush_jit(void); +void libafl_breakpoint_invalidate(CPUState* cpu, target_ulong pc); + +#ifdef CONFIG_USER_ONLY +int libafl_qemu_main(void); +int libafl_qemu_run(void); +void libafl_set_qemu_env(CPUArchState* env); +#endif diff --git a/include/libafl/exit.h b/include/libafl/exit.h index 55d6b8324e..839d26d9cd 100644 --- a/include/libafl/exit.h +++ b/include/libafl/exit.h @@ -12,9 +12,6 @@ struct libafl_breakpoint { struct libafl_breakpoint* next; }; -// in cpu-target.c -void libafl_breakpoint_invalidate(CPUState* cpu, target_ulong pc); - int libafl_qemu_set_breakpoint(target_ulong pc); int libafl_qemu_remove_breakpoint(target_ulong pc); void libafl_qemu_trigger_breakpoint(CPUState* cpu); diff --git a/include/libafl/gdb.h b/include/libafl/gdb.h new file mode 100644 index 0000000000..94e7debffb --- /dev/null +++ b/include/libafl/gdb.h @@ -0,0 +1,14 @@ +#pragma once + +#include "qemu/osdep.h" + +struct libafl_custom_gdb_cmd { + bool (*callback)(void*, uint8_t*, size_t); + void* data; + struct libafl_custom_gdb_cmd* next; +}; + +void libafl_qemu_add_gdb_cmd(bool (*callback)(void*, uint8_t*, size_t), + void* data); +void libafl_qemu_gdb_reply(const uint8_t* buf, size_t len); +bool libafl_qemu_gdb_exec(void); diff --git a/include/libafl/qemu_snapshot.h b/include/libafl/qemu_snapshot.h new file mode 100644 index 0000000000..b7f53a4247 --- /dev/null +++ b/include/libafl/qemu_snapshot.h @@ -0,0 +1,6 @@ +#pragma once + +#include "qemu/osdep.h" + +void libafl_save_qemu_snapshot(char* name, bool sync); +void libafl_load_qemu_snapshot(char* name, bool sync); diff --git a/include/libafl/syx-snapshot/device-save.h b/include/libafl/syx-snapshot/device-save.h index c0ec400613..275cabad7a 100644 --- a/include/libafl/syx-snapshot/device-save.h +++ b/include/libafl/syx-snapshot/device-save.h @@ -24,3 +24,5 @@ void device_restore_all(DeviceSaveState* device_save_state); void device_free_all(DeviceSaveState* dss); char** device_list_all(void); + +bool libafl_devices_is_restoring(void); diff --git a/include/libafl/user.h b/include/libafl/user.h index b7b8f6a5bd..69eba3995f 100644 --- a/include/libafl/user.h +++ b/include/libafl/user.h @@ -2,6 +2,9 @@ #include "qapi/error.h" #include "qemu/osdep.h" +#include "qemu/interval-tree.h" + +#include "exec/cpu-defs.h" struct libafl_mapinfo { target_ulong start; @@ -13,9 +16,17 @@ struct libafl_mapinfo { bool is_valid; }; +void libafl_dump_core_exec(int signal); + void libafl_qemu_handle_crash(int host_sig, siginfo_t* info, void* puc); IntervalTreeNode* libafl_maps_first(IntervalTreeRoot* map_info); IntervalTreeNode* libafl_maps_next(IntervalTreeNode* pageflags_maps_node, IntervalTreeRoot* proc_maps_node, struct libafl_mapinfo* ret); + +uint64_t libafl_load_addr(void); +struct image_info* libafl_get_image_info(void); + +uint64_t libafl_get_brk(void); +uint64_t libafl_set_brk(uint64_t new_brk); diff --git a/include/libafl/utils.h b/include/libafl/utils.h index 9bcc1f2ea6..a4dd40f8c0 100644 --- a/include/libafl/utils.h +++ b/include/libafl/utils.h @@ -1,15 +1,3 @@ #pragma once -#include "qemu/osdep.h" - -#ifndef CONFIG_USER_ONLY -#include "exec/memory.h" -#include "qemu/rcu.h" -#include "cpu.h" -#endif - uintptr_t libafl_qemu_host_page_size(void); - -#ifndef CONFIG_USER_ONLY -uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write); -#endif diff --git a/libafl/cpu.c b/libafl/cpu.c new file mode 100644 index 0000000000..55b699c45e --- /dev/null +++ b/libafl/cpu.c @@ -0,0 +1,160 @@ +#include "qemu/osdep.h" + +#ifdef CONFIG_USER_ONLY +#include "qemu.h" +#include "user-internals.h" +#endif + +#include "exec/gdbstub.h" +#include "exec/cpu-defs.h" +#include "exec/tb-flush.h" +#include "exec/exec-all.h" +#include "hw/core/sysemu-cpu-ops.h" + +#include "libafl/cpu.h" + +#include "libafl/exit.h" +#include "libafl/hook.h" + +int gdb_write_register(CPUState* cpu, uint8_t* mem_buf, int reg); + +static __thread GByteArray* libafl_qemu_mem_buf = NULL; + +#ifdef CONFIG_USER_ONLY +static __thread CPUArchState* libafl_qemu_env; +#endif + +#ifndef CONFIG_USER_ONLY +uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write) +{ + if (addr == -1) { + return NULL; + } + + hwaddr xlat; + MemoryRegion* mr; + WITH_RCU_READ_LOCK_GUARD() + { + mr = address_space_translate(cpu->as, addr, &xlat, NULL, is_write, + MEMTXATTRS_UNSPECIFIED); + } + + return qemu_map_ram_ptr(mr->ram_block, xlat); +} + +hwaddr libafl_qemu_current_paging_id(CPUState* cpu) +{ + CPUClass* cc = CPU_GET_CLASS(cpu); + if (cc->sysemu_ops && cc->sysemu_ops->get_paging_id) { + return cc->sysemu_ops->get_paging_id(cpu); + } else { + return 0; + } +} + +void libafl_breakpoint_invalidate(CPUState* cpu, target_ulong pc) +{ + // TODO invalidate only the virtual pages related to the TB + tb_flush(cpu); +} +#else +void libafl_breakpoint_invalidate(CPUState* cpu, target_ulong pc) +{ + mmap_lock(); + tb_invalidate_phys_range(pc, pc + 1); + mmap_unlock(); +} +#endif + +target_ulong libafl_page_from_addr(target_ulong addr) +{ + return addr & TARGET_PAGE_MASK; +} + +CPUState* libafl_qemu_get_cpu(int cpu_index) +{ + CPUState* cpu; + CPU_FOREACH(cpu) + { + if (cpu->cpu_index == cpu_index) + return cpu; + } + return NULL; +} + +int libafl_qemu_num_cpus(void) +{ + CPUState* cpu; + int num = 0; + CPU_FOREACH(cpu) { num++; } + return num; +} + +CPUState* libafl_qemu_current_cpu(void) +{ +#ifndef CONFIG_USER_ONLY + if (current_cpu == NULL) { + return libafl_last_exit_cpu(); + } +#endif + return current_cpu; +} + +int libafl_qemu_cpu_index(CPUState* cpu) +{ + if (cpu) + return cpu->cpu_index; + return -1; +} + +int libafl_qemu_write_reg(CPUState* cpu, int reg, uint8_t* val) +{ + return gdb_write_register(cpu, val, reg); +} + +int libafl_qemu_read_reg(CPUState* cpu, int reg, uint8_t* val) +{ + int len; + + if (libafl_qemu_mem_buf == NULL) { + libafl_qemu_mem_buf = g_byte_array_sized_new(64); + } + + g_byte_array_set_size(libafl_qemu_mem_buf, 0); + + len = gdb_read_register(cpu, libafl_qemu_mem_buf, reg); + + if (len > 0) { + memcpy(val, libafl_qemu_mem_buf->data, len); + } + + return len; +} + +int libafl_qemu_num_regs(CPUState* cpu) +{ + CPUClass* cc = CPU_GET_CLASS(cpu); + return cc->gdb_num_core_regs; +} + +void libafl_flush_jit(void) +{ + CPUState* cpu; + CPU_FOREACH(cpu) { tb_flush(cpu); } +} + +#ifdef CONFIG_USER_ONLY +__attribute__((weak)) int libafl_qemu_main(void) +{ + libafl_qemu_run(); + return 0; +} + +int libafl_qemu_run(void) +{ + cpu_loop(libafl_qemu_env); + return 1; +} + +void libafl_set_qemu_env(CPUArchState* env) { libafl_qemu_env = env; } +#endif diff --git a/libafl/exit.c b/libafl/exit.c index 52a9534d6f..921800a20d 100644 --- a/libafl/exit.c +++ b/libafl/exit.c @@ -7,6 +7,7 @@ #include "exec/translator.h" #include "cpu.h" +#include "libafl/cpu.h" #ifdef CONFIG_USER_ONLY #define THREAD_MODIFIER __thread diff --git a/libafl/gdb.c b/libafl/gdb.c new file mode 100644 index 0000000000..9745287c46 --- /dev/null +++ b/libafl/gdb.c @@ -0,0 +1,35 @@ +#include "qemu/osdep.h" +#include "libafl/gdb.h" +#include "gdbstub/internals.h" + +static struct libafl_custom_gdb_cmd* libafl_qemu_gdb_cmds; + +void libafl_qemu_add_gdb_cmd(bool (*callback)(void*, uint8_t*, size_t), + void* data) +{ + struct libafl_custom_gdb_cmd* c = + malloc(sizeof(struct libafl_custom_gdb_cmd)); + c->callback = callback; + c->data = data; + c->next = libafl_qemu_gdb_cmds; + libafl_qemu_gdb_cmds = c; +} + +void libafl_qemu_gdb_reply(const uint8_t* buf, size_t len) +{ + g_autoptr(GString) hex_buf = g_string_new("O"); + gdb_memtohex(hex_buf, buf, len); + gdb_put_packet(hex_buf->str); +} + +bool libafl_qemu_gdb_exec(void) +{ + struct libafl_custom_gdb_cmd** c = &libafl_qemu_gdb_cmds; + bool recognized = false; + while (*c) { + recognized |= (*c)->callback((*c)->data, gdbserver_state.mem_buf->data, + gdbserver_state.mem_buf->len); + c = &(*c)->next; + } + return recognized; +} diff --git a/libafl/hooks/tcg/instruction.c b/libafl/hooks/tcg/instruction.c index 1e0fdbc650..21e6fa4cbe 100644 --- a/libafl/hooks/tcg/instruction.c +++ b/libafl/hooks/tcg/instruction.c @@ -1,5 +1,7 @@ #include "libafl/hooks/tcg/instruction.h" +#include "libafl/cpu.h" + target_ulong libafl_gen_cur_pc; struct libafl_instruction_hook* libafl_qemu_instruction_hooks[LIBAFL_TABLES_SIZE]; diff --git a/libafl/hooks/thread.c b/libafl/hooks/thread.c index bc5f19e668..b58ca8b57a 100644 --- a/libafl/hooks/thread.c +++ b/libafl/hooks/thread.c @@ -1,9 +1,8 @@ #include "libafl/hooks/thread.h" +#include "libafl/cpu.h" #include -extern __thread CPUArchState* libafl_qemu_env; - struct libafl_new_thread_hook* libafl_new_thread_hooks; size_t libafl_new_thread_hooks_num = 0; @@ -27,7 +26,7 @@ size_t libafl_add_new_thread_hook(bool (*callback)(uint64_t data, bool libafl_hook_new_thread_run(CPUArchState* env) { - libafl_qemu_env = env; + libafl_set_qemu_env(env); if (libafl_new_thread_hooks) { bool continue_execution = true; diff --git a/libafl/meson.build b/libafl/meson.build index 9db973199e..3f4d2f5aad 100644 --- a/libafl/meson.build +++ b/libafl/meson.build @@ -1,8 +1,10 @@ specific_ss.add(files( + 'cpu.c', 'exit.c', 'hook.c', 'jit.c', 'utils.c', + 'gdb.c', # TCG-related hooks 'hooks/tcg/backdoor.c', @@ -17,6 +19,7 @@ specific_ss.add(files( )) specific_ss.add(when : 'CONFIG_SOFTMMU', if_true : [files( + 'qemu_snapshot.c', 'syx-snapshot/device-save.c', 'syx-snapshot/syx-snapshot.c', 'syx-snapshot/syx-cow-cache.c', @@ -24,6 +27,7 @@ specific_ss.add(when : 'CONFIG_SOFTMMU', if_true : [files( )]) specific_ss.add(when : 'CONFIG_USER_ONLY', if_true : [files( + 'user.c', 'hooks/syscall.c', 'hooks/thread.c', )]) diff --git a/libafl/qemu_snapshot.c b/libafl/qemu_snapshot.c new file mode 100644 index 0000000000..b742465fa6 --- /dev/null +++ b/libafl/qemu_snapshot.c @@ -0,0 +1,89 @@ +#include "libafl/qemu_snapshot.h" + +#include "sysemu/runstate.h" +#include "migration/snapshot.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/main-loop.h" +#include "hw/core/cpu.h" +#include "sysemu/hw_accel.h" +#include +#include + +static void save_snapshot_cb(void* opaque) +{ + char* name = (char*)opaque; + Error* err = NULL; + if (!save_snapshot(name, true, NULL, false, NULL, &err)) { + error_report_err(err); + error_report("Could not save snapshot"); + } + free(opaque); +} + +static void load_snapshot_cb(void* opaque) +{ + char* name = (char*)opaque; + 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(); + } + free(opaque); +} + +void libafl_save_qemu_snapshot(char* name, bool sync) +{ + // 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"); +} + +void libafl_load_qemu_snapshot(char* name, bool sync) +{ + // 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"); +} diff --git a/libafl/syx-snapshot/device-save.c b/libafl/syx-snapshot/device-save.c index 53140ec31d..1b12e231c0 100644 --- a/libafl/syx-snapshot/device-save.c +++ b/libafl/syx-snapshot/device-save.c @@ -11,12 +11,13 @@ #include "migration/savevm.h" -int libafl_restoring_devices; - extern SaveState savevm_state; - extern int vmstate_save(QEMUFile* f, SaveStateEntry* se, JSONWriter* vmdesc); +static bool libafl_restoring_devices = false; + +bool libafl_devices_is_restoring(void) { return libafl_restoring_devices; } + // iothread must be locked DeviceSaveState* device_save_all(void) { @@ -101,8 +102,8 @@ void device_restore_all(DeviceSaveState* dss) QEMUFile* f = qemu_file_new_input(ioc); - int save_libafl_restoring_devices = libafl_restoring_devices; - libafl_restoring_devices = 1; + bool save_libafl_restoring_devices = libafl_restoring_devices; + libafl_restoring_devices = true; qemu_load_device_state(f); diff --git a/libafl/user.c b/libafl/user.c new file mode 100644 index 0000000000..e259361b97 --- /dev/null +++ b/libafl/user.c @@ -0,0 +1,37 @@ +#include "qemu/osdep.h" +#include "qemu.h" +#include "loader.h" + +#include "libafl/user.h" + +void (*libafl_dump_core_hook)(int host_sig) = NULL; +static struct image_info libafl_image_info; + +extern abi_ulong target_brk, initial_target_brk; + +void host_signal_handler(int host_sig, siginfo_t* info, void* puc); + +void libafl_qemu_handle_crash(int host_sig, siginfo_t* info, void* puc) +{ + host_signal_handler(host_sig, info, puc); +} + +void libafl_dump_core_exec(int signal) +{ + if (libafl_dump_core_hook) { + libafl_dump_core_hook(signal); + } +} + +uint64_t libafl_load_addr(void) { return libafl_image_info.load_addr; } + +struct image_info* libafl_get_image_info(void) { return &libafl_image_info; } + +uint64_t libafl_get_brk(void) { return (uint64_t)target_brk; } + +uint64_t libafl_set_brk(uint64_t new_brk) +{ + uint64_t old_brk = (uint64_t)target_brk; + target_brk = (abi_ulong)new_brk; + return old_brk; +} diff --git a/libafl/utils.c b/libafl/utils.c index de8b06aa66..427b0a44d5 100644 --- a/libafl/utils.c +++ b/libafl/utils.c @@ -5,24 +5,3 @@ uintptr_t libafl_qemu_host_page_size(void) { return qemu_real_host_page_size(); } - -#ifndef CONFIG_USER_ONLY - -uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write) -{ - if (addr == -1) { - return NULL; - } - - hwaddr xlat; - MemoryRegion* mr; - WITH_RCU_READ_LOCK_GUARD() - { - mr = address_space_translate(cpu->as, addr, &xlat, NULL, is_write, - MEMTXATTRS_UNSPECIFIED); - } - - return qemu_map_ram_ptr(mr->ram_block, xlat); -} - -#endif diff --git a/linux-user/main.c b/linux-user/main.c index 31d14192c5..c46e7696b9 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -57,6 +57,11 @@ #include "tcg/perf.h" #include "exec/page-vary.h" +//// --- End LibAFL code --- +#include "libafl/cpu.h" +#include "libafl/user.h" +//// --- Begin LibAFL code --- + #ifdef CONFIG_SEMIHOSTING #include "semihosting/semihost.h" #endif @@ -685,45 +690,22 @@ static int parse_args(int argc, char **argv) } //// --- Begin LibAFL code --- - -uint64_t libafl_load_addr(void); -int libafl_qemu_main(void); -int libafl_qemu_run(void); - -__thread CPUArchState *libafl_qemu_env; - -struct image_info libafl_image_info; struct linux_binprm bprm; -uint64_t libafl_load_addr(void) { - return libafl_image_info.load_addr; -} - -__attribute__((weak)) int libafl_qemu_main(void) -{ - libafl_qemu_run(); - return 0; -} - -int libafl_qemu_run(void) -{ - cpu_loop(libafl_qemu_env); - return 1; -} - -//// --- End LibAFL code --- - #ifdef AS_LIB int qemu_user_init(int argc, char **argv, char **envp); int qemu_user_init(int argc, char **argv, char **envp) #else +//// --- End LibAFL code --- int main(int argc, char **argv, char **envp) +//// --- Begin LibAFL code --- #endif +//// --- End LibAFL code --- { struct target_pt_regs regs1, *regs = ®s1; //// --- Begin LibAFL code --- //struct image_info info1, *info = &info1; - struct image_info *info = &libafl_image_info; + struct image_info *info = libafl_get_image_info(); // struct linux_binprm bprm; //// --- End LibAFL code --- TaskState *ts; @@ -1076,7 +1058,7 @@ int main(int argc, char **argv, char **envp) //// --- Begin LibAFL code --- - libafl_qemu_env = env; + libafl_set_qemu_env(env); #ifndef AS_LIB return libafl_qemu_main(); diff --git a/linux-user/signal.c b/linux-user/signal.c index d3df87dd59..15a2669e96 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -34,12 +34,21 @@ #include "user/safe-syscall.h" #include "tcg/tcg.h" +//// --- Begin LibAFL code --- + +#include "libafl/user.h" + +//// --- End LibAFL code --- + /* target_siginfo_t must fit in gdbstub's siginfo save area. */ QEMU_BUILD_BUG_ON(sizeof(target_siginfo_t) > MAX_SIGINFO_LENGTH); static struct target_sigaction sigact_table[TARGET_NSIG]; -static void host_signal_handler(int host_signum, siginfo_t *info, +//// --- Begin LibAFL code --- +/* static */ +//// --- End LibAFL code --- +void host_signal_handler(int host_signum, siginfo_t *info, void *puc); /* Fallback addresses into sigtramp page. */ @@ -729,7 +738,6 @@ void die_with_signal(int host_sig) //// --- Begin LibAFL code --- -void (*libafl_dump_core_hook)(int host_sig); //// --- End LibAFL code --- @@ -770,8 +778,8 @@ void dump_core_and_abort(CPUArchState *env, int target_sig) //// --- Begin LibAFL code --- - if (libafl_dump_core_hook) libafl_dump_core_hook(host_sig); - + libafl_dump_core_exec(host_sig); + // die_with_signal_nodfl(host_sig); // to trigger LibAFL sig handler //// --- End LibAFL code --- @@ -890,9 +898,9 @@ void die_from_signal(siginfo_t *info) sig, code, info->si_addr); //// --- Begin LibAFL code --- - - if (libafl_dump_core_hook) libafl_dump_core_hook(info->si_signo); - + + libafl_dump_core_exec(info->si_signo); + //// --- End LibAFL code --- die_with_signal(info->si_signo); @@ -997,15 +1005,12 @@ static uintptr_t host_sigbus_handler(CPUState *cpu, siginfo_t *info, pc, guest_addr); } */ -#include "libafl/user.h" - -void libafl_qemu_handle_crash(int host_sig, siginfo_t *info, void *puc) { - host_signal_handler(host_sig, info, puc); -} - //// --- End LibAFL code --- -static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) +//// --- Begin LibAFL code --- +/* static */ +//// --- End LibAFL code --- +void host_signal_handler(int host_sig, siginfo_t *info, void *puc) { CPUState *cpu = thread_cpu; CPUArchState *env = cpu_env(cpu); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 82338df63c..a1479e77fe 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -805,7 +805,10 @@ static inline int host_to_target_sock_type(int host_type) return target_type; } -static abi_ulong target_brk, initial_target_brk; +//// --- Begin LibAFL code --- +/* static */ +//// --- End LibAFL code --- +abi_ulong target_brk, initial_target_brk; void target_set_brk(abi_ulong new_brk) { @@ -813,23 +816,6 @@ void target_set_brk(abi_ulong new_brk) initial_target_brk = target_brk; } -//// --- Begin LibAFL code --- - -uint64_t libafl_get_brk(void); -uint64_t libafl_set_brk(uint64_t new_brk); - -uint64_t libafl_get_brk(void) { - return (uint64_t)target_brk; -} - -uint64_t libafl_set_brk(uint64_t new_brk) { - uint64_t old_brk = (uint64_t)target_brk; - target_brk = (abi_ulong)new_brk; - return old_brk; -} - -//// --- End LibAFL code --- - /* do_brk() must return target values and target errnos. */ abi_long do_brk(abi_ulong brk_val) {