From 86d38fbfa7e632b3a4a14def14a11b9b9ba1642d Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Tue, 13 Aug 2024 16:56:00 +0200 Subject: [PATCH] Add pre/post cpu_run hooks + Refactoring (#82) * Add cpu_run pre/post exec hooks, to hook the cpu just before / after it runs target code. * Refactor hooks to separate them in different files * Remove most extern variables * Reduce the amount of extra code in QEMU * Add clang-format script --- accel/kvm/kvm-all.c | 18 + accel/tcg/translate-all.c | 61 +- accel/tcg/translator.c | 45 +- include/libafl/exit.h | 15 +- include/libafl/hook.h | 254 ++----- include/libafl/hooks/cpu_run.h | 36 + include/libafl/hooks/syscall.h | 76 ++ include/libafl/hooks/tcg/backdoor.h | 38 + include/libafl/hooks/tcg/block.h | 43 ++ include/libafl/hooks/tcg/cmp.h | 39 + include/libafl/hooks/tcg/edge.h | 48 ++ include/libafl/hooks/tcg/instruction.h | 43 ++ include/libafl/hooks/tcg/read_write.h | 60 ++ include/libafl/hooks/thread.h | 31 + include/libafl/syx-misc.h | 14 +- .../syx-snapshot/channel-buffer-writeback.h | 15 +- include/libafl/syx-snapshot/device-save.h | 2 +- include/libafl/syx-snapshot/syx-cow-cache.h | 18 +- include/libafl/syx-snapshot/syx-snapshot.h | 53 +- include/libafl/user.h | 10 +- libafl/.clang-format | 9 + libafl/exit.c | 44 +- libafl/hook.c | 693 +----------------- libafl/hooks/cpu_run.c | 41 ++ libafl/hooks/syscall.c | 89 +++ libafl/hooks/tcg/backdoor.c | 47 ++ libafl/hooks/tcg/block.c | 89 +++ libafl/hooks/tcg/cmp.c | 129 ++++ libafl/hooks/tcg/edge.c | 89 +++ libafl/hooks/tcg/instruction.c | 133 ++++ libafl/hooks/tcg/read_write.c | 240 ++++++ libafl/hooks/thread.c | 47 ++ libafl/jit.c | 27 +- libafl/meson.build | 38 +- .../syx-snapshot/channel-buffer-writeback.c | 170 +++-- libafl/syx-snapshot/device-save.c | 85 ++- libafl/syx-snapshot/syx-cow-cache.c | 129 ++-- libafl/syx-snapshot/syx-snapshot.c | 498 ++++++++----- libafl/utils.c | 10 +- linux-user/signal.c | 3 +- linux-user/syscall.c | 58 +- scripts/libafl-format.sh | 15 + system/cpus.c | 23 + target/arm/machine.c | 12 +- 44 files changed, 2143 insertions(+), 1494 deletions(-) create mode 100644 include/libafl/hooks/cpu_run.h create mode 100644 include/libafl/hooks/syscall.h create mode 100644 include/libafl/hooks/tcg/backdoor.h create mode 100644 include/libafl/hooks/tcg/block.h create mode 100644 include/libafl/hooks/tcg/cmp.h create mode 100644 include/libafl/hooks/tcg/edge.h create mode 100644 include/libafl/hooks/tcg/instruction.h create mode 100644 include/libafl/hooks/tcg/read_write.h create mode 100644 include/libafl/hooks/thread.h create mode 100644 libafl/.clang-format create mode 100644 libafl/hooks/cpu_run.c create mode 100644 libafl/hooks/syscall.c create mode 100644 libafl/hooks/tcg/backdoor.c create mode 100644 libafl/hooks/tcg/block.c create mode 100644 libafl/hooks/tcg/cmp.c create mode 100644 libafl/hooks/tcg/edge.c create mode 100644 libafl/hooks/tcg/instruction.c create mode 100644 libafl/hooks/tcg/read_write.c create mode 100644 libafl/hooks/thread.c create mode 100755 scripts/libafl-format.sh diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 931f74256e..2fc8bf054f 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -52,6 +52,12 @@ #include "hw/boards.h" #include "sysemu/stats.h" +//// --- Begin LibAFL code --- + +#include "libafl/hooks/cpu_run.h" + +//// --- End LibAFL code --- + /* This check must be after config-host.h is included */ #ifdef CONFIG_EVENTFD #include @@ -2866,10 +2872,22 @@ int kvm_cpu_exec(CPUState *cpu) */ smp_rmb(); + //// --- Begin LibAFL code --- + + libafl_hook_cpu_run_pre_exec(cpu); + + //// --- End LibAFL code --- + run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0); attrs = kvm_arch_post_run(cpu, run); + //// --- Begin LibAFL code --- + + libafl_hook_cpu_run_post_exec(cpu); + + //// --- End LibAFL code --- + #ifdef KVM_HAVE_MCE_INJECTION if (unlikely(have_sigbus_pending)) { bql_lock(); diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index e470fd771c..a020ffb56b 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -68,7 +68,8 @@ //// --- Begin LibAFL code --- -#include "libafl/hook.h" +#include "libafl/hooks/tcg/block.h" +#include "libafl/hooks/tcg/edge.h" //// --- End LibAFL code --- @@ -284,24 +285,7 @@ static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb, //// --- Begin LibAFL code --- - struct libafl_block_hook* hook = libafl_block_hooks; - while (hook) { - uint64_t cur_id = 0; - if (hook->gen) - cur_id = hook->gen(hook->data, pc); - if (cur_id != (uint64_t)-1 && hook->helper_info.func) { - TCGv_i64 tmp0 = tcg_constant_i64(hook->data); - TCGv_i64 tmp1 = tcg_constant_i64(cur_id); - TCGTemp *tmp2[2] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1) }; - tcg_gen_callN(&hook->helper_info, NULL, tmp2); - tcg_temp_free_i64(tmp0); - tcg_temp_free_i64(tmp1); - } - if (cur_id != (uint64_t)-1 && hook->jit) { - hook->jit(hook->data, cur_id); - } - hook = hook->next; - } + libafl_qemu_hook_block_run(pc); //// --- End LibAFL code --- @@ -361,21 +345,9 @@ static int libafl_setjmp_gen_code(CPUArchState *env, TranslationBlock *tb, #error Unhandled TARGET_INSN_START_EXTRA_WORDS value #endif - struct libafl_edge_hook* hook = libafl_edge_hooks; - while (hook) { - if (hook->cur_id != (uint64_t)-1 && hook->helper_info.func) { - TCGv_i64 tmp0 = tcg_constant_i64(hook->data); - TCGv_i64 tmp1 = tcg_constant_i64(hook->cur_id); - TCGTemp *tmp2[2] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1) }; - tcg_gen_callN(&hook->helper_info, NULL, tmp2); - tcg_temp_free_i64(tmp0); - tcg_temp_free_i64(tmp1); - } - if (hook->cur_id != (uint64_t)-1 && hook->jit) { - hook->jit(hook->data, hook->cur_id); - } - hook = hook->next; - } + // run edge hooks + libafl_qemu_hook_edge_run(); + tcg_gen_goto_tb(0); tcg_gen_exit_tb(tb, 0); @@ -430,16 +402,7 @@ TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block, QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS); // edge hooks generation callbacks - struct libafl_edge_hook* hook = libafl_edge_hooks; - int no_exec_hook = 1; - while (hook) { - hook->cur_id = 0; - if (hook->gen) - hook->cur_id = hook->gen(hook->data, src_block, dst_block); - if (hook->cur_id != (uint64_t)-1 && (hook->helper_info.func || hook->jit)) - no_exec_hook = 0; - hook = hook->next; - } + bool no_exec_hook = libafl_qemu_hook_edge_gen(src_block, dst_block); if (no_exec_hook) return NULL; @@ -749,13 +712,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tb->tc.size = gen_code_size; //// --- Begin LibAFL code --- - struct libafl_block_hook *hook = libafl_block_hooks; - while (hook) - { - if (hook->post_gen) - hook->post_gen(hook->data, pc, tb->size); - hook = hook->next; - } + + libafl_qemu_hook_block_post_gen(tb, pc); + //// --- End LibAFL code --- /* diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 22370e6ce3..935d321464 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -104,6 +104,9 @@ static void gen_tb_end(const TranslationBlock *tb, uint32_t cflags, #include "libafl/exit.h" #include "libafl/hook.h" +#include "libafl/hooks/tcg/instruction.h" +#include "libafl/hooks/tcg/backdoor.h" + #ifndef TARGET_LONG_BITS #error "TARGET_LONG_BITS not defined" #endif @@ -168,37 +171,10 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, //// --- Begin LibAFL code --- - struct libafl_hook* hk = libafl_search_instruction_hook(db->pc_next); - if (hk) { - TCGv_i64 tmp0 = tcg_constant_i64(hk->data); -#if TARGET_LONG_BITS == 32 - TCGv_i32 tmp1 = tcg_constant_i32(db->pc_next); - TCGTemp *tmp2[2] = { tcgv_i64_temp(tmp0), tcgv_i32_temp(tmp1) }; -#else - TCGv_i64 tmp1 = tcg_constant_i64(db->pc_next); - TCGTemp *tmp2[2] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1) }; -#endif - // tcg_gen_callN(hk->callback, NULL, 2, tmp2); - tcg_gen_callN(&hk->helper_info, NULL, tmp2); -#if TARGET_LONG_BITS == 32 - tcg_temp_free_i32(tmp1); -#else - tcg_temp_free_i64(tmp1); -#endif - tcg_temp_free_i64(tmp0); - } - - struct libafl_breakpoint* bp = libafl_qemu_breakpoints; - while (bp) { - if (bp->addr == db->pc_next) { - TCGv_i64 tmp0 = tcg_constant_i64((uint64_t)db->pc_next); - gen_helper_libafl_qemu_handle_breakpoint(tcg_env, tmp0); - tcg_temp_free_i64(tmp0); - } - bp = bp->next; - } + libafl_qemu_hook_instruction_run(db->pc_next); libafl_gen_cur_pc = db->pc_next; + libafl_qemu_breakpoint_run(libafl_gen_cur_pc); // 0x0f, 0x3a, 0xf2, 0x44 uint8_t backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next); @@ -209,16 +185,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, if (backdoor == 0xf2) { backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next +3); if (backdoor == 0x44) { - struct libafl_backdoor_hook* bhk = libafl_backdoor_hooks; - while (bhk) { - TCGv_i64 tmp0 = tcg_constant_i64(bhk->data); - TCGv tmp2 = tcg_constant_tl(db->pc_next); - TCGTemp *args[3] = { tcgv_i64_temp(tmp0), tcgv_ptr_temp(tcg_env), tcgv_tl_temp(tmp2) }; - - tcg_gen_callN(&bhk->helper_info, NULL, args); - - bhk = bhk->next; - } + libafl_qemu_hook_backdoor_run(db->pc_next); db->pc_next += 4; goto post_translate_insn; diff --git a/include/libafl/exit.h b/include/libafl/exit.h index a302aa53c1..55d6b8324e 100644 --- a/include/libafl/exit.h +++ b/include/libafl/exit.h @@ -1,7 +1,9 @@ #pragma once #include "qemu/osdep.h" + #include "exec/cpu-defs.h" +#include "exec/translator.h" #define EXCP_LIBAFL_EXIT 0xf4775747 @@ -10,14 +12,13 @@ struct libafl_breakpoint { struct libafl_breakpoint* next; }; -extern struct libafl_breakpoint* libafl_qemu_breakpoints; - // in cpu-target.c -void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc); +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); +void libafl_qemu_breakpoint_run(vaddr pc_next); enum libafl_exit_reason_kind { INTERNAL = 0, @@ -31,7 +32,8 @@ struct libafl_exit_reason_breakpoint { }; // A synchronous exit has been triggered. -struct libafl_exit_reason_sync_exit { }; +struct libafl_exit_reason_sync_exit { +}; // QEMU exited on its own for some reason. struct libafl_exit_reason_internal { @@ -46,7 +48,7 @@ struct libafl_exit_reason { union { struct libafl_exit_reason_internal internal; struct libafl_exit_reason_breakpoint breakpoint; // kind == BREAKPOINT - struct libafl_exit_reason_sync_exit sync_exit; // kind == SYNC_EXIT + struct libafl_exit_reason_sync_exit sync_exit; // kind == SYNC_EXIT } data; }; @@ -58,7 +60,8 @@ void libafl_exit_signal_vm_start(void); bool libafl_exit_asap(void); void libafl_sync_exit_cpu(void); -void libafl_exit_request_internal(CPUState* cpu, uint64_t pc, ShutdownCause cause, int signal); +void libafl_exit_request_internal(CPUState* cpu, uint64_t pc, + ShutdownCause cause, int signal); void libafl_exit_request_sync_backdoor(CPUState* cpu, target_ulong pc); void libafl_exit_request_breakpoint(CPUState* cpu, target_ulong pc); struct libafl_exit_reason* libafl_get_exit_reason(void); diff --git a/include/libafl/hook.h b/include/libafl/hook.h index 3848fc2416..7e50e7da1b 100644 --- a/include/libafl/hook.h +++ b/include/libafl/hook.h @@ -7,221 +7,55 @@ #include "tcg/tcg-internal.h" #include "tcg/tcg-temp-internal.h" -#define LIBAFL_TABLES_SIZE 16384 -#define LIBAFL_TABLES_HASH(p) (((13*((size_t)(p))) ^ (((size_t)(p)) >> 15)) % LIBAFL_TABLES_SIZE) #define LIBAFL_MAX_INSNS 16 -void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args); +#define GEN_REMOVE_HOOK(name) \ + int libafl_qemu_remove_##name##_hook(size_t num, int invalidate) \ + { \ + CPUState* cpu; \ + struct libafl_##name##_hook** hk = &libafl_##name##_hooks; \ + \ + while (*hk) { \ + if ((*hk)->num == num) { \ + if (invalidate) { \ + CPU_FOREACH(cpu) { tb_flush(cpu); } \ + } \ + \ + void* tmp = *hk; \ + *hk = (*hk)->next; \ + free(tmp); \ + return 1; \ + } else { \ + hk = &(*hk)->next; \ + } \ + } \ + \ + return 0; \ + } -TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block, - target_ulong dst_block, int exit_n, - target_ulong cs_base, uint32_t flags, - int cflags); - -void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot); -void libafl_gen_backdoor(target_ulong pc); +#define GEN_REMOVE_HOOK1(name) \ + int libafl_qemu_remove_##name##_hook(size_t num) \ + { \ + struct libafl_##name##_hook** hk = &libafl_##name##_hooks; \ + \ + while (*hk) { \ + if ((*hk)->num == num) { \ + void* tmp = *hk; \ + *hk = (*hk)->next; \ + free(tmp); \ + return 1; \ + } else { \ + hk = &(*hk)->next; \ + } \ + } \ + \ + return 0; \ + } +// TODO: cleanup this extern target_ulong libafl_gen_cur_pc; - -struct libafl_hook { - target_ulong addr; - // void (*callback)(uint64_t, target_ulong); - uint64_t data; - size_t num; - TCGHelperInfo helper_info; - struct libafl_hook* next; -}; - -extern struct libafl_hook* libafl_qemu_instruction_hooks[LIBAFL_TABLES_SIZE]; extern size_t libafl_qemu_hooks_num; -size_t libafl_qemu_add_instruction_hooks(target_ulong pc, void (*callback)(uint64_t data, target_ulong pc), - uint64_t data, int invalidate); -size_t libafl_qemu_remove_instruction_hooks_at(target_ulong addr, int invalidate); -int libafl_qemu_remove_instruction_hook(size_t num, int invalidate); -struct libafl_hook* libafl_search_instruction_hook(target_ulong addr); +void tcg_gen_callN(TCGHelperInfo* info, TCGTemp* ret, TCGTemp** args); -struct libafl_backdoor_hook { - void (*exec)(uint64_t data, CPUArchState* cpu, target_ulong pc); - uint64_t data; - size_t num; - TCGHelperInfo helper_info; - struct libafl_backdoor_hook* next; -}; - -extern struct libafl_backdoor_hook* libafl_backdoor_hooks; - -size_t libafl_add_backdoor_hook(void (*exec)(uint64_t data, CPUArchState* cpu, target_ulong pc), - uint64_t data); -int libafl_qemu_remove_backdoor_hook(size_t num, int invalidate); - -struct libafl_edge_hook { - uint64_t (*gen)(uint64_t data, target_ulong src, target_ulong dst); - // void (*exec)(uint64_t data, uint64_t id); - size_t (*jit)(uint64_t data, uint64_t id); // optional opt - uint64_t data; - size_t num; - uint64_t cur_id; - TCGHelperInfo helper_info; - struct libafl_edge_hook* next; -}; - -extern struct libafl_edge_hook* libafl_edge_hooks; - -size_t libafl_add_edge_hook(uint64_t (*gen)(uint64_t data, target_ulong src, target_ulong dst), - void (*exec)(uint64_t data, uint64_t id), - uint64_t data); -int libafl_qemu_remove_edge_hook(size_t num, int invalidate); -bool libafl_qemu_edge_hook_set_jit(size_t num, size_t (*jit)(uint64_t, uint64_t)); // no param names to avoid to be marked as safe - -struct libafl_block_hook { - uint64_t (*gen)(uint64_t data, target_ulong pc); - void (*post_gen)(uint64_t data, target_ulong pc, target_ulong block_length); - // void (*exec)(uint64_t data, uint64_t id); - size_t (*jit)(uint64_t data, uint64_t id); // optional opt - uint64_t data; - size_t num; - TCGHelperInfo helper_info; - struct libafl_block_hook* next; -}; - -extern struct libafl_block_hook* libafl_block_hooks; - -size_t libafl_add_block_hook(uint64_t (*gen)(uint64_t data, target_ulong pc), - void (*post_gen)(uint64_t data, target_ulong pc, target_ulong block_length), - void (*exec)(uint64_t data, uint64_t id), uint64_t data); -int libafl_qemu_remove_block_hook(size_t num, int invalidate); -bool libafl_qemu_block_hook_set_jit(size_t num, size_t (*jit)(uint64_t, uint64_t)); // no param names to avoid to be marked as safe - -struct libafl_rw_hook { - uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi); - /*void (*exec1)(uint64_t data, uint64_t id, target_ulong addr); - void (*exec2)(uint64_t data, uint64_t id, target_ulong addr); - void (*exec4)(uint64_t data, uint64_t id, target_ulong addr); - void (*exec8)(uint64_t data, uint64_t id, target_ulong addr); - void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size);*/ - uint64_t data; - size_t num; - TCGHelperInfo helper_info1; - TCGHelperInfo helper_info2; - TCGHelperInfo helper_info4; - TCGHelperInfo helper_info8; - TCGHelperInfo helper_infoN; - struct libafl_rw_hook* next; -}; - -// alias -#define libafl_read_hook libafl_rw_hook -#define libafl_write_hook libafl_rw_hook - -extern struct libafl_rw_hook* libafl_read_hooks; -extern struct libafl_rw_hook* libafl_write_hooks; - -size_t libafl_add_read_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp *addr, MemOpIdx oi), - void (*exec1)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec2)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec4)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec8)(uint64_t data, uint64_t id, target_ulong addr), - void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size), - uint64_t data); -size_t libafl_add_write_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp *addr, MemOpIdx oi), - void (*exec1)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec2)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec4)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec8)(uint64_t data, uint64_t id, target_ulong addr), - void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size), - uint64_t data); - -int libafl_qemu_remove_read_hook(size_t num, int invalidate); -int libafl_qemu_remove_write_hook(size_t num, int invalidate); - -void libafl_gen_read(TCGTemp *addr, MemOpIdx oi); -void libafl_gen_write(TCGTemp *addr, MemOpIdx oi); - -struct libafl_cmp_hook { - uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size); - /*void (*exec1)(uint64_t data, uint64_t id, uint8_t v0, uint8_t v1); - void (*exec2)(uint64_t data, uint64_t id, uint16_t v0, uint16_t v1); - void (*exec4)(uint64_t data, uint64_t id, uint32_t v0, uint32_t v1); - void (*exec8)(uint64_t data, uint64_t id, uint64_t v0, uint64_t v1);*/ - uint64_t data; - size_t num; - TCGHelperInfo helper_info1; - TCGHelperInfo helper_info2; - TCGHelperInfo helper_info4; - TCGHelperInfo helper_info8; - struct libafl_cmp_hook* next; -}; - -extern struct libafl_cmp_hook* libafl_cmp_hooks; - -size_t libafl_add_cmp_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size), - void (*exec1)(uint64_t data, uint64_t id, uint8_t v0, uint8_t v1), - void (*exec2)(uint64_t data, uint64_t id, uint16_t v0, uint16_t v1), - void (*exec4)(uint64_t data, uint64_t id, uint32_t v0, uint32_t v1), - void (*exec8)(uint64_t data, uint64_t id, uint64_t v0, uint64_t v1), - uint64_t data); -int libafl_qemu_remove_cmp_hook(size_t num, int invalidate); - -struct syshook_ret { - target_ulong retval; - bool skip_syscall; -}; - -struct libafl_pre_syscall_hook { - struct syshook_ret (*callback)(uint64_t data, int sys_num, target_ulong arg0, - target_ulong arg1, target_ulong arg2, - target_ulong arg3, target_ulong arg4, - target_ulong arg5, target_ulong arg6, - target_ulong arg7); - uint64_t data; - size_t num; - struct libafl_pre_syscall_hook* next; -}; - -struct libafl_post_syscall_hook { - target_ulong (*callback)(uint64_t data, target_ulong ret, int sys_num, - target_ulong arg0, target_ulong arg1, - target_ulong arg2, target_ulong arg3, - target_ulong arg4, target_ulong arg5, - target_ulong arg6, target_ulong arg7); - uint64_t data; - size_t num; - struct libafl_post_syscall_hook* next; -}; - -extern struct libafl_pre_syscall_hook* libafl_pre_syscall_hooks; -extern struct libafl_post_syscall_hook* libafl_post_syscall_hooks; - -size_t libafl_add_pre_syscall_hook(struct syshook_ret (*callback)( - uint64_t data, int sys_num, target_ulong arg0, - target_ulong arg1, target_ulong arg2, - target_ulong arg3, target_ulong arg4, - target_ulong arg5, target_ulong arg6, - target_ulong arg7), - uint64_t data); -size_t libafl_add_post_syscall_hook(target_ulong (*callback)( - uint64_t data, target_ulong ret, int sys_num, - target_ulong arg0, target_ulong arg1, - target_ulong arg2, target_ulong arg3, - target_ulong arg4, target_ulong arg5, - target_ulong arg6, target_ulong arg7), - uint64_t data); - -int libafl_qemu_remove_pre_syscall_hook(size_t num); -int libafl_qemu_remove_post_syscall_hook(size_t num); - -struct libafl_new_thread_hook { - bool (*callback)(uint64_t data, uint32_t tid); - uint64_t data; - size_t num; - struct libafl_new_thread_hook* next; -}; - -extern struct libafl_new_thread_hook* libafl_new_thread_hooks; - -size_t libafl_add_new_thread_hook(bool (*callback)(uint64_t data, uint32_t tid), - uint64_t data); -int libafl_qemu_remove_new_thread_hook(size_t num); - -void libafl_tcg_gen_asan(TCGTemp * addr, size_t size); \ No newline at end of file +void libafl_tcg_gen_asan(TCGTemp* addr, size_t size); diff --git a/include/libafl/hooks/cpu_run.h b/include/libafl/hooks/cpu_run.h new file mode 100644 index 0000000000..b516c055a6 --- /dev/null +++ b/include/libafl/hooks/cpu_run.h @@ -0,0 +1,36 @@ +#pragma once + +#include "qemu/osdep.h" + +#include "qapi/error.h" + +#include "exec/exec-all.h" +#include "exec/tb-flush.h" + +#include "libafl/exit.h" +#include "libafl/hook.h" + +typedef void (*libafl_cpu_run_fn)(uint64_t data, CPUState* cpu); + +struct libafl_cpu_run_hook { + // functions + libafl_cpu_run_fn pre_cpu_run; + libafl_cpu_run_fn post_cpu_run; + + // data + uint64_t data; + size_t num; + + // next + struct libafl_cpu_run_hook* next; +}; + +size_t libafl_hook_cpu_run_add(libafl_cpu_run_fn pre_cpu_run, + libafl_cpu_run_fn post_cpu_run, uint64_t data); + +int libafl_hook_cpu_run_remove(size_t num); + +int libafl_qemu_remove_cpu_run_hook(size_t num); + +void libafl_hook_cpu_run_pre_exec(CPUState* cpu); +void libafl_hook_cpu_run_post_exec(CPUState* cpu); diff --git a/include/libafl/hooks/syscall.h b/include/libafl/hooks/syscall.h new file mode 100644 index 0000000000..529c2bf442 --- /dev/null +++ b/include/libafl/hooks/syscall.h @@ -0,0 +1,76 @@ +#pragma once + +#include "qemu/osdep.h" + +#include "qapi/error.h" + +#include "exec/exec-all.h" +#include "exec/tb-flush.h" + +#include "libafl/exit.h" +#include "libafl/hook.h" + +struct syshook_ret { + target_ulong retval; + bool skip_syscall; +}; + +struct libafl_pre_syscall_hook { + // functions + struct syshook_ret (*callback)(uint64_t data, int sys_num, + target_ulong arg0, target_ulong arg1, + target_ulong arg2, target_ulong arg3, + target_ulong arg4, target_ulong arg5, + target_ulong arg6, target_ulong arg7); + + // data + uint64_t data; + size_t num; + + // next + struct libafl_pre_syscall_hook* next; +}; + +struct libafl_post_syscall_hook { + // functions + target_ulong (*callback)(uint64_t data, target_ulong ret, int sys_num, + target_ulong arg0, target_ulong arg1, + target_ulong arg2, target_ulong arg3, + target_ulong arg4, target_ulong arg5, + target_ulong arg6, target_ulong arg7); + + // data + uint64_t data; + size_t num; + + // next + struct libafl_post_syscall_hook* next; +}; + +size_t libafl_add_pre_syscall_hook( + struct syshook_ret (*callback)(uint64_t data, int sys_num, + target_ulong arg0, target_ulong arg1, + target_ulong arg2, target_ulong arg3, + target_ulong arg4, target_ulong arg5, + target_ulong arg6, target_ulong arg7), + uint64_t data); +size_t libafl_add_post_syscall_hook( + target_ulong (*callback)(uint64_t data, target_ulong ret, int sys_num, + target_ulong arg0, target_ulong arg1, + target_ulong arg2, target_ulong arg3, + target_ulong arg4, target_ulong arg5, + target_ulong arg6, target_ulong arg7), + uint64_t data); + +int libafl_qemu_remove_pre_syscall_hook(size_t num); +int libafl_qemu_remove_post_syscall_hook(size_t num); + +bool libafl_hook_syscall_pre_run(CPUArchState* env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6, abi_long arg7, + abi_long arg8, abi_long* ret); + +void libafl_hook_syscall_post_run(int num, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5, + abi_long arg6, abi_long arg7, abi_long arg8, + abi_long* ret); diff --git a/include/libafl/hooks/tcg/backdoor.h b/include/libafl/hooks/tcg/backdoor.h new file mode 100644 index 0000000000..617ee4f2cf --- /dev/null +++ b/include/libafl/hooks/tcg/backdoor.h @@ -0,0 +1,38 @@ +#pragma once + +#include "qemu/osdep.h" + +#include "qapi/error.h" + +#include "exec/exec-all.h" +#include "exec/tb-flush.h" + +#include "libafl/exit.h" +#include "libafl/hook.h" + +struct libafl_backdoor_hook { + // functions + void (*gen)(uint64_t data, CPUArchState* cpu, target_ulong pc); + + // data + uint64_t data; + size_t num; + + // helpers + TCGHelperInfo helper_info; + + // next + struct libafl_backdoor_hook* next; +}; + +extern struct libafl_backdoor_hook* libafl_backdoor_hooks; + +void libafl_gen_backdoor(target_ulong pc); + +size_t libafl_add_backdoor_hook(void (*exec)(uint64_t data, CPUArchState* cpu, + target_ulong pc), + uint64_t data); + +int libafl_qemu_remove_backdoor_hook(size_t num, int invalidate); + +void libafl_qemu_hook_backdoor_run(vaddr pc_next); diff --git a/include/libafl/hooks/tcg/block.h b/include/libafl/hooks/tcg/block.h new file mode 100644 index 0000000000..7b4f49b076 --- /dev/null +++ b/include/libafl/hooks/tcg/block.h @@ -0,0 +1,43 @@ +#pragma once + +#include "qemu/osdep.h" + +#include "qapi/error.h" + +#include "exec/exec-all.h" +#include "exec/tb-flush.h" + +#include "libafl/exit.h" +#include "libafl/hook.h" + +struct libafl_block_hook { + // functions + uint64_t (*gen)(uint64_t data, target_ulong pc); + void (*post_gen)(uint64_t data, target_ulong pc, target_ulong block_length); + + size_t (*jit)(uint64_t data, uint64_t id); // optional opt + + // data + uint64_t data; + size_t num; + + // helpers + TCGHelperInfo helper_info; + + // next + struct libafl_block_hook* next; +}; + +void libafl_qemu_hook_block_post_gen(TranslationBlock* tb, vaddr pc); +void libafl_qemu_hook_block_run(target_ulong pc); + +bool libafl_qemu_block_hook_set_jit( + size_t num, + size_t (*jit)(uint64_t, + uint64_t)); // no param names to avoid to be marked as safe +int libafl_qemu_remove_block_hook(size_t num, int invalidate); +size_t libafl_add_block_hook(uint64_t (*gen)(uint64_t data, target_ulong pc), + void (*post_gen)(uint64_t data, target_ulong pc, + target_ulong block_length), + void (*exec)(uint64_t data, uint64_t id), + uint64_t data); diff --git a/include/libafl/hooks/tcg/cmp.h b/include/libafl/hooks/tcg/cmp.h new file mode 100644 index 0000000000..3a7bab699e --- /dev/null +++ b/include/libafl/hooks/tcg/cmp.h @@ -0,0 +1,39 @@ +#pragma once + +#include "qemu/osdep.h" + +#include "qapi/error.h" + +#include "exec/exec-all.h" +#include "exec/tb-flush.h" + +#include "libafl/exit.h" +#include "libafl/hook.h" + +struct libafl_cmp_hook { + // functions + uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size); + + // data + uint64_t data; + size_t num; + + // helpers + TCGHelperInfo helper_info1; + TCGHelperInfo helper_info2; + TCGHelperInfo helper_info4; + TCGHelperInfo helper_info8; + + // next + struct libafl_cmp_hook* next; +}; + +void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot); +size_t libafl_add_cmp_hook( + uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size), + void (*exec1)(uint64_t data, uint64_t id, uint8_t v0, uint8_t v1), + void (*exec2)(uint64_t data, uint64_t id, uint16_t v0, uint16_t v1), + void (*exec4)(uint64_t data, uint64_t id, uint32_t v0, uint32_t v1), + void (*exec8)(uint64_t data, uint64_t id, uint64_t v0, uint64_t v1), + uint64_t data); +int libafl_qemu_remove_cmp_hook(size_t num, int invalidate); diff --git a/include/libafl/hooks/tcg/edge.h b/include/libafl/hooks/tcg/edge.h new file mode 100644 index 0000000000..355592d159 --- /dev/null +++ b/include/libafl/hooks/tcg/edge.h @@ -0,0 +1,48 @@ +#pragma once + +#include "qemu/osdep.h" + +#include "qapi/error.h" + +#include "exec/exec-all.h" +#include "exec/tb-flush.h" + +#include "libafl/exit.h" +#include "libafl/hook.h" + +struct libafl_edge_hook { + // functions + uint64_t (*gen)(uint64_t data, target_ulong src, target_ulong dst); + size_t (*jit)(uint64_t data, uint64_t id); // optional opt + + // data + uint64_t data; + size_t num; + uint64_t cur_id; + + // helpers + TCGHelperInfo helper_info; + + // next + struct libafl_edge_hook* next; +}; + +TranslationBlock* libafl_gen_edge(CPUState* cpu, target_ulong src_block, + target_ulong dst_block, int exit_n, + target_ulong cs_base, uint32_t flags, + int cflags); + +size_t libafl_add_edge_hook(uint64_t (*gen)(uint64_t data, target_ulong src, + target_ulong dst), + void (*exec)(uint64_t data, uint64_t id), + uint64_t data); + +bool libafl_qemu_edge_hook_set_jit( + size_t num, + size_t (*jit)(uint64_t, + uint64_t)); // no param names to avoid to be marked as safe + +int libafl_qemu_remove_edge_hook(size_t num, int invalidate); + +bool libafl_qemu_hook_edge_gen(target_ulong src_block, target_ulong dst_block); +void libafl_qemu_hook_edge_run(void); diff --git a/include/libafl/hooks/tcg/instruction.h b/include/libafl/hooks/tcg/instruction.h new file mode 100644 index 0000000000..3deeb398a5 --- /dev/null +++ b/include/libafl/hooks/tcg/instruction.h @@ -0,0 +1,43 @@ +#pragma once + +#include "qemu/osdep.h" + +#include "qapi/error.h" + +#include "exec/exec-all.h" +#include "exec/tb-flush.h" + +#include "libafl/exit.h" +#include "libafl/hook.h" + +#define LIBAFL_TABLES_SIZE 16384 +#define LIBAFL_TABLES_HASH(p) \ + (((13 * ((size_t)(p))) ^ (((size_t)(p)) >> 15)) % LIBAFL_TABLES_SIZE) + +struct libafl_instruction_hook { + // data + uint64_t data; + size_t num; + target_ulong addr; + + // helpers + TCGHelperInfo helper_info; + + // next + struct libafl_instruction_hook* next; +}; + +size_t libafl_qemu_add_instruction_hooks(target_ulong pc, + void (*callback)(uint64_t data, + target_ulong pc), + uint64_t data, int invalidate); + +int libafl_qemu_remove_instruction_hook(size_t num, int invalidate); + +size_t libafl_qemu_remove_instruction_hooks_at(target_ulong addr, + int invalidate); + +struct libafl_instruction_hook* +libafl_search_instruction_hook(target_ulong addr); + +void libafl_qemu_hook_instruction_run(vaddr pc_next); diff --git a/include/libafl/hooks/tcg/read_write.h b/include/libafl/hooks/tcg/read_write.h new file mode 100644 index 0000000000..8e8f4f8118 --- /dev/null +++ b/include/libafl/hooks/tcg/read_write.h @@ -0,0 +1,60 @@ +#pragma once + +#include "qemu/osdep.h" + +#include "qapi/error.h" + +#include "exec/exec-all.h" +#include "exec/tb-flush.h" + +#include "libafl/exit.h" +#include "libafl/hook.h" + +#define libafl_read_hook libafl_rw_hook +#define libafl_write_hook libafl_rw_hook + +#define LIBAFL_TABLES_SIZE 16384 +#define LIBAFL_TABLES_HASH(p) \ + (((13 * ((size_t)(p))) ^ (((size_t)(p)) >> 15)) % LIBAFL_TABLES_SIZE) + +struct libafl_rw_hook { + // functions + uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi); + + // data + uint64_t data; + size_t num; + + // helpers + TCGHelperInfo helper_info1; + TCGHelperInfo helper_info2; + TCGHelperInfo helper_info4; + TCGHelperInfo helper_info8; + TCGHelperInfo helper_infoN; + + // next + struct libafl_rw_hook* next; +}; + +void libafl_gen_read(TCGTemp* addr, MemOpIdx oi); +void libafl_gen_write(TCGTemp* addr, MemOpIdx oi); + +size_t libafl_add_read_hook( + uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi), + void (*exec1)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec2)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec4)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec8)(uint64_t data, uint64_t id, target_ulong addr), + void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size), + uint64_t data); +size_t libafl_add_write_hook( + uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi), + void (*exec1)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec2)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec4)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec8)(uint64_t data, uint64_t id, target_ulong addr), + void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size), + uint64_t data); + +int libafl_qemu_remove_read_hook(size_t num, int invalidate); +int libafl_qemu_remove_write_hook(size_t num, int invalidate); diff --git a/include/libafl/hooks/thread.h b/include/libafl/hooks/thread.h new file mode 100644 index 0000000000..2db1744c48 --- /dev/null +++ b/include/libafl/hooks/thread.h @@ -0,0 +1,31 @@ +#pragma once + +#include "qemu/osdep.h" + +#include "qapi/error.h" + +#include "exec/exec-all.h" +#include "exec/tb-flush.h" + +#include "libafl/exit.h" +#include "libafl/hook.h" + +struct libafl_new_thread_hook { + // functions + bool (*callback)(uint64_t data, CPUArchState* cpu, uint32_t tid); + + // data + uint64_t data; + size_t num; + + // next + struct libafl_new_thread_hook* next; +}; + +size_t libafl_add_new_thread_hook(bool (*callback)(uint64_t data, + CPUArchState* env, + uint32_t tid), + uint64_t data); +int libafl_qemu_remove_new_thread_hook(size_t num); + +bool libafl_hook_new_thread_run(CPUArchState* env); diff --git a/include/libafl/syx-misc.h b/include/libafl/syx-misc.h index 60ab8d2856..5f4fd0e310 100644 --- a/include/libafl/syx-misc.h +++ b/include/libafl/syx-misc.h @@ -2,14 +2,18 @@ #include "qemu/error-report.h" -#define SYX_PRINTF(format, ...) fprintf(stderr, ("[QEMU-SYX] " format), ##__VA_ARGS__) +#define SYX_PRINTF(format, ...) \ + fprintf(stderr, ("[QEMU-SYX] " format), ##__VA_ARGS__) #ifdef CONFIG_DEBUG_SYX -#define SYX_DEBUG(format, ...) fprintf(stderr, ("[QEMU-SYX] DEBUG: " format), ##__VA_ARGS__) +#define SYX_DEBUG(format, ...) \ + fprintf(stderr, ("[QEMU-SYX] DEBUG: " format), ##__VA_ARGS__) #else -#define SYX_DEBUG(format, ...) +#define SYX_DEBUG(format, ...) #endif -#define SYX_WARNING(format, ...) warn_report(("[QEMU-SYX] " format), ##__VA_ARGS__) +#define SYX_WARNING(format, ...) \ + warn_report(("[QEMU-SYX] " format), ##__VA_ARGS__) -#define SYX_ERROR(format, ...) error_report(("[QEMU-SYX] " format), ##__VA_ARGS__) +#define SYX_ERROR(format, ...) \ + error_report(("[QEMU-SYX] " format), ##__VA_ARGS__) diff --git a/include/libafl/syx-snapshot/channel-buffer-writeback.h b/include/libafl/syx-snapshot/channel-buffer-writeback.h index 90deee0e04..828536deb3 100644 --- a/include/libafl/syx-snapshot/channel-buffer-writeback.h +++ b/include/libafl/syx-snapshot/channel-buffer-writeback.h @@ -1,15 +1,16 @@ #pragma once #include "qemu/osdep.h" -#include "migration/qemu-file.h" +#include "migration/qemu-file.h" #include "io/channel.h" #include "qom/object.h" #define QEMU_FILE_RAM_LIMIT (32 * 1024 * 1024) #define TYPE_QIO_CHANNEL_BUFFER_WRITEBACK "qio-channel-buffer-writeback" -OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelBufferWriteback, QIO_CHANNEL_BUFFER_WRITEBACK) +OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelBufferWriteback, + QIO_CHANNEL_BUFFER_WRITEBACK) struct QIOChannelBufferWriteback { QIOChannel parent; @@ -26,7 +27,10 @@ struct QIOChannelBufferWriteback { bool internal_allocation; }; -QIOChannelBufferWriteback* qio_channel_buffer_writeback_new(size_t capacity, uint8_t* writeback_buf, size_t writeback_buf_capacity, size_t* writeback_buf_usage); +QIOChannelBufferWriteback* +qio_channel_buffer_writeback_new(size_t capacity, uint8_t* writeback_buf, + size_t writeback_buf_capacity, + size_t* writeback_buf_usage); /** * qio_channel_buffer_new_external: @@ -34,5 +38,6 @@ QIOChannelBufferWriteback* qio_channel_buffer_writeback_new(size_t capacity, uin * @capacity: the total capacity of the underlying buffer * @usage: The size actually used by the buffer */ -QIOChannelBufferWriteback* -qio_channel_buffer_writeback_new_external(uint8_t* buf, size_t capacity, size_t usage, uint8_t* writeback_buf, size_t writeback_buf_capacity, size_t* writeback_buf_usage); +QIOChannelBufferWriteback* qio_channel_buffer_writeback_new_external( + uint8_t* buf, size_t capacity, size_t usage, uint8_t* writeback_buf, + size_t writeback_buf_capacity, size_t* writeback_buf_usage); diff --git a/include/libafl/syx-snapshot/device-save.h b/include/libafl/syx-snapshot/device-save.h index 1337e52bec..c0ec400613 100644 --- a/include/libafl/syx-snapshot/device-save.h +++ b/include/libafl/syx-snapshot/device-save.h @@ -2,7 +2,7 @@ #include "qemu/osdep.h" -#define DEVICE_SAVE_KIND_FULL 0 +#define DEVICE_SAVE_KIND_FULL 0 typedef struct DeviceSaveState { uint8_t kind; diff --git a/include/libafl/syx-snapshot/syx-cow-cache.h b/include/libafl/syx-snapshot/syx-cow-cache.h index 1e9f9fbe1e..2375f0d401 100644 --- a/include/libafl/syx-snapshot/syx-cow-cache.h +++ b/include/libafl/syx-snapshot/syx-cow-cache.h @@ -1,8 +1,10 @@ #pragma once -// Rewritten COW cache for block devices, heavily inspired by kAFL/NYX implementation. +// Rewritten COW cache for block devices, heavily inspired by kAFL/NYX +// implementation. #include "qemu/osdep.h" + #include "qemu/iov.h" #include "block/block.h" @@ -16,7 +18,7 @@ typedef struct SyxCowCacheDevice { typedef struct SyxCowCacheLayer SyxCowCacheLayer; typedef struct SyxCowCacheLayer { - GHashTable *cow_cache_devices; // H(device) -> SyxCowCacheDevice + GHashTable* cow_cache_devices; // H(device) -> SyxCowCacheDevice uint64_t chunk_size; uint64_t max_nb_chunks; @@ -33,13 +35,17 @@ SyxCowCache* syx_cow_cache_new(void); // rhs is freed and nulled. void syx_cow_cache_move(SyxCowCache* lhs, SyxCowCache** rhs); -void syx_cow_cache_push_layer(SyxCowCache* scc, uint64_t chunk_size, uint64_t max_size); +void syx_cow_cache_push_layer(SyxCowCache* scc, uint64_t chunk_size, + uint64_t max_size); void syx_cow_cache_pop_layer(SyxCowCache* scc); void syx_cow_cache_flush_highest_layer(SyxCowCache* scc); -void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, - BdrvRequestFlags flags); +void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend* blk, + int64_t offset, int64_t bytes, QEMUIOVector* qiov, + size_t qiov_offset, BdrvRequestFlags flags); -bool syx_cow_cache_write_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, +bool syx_cow_cache_write_entry(SyxCowCache* scc, BlockBackend* blk, + int64_t offset, int64_t bytes, + QEMUIOVector* qiov, size_t qiov_offset, BdrvRequestFlags flags); diff --git a/include/libafl/syx-snapshot/syx-snapshot.h b/include/libafl/syx-snapshot/syx-snapshot.h index 29b8de71bf..5a6cbbc85c 100644 --- a/include/libafl/syx-snapshot/syx-snapshot.h +++ b/include/libafl/syx-snapshot/syx-snapshot.h @@ -9,11 +9,13 @@ #pragma once #include "qemu/osdep.h" + #include "qom/object.h" #include "sysemu/sysemu.h" #include "device-save.h" #include "syx-cow-cache.h" + #include "libafl/syx-misc.h" #define SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE 64 @@ -31,7 +33,9 @@ typedef struct SyxSnapshot { SyxSnapshotIncrement* last_incremental_snapshot; SyxCowCache* bdrvs_cow_cache; - GHashTable *rbs_dirty_list; // hash map: H(rb) -> GHashTable(offset_within_ramblock). Filled lazily. + GHashTable* + rbs_dirty_list; // hash map: H(rb) -> + // GHashTable(offset_within_ramblock). Filled lazily. } SyxSnapshot; typedef struct SyxSnapshotTracker { @@ -54,7 +58,7 @@ typedef struct SyxSnapshotState { // It is not updated anymore when an active bdrv cache snapshto is set. SyxCowCache* before_fuzz_cache; // snapshot used to restore bdrv cache if enabled. - SyxSnapshot* active_bdrv_cache_snapshot; + SyxSnapshot* active_bdrv_cache_snapshot; // Root } SyxSnapshotState; @@ -69,22 +73,24 @@ void syx_snapshot_init(bool cached_bdrvs); // Snapshot API // -SyxSnapshot *syx_snapshot_new(bool track, bool is_active_bdrv_cache, DeviceSnapshotKind kind, char **devices); +SyxSnapshot* syx_snapshot_new(bool track, bool is_active_bdrv_cache, + DeviceSnapshotKind kind, char** devices); -void syx_snapshot_free(SyxSnapshot *snapshot); +void syx_snapshot_free(SyxSnapshot* snapshot); -void syx_snapshot_root_restore(SyxSnapshot *snapshot); +void syx_snapshot_root_restore(SyxSnapshot* snapshot); SyxSnapshotCheckResult syx_snapshot_check(SyxSnapshot* ref_snapshot); // Push the current RAM state and saves it -void syx_snapshot_increment_push(SyxSnapshot *snapshot, DeviceSnapshotKind kind, char **devices); +void syx_snapshot_increment_push(SyxSnapshot* snapshot, DeviceSnapshotKind kind, + char** devices); -// Restores the last push. Restores the root snapshot if no incremental snapshot is present. -void syx_snapshot_increment_pop(SyxSnapshot *snapshot); - -void syx_snapshot_increment_restore_last(SyxSnapshot *snapshot); +// Restores the last push. Restores the root snapshot if no incremental snapshot +// is present. +void syx_snapshot_increment_pop(SyxSnapshot* snapshot); +void syx_snapshot_increment_restore_last(SyxSnapshot* snapshot); // // Snapshot tracker API @@ -92,10 +98,10 @@ void syx_snapshot_increment_restore_last(SyxSnapshot *snapshot); SyxSnapshotTracker syx_snapshot_tracker_init(void); -void syx_snapshot_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot); - -void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot); +void syx_snapshot_track(SyxSnapshotTracker* tracker, SyxSnapshot* snapshot); +void syx_snapshot_stop_track(SyxSnapshotTracker* tracker, + SyxSnapshot* snapshot); // // Misc functions @@ -103,14 +109,13 @@ void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot) bool syx_snapshot_is_enabled(void); - // // Dirty list API // -void syx_snapshot_dirty_list_add_hostaddr(void *host_addr); +void syx_snapshot_dirty_list_add_hostaddr(void* host_addr); -void syx_snapshot_dirty_list_add_hostaddr_range(void *host_addr, uint64_t len); +void syx_snapshot_dirty_list_add_hostaddr_range(void* host_addr, uint64_t len); /** * @brief Same as syx_snapshot_dirty_list_add. The difference @@ -119,15 +124,19 @@ void syx_snapshot_dirty_list_add_hostaddr_range(void *host_addr, uint64_t len); * extreme environments where SystemV ABI is not respected. * It was created with tcg-target.inc.c environment in * mind. - * + * * @param dummy A dummy argument. it is to comply with * tcg-target.inc.c specific environment. * @param host_addr The host address where the dirty page is located. */ -void syx_snapshot_dirty_list_add_tcg_target(uint64_t dummy, void *host_addr); +void syx_snapshot_dirty_list_add_tcg_target(uint64_t dummy, void* host_addr); -bool syx_snapshot_cow_cache_read_entry(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, - BdrvRequestFlags flags); +bool syx_snapshot_cow_cache_read_entry(BlockBackend* blk, int64_t offset, + int64_t bytes, QEMUIOVector* qiov, + size_t qiov_offset, + BdrvRequestFlags flags); -bool syx_snapshot_cow_cache_write_entry(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, - BdrvRequestFlags flags); +bool syx_snapshot_cow_cache_write_entry(BlockBackend* blk, int64_t offset, + int64_t bytes, QEMUIOVector* qiov, + size_t qiov_offset, + BdrvRequestFlags flags); diff --git a/include/libafl/user.h b/include/libafl/user.h index fd386511a3..b7b8f6a5bd 100644 --- a/include/libafl/user.h +++ b/include/libafl/user.h @@ -1,7 +1,7 @@ #pragma once -#include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/osdep.h" struct libafl_mapinfo { target_ulong start; @@ -13,5 +13,9 @@ struct libafl_mapinfo { bool is_valid; }; -IntervalTreeNode * libafl_maps_first(IntervalTreeRoot * map_info); -IntervalTreeNode * libafl_maps_next(IntervalTreeNode *pageflags_maps_node, IntervalTreeRoot *proc_maps_node, struct libafl_mapinfo* ret); +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); diff --git a/libafl/.clang-format b/libafl/.clang-format new file mode 100644 index 0000000000..101a07de9f --- /dev/null +++ b/libafl/.clang-format @@ -0,0 +1,9 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +UseTab: Never +BreakBeforeBraces: Linux +AllowShortIfStatementsOnASingleLine: false +IndentCaseLabels: false +SortIncludes: Never +IncludeBlocks: Preserve +PointerAlignment: Left diff --git a/libafl/exit.c b/libafl/exit.c index df0ab04a09..52a9534d6f 100644 --- a/libafl/exit.c +++ b/libafl/exit.c @@ -1,6 +1,11 @@ #include "libafl/exit.h" +#include "tcg/tcg.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-temp-internal.h" #include "sysemu/runstate.h" +#include "exec/translator.h" + #include "cpu.h" #ifdef CONFIG_USER_ONLY @@ -13,11 +18,9 @@ struct libafl_breakpoint* libafl_qemu_breakpoints = NULL; int libafl_qemu_set_breakpoint(target_ulong pc) { - CPUState *cpu; + CPUState* cpu; - CPU_FOREACH(cpu) { - libafl_breakpoint_invalidate(cpu, pc); - } + CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, pc); } struct libafl_breakpoint* bp = calloc(sizeof(struct libafl_breakpoint), 1); bp->addr = pc; @@ -28,15 +31,13 @@ int libafl_qemu_set_breakpoint(target_ulong pc) int libafl_qemu_remove_breakpoint(target_ulong pc) { - CPUState *cpu; + CPUState* cpu; int r = 0; struct libafl_breakpoint** bp = &libafl_qemu_breakpoints; while (*bp) { if ((*bp)->addr == pc) { - CPU_FOREACH(cpu) { - libafl_breakpoint_invalidate(cpu, pc); - } + CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, pc); } *bp = (*bp)->next; r = 1; @@ -61,15 +62,13 @@ void libafl_sync_exit_cpu(void) { if (last_exit_reason.next_pc) { CPUClass* cc = CPU_GET_CLASS(last_exit_reason.cpu); - cc->set_pc(last_exit_reason.cpu, THUMB_MASK(last_exit_reason.cpu, last_exit_reason.next_pc)); + cc->set_pc(last_exit_reason.cpu, + THUMB_MASK(last_exit_reason.cpu, last_exit_reason.next_pc)); } last_exit_reason.next_pc = 0; } -bool libafl_exit_asap(void) -{ - return expected_exit; -} +bool libafl_exit_asap(void) { return expected_exit; } static void prepare_qemu_exit(CPUState* cpu, target_ulong next_pc) { @@ -81,7 +80,8 @@ static void prepare_qemu_exit(CPUState* cpu, target_ulong next_pc) qemu_system_debug_request(); cpu->stopped = true; // TODO check if still needed #endif - // in usermode, this may be called from the syscall hook, thus already out of the cpu_exec but still in the cpu_loop + // in usermode, this may be called from the syscall hook, thus already out + // of the cpu_exec but still in the cpu_loop if (cpu->running) { cpu->exception_index = EXCP_LIBAFL_EXIT; cpu_loop_exit(cpu); @@ -97,7 +97,8 @@ CPUState* libafl_last_exit_cpu(void) return NULL; } -void libafl_exit_request_internal(CPUState* cpu, uint64_t pc, ShutdownCause cause, int signal) +void libafl_exit_request_internal(CPUState* cpu, uint64_t pc, + ShutdownCause cause, int signal) { last_exit_reason.kind = INTERNAL; last_exit_reason.data.internal.cause = cause; @@ -143,3 +144,16 @@ struct libafl_exit_reason* libafl_get_exit_reason(void) return NULL; } + +void libafl_qemu_breakpoint_run(vaddr pc_next) +{ + struct libafl_breakpoint* bp = libafl_qemu_breakpoints; + while (bp) { + if (bp->addr == pc_next) { + TCGv_i64 tmp0 = tcg_constant_i64((uint64_t)pc_next); + gen_helper_libafl_qemu_handle_breakpoint(tcg_env, tmp0); + tcg_temp_free_i64(tmp0); + } + bp = bp->next; + } +} diff --git a/libafl/hook.c b/libafl/hook.c index a8df7f58a3..03dc93cdcc 100644 --- a/libafl/hook.c +++ b/libafl/hook.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" + #include "qapi/error.h" #include "exec/exec-all.h" @@ -11,683 +12,6 @@ #error "TARGET_LONG_BITS not defined" #endif -target_ulong libafl_gen_cur_pc; - -struct libafl_hook* libafl_qemu_instruction_hooks[LIBAFL_TABLES_SIZE]; -size_t libafl_qemu_hooks_num = 0; - -size_t libafl_qemu_add_instruction_hooks(target_ulong pc, void (*callback)(uint64_t data, target_ulong pc), - uint64_t data, int invalidate) -{ - CPUState *cpu; - - if (invalidate) { - CPU_FOREACH(cpu) { - libafl_breakpoint_invalidate(cpu, pc); - } - } - - size_t idx = LIBAFL_TABLES_HASH(pc); - - struct libafl_hook* hk = calloc(sizeof(struct libafl_hook), 1); - hk->addr = pc; - // hk->callback = callback; - hk->data = data; - hk->helper_info.func = callback; - hk->helper_info.name = "libafl_hook"; - hk->helper_info.flags = dh_callflag(void); - hk->helper_info.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(tl, 2); - // TODO check for overflow - hk->num = libafl_qemu_hooks_num++; - hk->next = libafl_qemu_instruction_hooks[idx]; - libafl_qemu_instruction_hooks[idx] = hk; - return hk->num; -} - -size_t libafl_qemu_remove_instruction_hooks_at(target_ulong addr, int invalidate) -{ - CPUState *cpu; - size_t r = 0; - - size_t idx = LIBAFL_TABLES_HASH(addr); - struct libafl_hook** hk = &libafl_qemu_instruction_hooks[idx]; - while (*hk) { - if ((*hk)->addr == addr) { - if (invalidate) { - CPU_FOREACH(cpu) { - libafl_breakpoint_invalidate(cpu, addr); - } - } - - void *tmp = *hk; - *hk = (*hk)->next; - free(tmp); - r++; - } else { - hk = &(*hk)->next; - } - } - return r; -} - -int libafl_qemu_remove_instruction_hook(size_t num, int invalidate) -{ - CPUState *cpu; - size_t idx; - - for (idx = 0; idx < LIBAFL_TABLES_SIZE; ++idx) { - struct libafl_hook** hk = &libafl_qemu_instruction_hooks[idx]; - while (*hk) { - if ((*hk)->num == num) { - if (invalidate) { - CPU_FOREACH(cpu) { - libafl_breakpoint_invalidate(cpu, (*hk)->addr); - } - } - - void *tmp = *hk; - *hk = (*hk)->next; - free(tmp); - return 1; - } else { - hk = &(*hk)->next; - } - } - } - return 0; -} - -struct libafl_hook* libafl_search_instruction_hook(target_ulong addr) -{ - size_t idx = LIBAFL_TABLES_HASH(addr); - - struct libafl_hook* hk = libafl_qemu_instruction_hooks[idx]; - while (hk) { - if (hk->addr == addr) { - return hk; - } - hk = hk->next; - } - - return NULL; -} - -#define GEN_REMOVE_HOOK(name) \ -int libafl_qemu_remove_##name##_hook(size_t num, int invalidate) \ -{ \ - CPUState *cpu; \ - struct libafl_##name##_hook** hk = &libafl_##name##_hooks; \ - \ - while (*hk) { \ - if ((*hk)->num == num) { \ - if (invalidate) { \ - CPU_FOREACH(cpu) { \ - tb_flush(cpu); \ - } \ - } \ - \ - void *tmp = *hk; \ - *hk = (*hk)->next; \ - free(tmp); \ - return 1; \ - } else { \ - hk = &(*hk)->next; \ - } \ - } \ - \ - return 0; \ -} - -#define GEN_REMOVE_HOOK1(name) \ -int libafl_qemu_remove_##name##_hook(size_t num) \ -{ \ - struct libafl_##name##_hook** hk = &libafl_##name##_hooks; \ - \ - while (*hk) { \ - if ((*hk)->num == num) { \ - void *tmp = *hk; \ - *hk = (*hk)->next; \ - free(tmp); \ - return 1; \ - } else { \ - hk = &(*hk)->next; \ - } \ - } \ - \ - return 0; \ -} - -static TCGHelperInfo libafl_exec_backdoor_hook_info = { - .func = NULL, .name = "libafl_exec_backdoor_hook", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) - | dh_typemask(env, 1) - | dh_typemask(i64, 2) - | dh_typemask(tl, 3) -}; - -struct libafl_backdoor_hook* libafl_backdoor_hooks; -size_t libafl_backdoor_hooks_num = 0; - -size_t libafl_add_backdoor_hook(void (*exec)(uint64_t data, CPUArchState* cpu, target_ulong pc), - uint64_t data) -{ - struct libafl_backdoor_hook* hook = calloc(sizeof(struct libafl_backdoor_hook), 1); - // hook->exec = exec; - hook->data = data; - hook->num = libafl_backdoor_hooks_num++; - hook->next = libafl_backdoor_hooks; - libafl_backdoor_hooks = hook; - - memcpy(&hook->helper_info, &libafl_exec_backdoor_hook_info, sizeof(TCGHelperInfo)); - hook->helper_info.func = exec; - - return hook->num; -} - -GEN_REMOVE_HOOK(backdoor) - -static TCGHelperInfo libafl_exec_edge_hook_info = { - .func = NULL, .name = "libafl_exec_edge_hook", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) -}; - -struct libafl_edge_hook* libafl_edge_hooks; -size_t libafl_edge_hooks_num = 0; - -size_t libafl_add_edge_hook(uint64_t (*gen)(uint64_t data, target_ulong src, target_ulong dst), - void (*exec)(uint64_t data, uint64_t id), - uint64_t data) -{ - CPUState *cpu; - CPU_FOREACH(cpu) { - tb_flush(cpu); - } - - struct libafl_edge_hook* hook = calloc(sizeof(struct libafl_edge_hook), 1); - hook->gen = gen; - // hook->exec = exec; - hook->data = data; - hook->num = libafl_edge_hooks_num++; - hook->next = libafl_edge_hooks; - libafl_edge_hooks = hook; - - if (exec) { - memcpy(&hook->helper_info, &libafl_exec_edge_hook_info, sizeof(TCGHelperInfo)); - hook->helper_info.func = exec; - } - - return hook->num; -} - -GEN_REMOVE_HOOK(edge) - -bool libafl_qemu_edge_hook_set_jit(size_t num, size_t (*jit)(uint64_t data, uint64_t id)) { - struct libafl_edge_hook* hk = libafl_edge_hooks; - while (hk) { - if (hk->num == num) { - hk->jit = jit; - return true; - } else { - hk = hk->next; - } - } - return false; -} - -static TCGHelperInfo libafl_exec_block_hook_info = { - .func = NULL, .name = "libafl_exec_block_hook", \ - .flags = dh_callflag(void), \ - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) -}; - -struct libafl_block_hook* libafl_block_hooks; -size_t libafl_block_hooks_num = 0; - -size_t libafl_add_block_hook(uint64_t (*gen)(uint64_t data, target_ulong pc), - void (*post_gen)(uint64_t data, target_ulong pc, target_ulong block_length), - void (*exec)(uint64_t data, uint64_t id), uint64_t data) -{ - CPUState *cpu; - CPU_FOREACH(cpu) { - tb_flush(cpu); - } - - struct libafl_block_hook* hook = calloc(sizeof(struct libafl_block_hook), 1); - hook->gen = gen; - hook->post_gen = post_gen; - // hook->exec = exec; - hook->data = data; - hook->num = libafl_block_hooks_num++; - hook->next = libafl_block_hooks; - libafl_block_hooks = hook; - - if (exec) { - memcpy(&hook->helper_info, &libafl_exec_block_hook_info, sizeof(TCGHelperInfo)); - hook->helper_info.func = exec; - } - - return hook->num; -} - -GEN_REMOVE_HOOK(block) - -bool libafl_qemu_block_hook_set_jit(size_t num, size_t (*jit)(uint64_t data, uint64_t id)) { - struct libafl_block_hook* hk = libafl_block_hooks; - while (hk) { - if (hk->num == num) { - hk->jit = jit; - return true; - } else { - hk = hk->next; - } - } - return false; -} - -static TCGHelperInfo libafl_exec_read_hook1_info = { - .func = NULL, .name = "libafl_exec_read_hook1", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3) -}; -static TCGHelperInfo libafl_exec_read_hook2_info = { - .func = NULL, .name = "libafl_exec_read_hook2", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3) -}; -static TCGHelperInfo libafl_exec_read_hook4_info = { - .func = NULL, .name = "libafl_exec_read_hook4", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3) -}; -static TCGHelperInfo libafl_exec_read_hook8_info = { - .func = NULL, .name = "libafl_exec_read_hook8", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3) -}; -static TCGHelperInfo libafl_exec_read_hookN_info = { - .func = NULL, .name = "libafl_exec_read_hookN", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) - | dh_typemask(tl, 3) | dh_typemask(i64, 4) -}; -static TCGHelperInfo libafl_exec_write_hook1_info = { - .func = NULL, .name = "libafl_exec_write_hook1", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3) -}; -static TCGHelperInfo libafl_exec_write_hook2_info = { - .func = NULL, .name = "libafl_exec_write_hook2", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3) -}; -static TCGHelperInfo libafl_exec_write_hook4_info = { - .func = NULL, .name = "libafl_exec_write_hook4", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3) -}; -static TCGHelperInfo libafl_exec_write_hook8_info = { - .func = NULL, .name = "libafl_exec_write_hook8", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3) -}; -static TCGHelperInfo libafl_exec_write_hookN_info = { - .func = NULL, .name = "libafl_exec_write_hookN", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) - | dh_typemask(tl, 3) | dh_typemask(i64, 4) -}; - -struct libafl_rw_hook* libafl_read_hooks; -size_t libafl_read_hooks_num = 0; - -size_t libafl_add_read_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp *addr, MemOpIdx oi), - void (*exec1)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec2)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec4)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec8)(uint64_t data, uint64_t id, target_ulong addr), - void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size), - uint64_t data) -{ - CPUState *cpu; - CPU_FOREACH(cpu) { - tb_flush(cpu); - } - - struct libafl_rw_hook* hook = calloc(sizeof(struct libafl_rw_hook), 1); - hook->gen = gen; - /*hook->exec1 = exec1; - hook->exec2 = exec2; - hook->exec4 = exec4; - hook->exec8 = exec8; - hook->execN = execN;*/ - hook->data = data; - hook->num = libafl_read_hooks_num++; - hook->next = libafl_read_hooks; - libafl_read_hooks = hook; - - if (exec1) { - memcpy(&hook->helper_info1, &libafl_exec_read_hook1_info, sizeof(TCGHelperInfo)); - hook->helper_info1.func = exec1; - } - if (exec2) { - memcpy(&hook->helper_info2, &libafl_exec_read_hook2_info, sizeof(TCGHelperInfo)); - hook->helper_info2.func = exec2; - } - if (exec4) { - memcpy(&hook->helper_info4, &libafl_exec_read_hook4_info, sizeof(TCGHelperInfo)); - hook->helper_info4.func = exec4; - } - if (exec8) { - memcpy(&hook->helper_info8, &libafl_exec_read_hook8_info, sizeof(TCGHelperInfo)); - hook->helper_info8.func = exec8; - } - if (execN) { - memcpy(&hook->helper_infoN, &libafl_exec_read_hookN_info, sizeof(TCGHelperInfo)); - hook->helper_infoN.func = execN; - } - - return hook->num; -} - -GEN_REMOVE_HOOK(read) - -struct libafl_rw_hook* libafl_write_hooks; -size_t libafl_write_hooks_num = 0; - -size_t libafl_add_write_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp *addr, MemOpIdx oi), - void (*exec1)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec2)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec4)(uint64_t data, uint64_t id, target_ulong addr), - void (*exec8)(uint64_t data, uint64_t id, target_ulong addr), - void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size), - uint64_t data) -{ - CPUState *cpu; - CPU_FOREACH(cpu) { - tb_flush(cpu); - } - - struct libafl_rw_hook* hook = calloc(sizeof(struct libafl_rw_hook), 1); - hook->gen = gen; - /*hook->exec1 = exec1; - hook->exec2 = exec2; - hook->exec4 = exec4; - hook->exec8 = exec8; - hook->execN = execN;*/ - hook->data = data; - hook->num = libafl_write_hooks_num++; - hook->next = libafl_write_hooks; - libafl_write_hooks = hook; - - if (exec1) { - memcpy(&hook->helper_info1, &libafl_exec_write_hook1_info, sizeof(TCGHelperInfo)); - hook->helper_info1.func = exec1; - } - if (exec2) { - memcpy(&hook->helper_info2, &libafl_exec_write_hook2_info, sizeof(TCGHelperInfo)); - hook->helper_info2.func = exec2; - } - if (exec4) { - memcpy(&hook->helper_info4, &libafl_exec_write_hook4_info, sizeof(TCGHelperInfo)); - hook->helper_info4.func = exec4; - } - if (exec8) { - memcpy(&hook->helper_info8, &libafl_exec_write_hook8_info, sizeof(TCGHelperInfo)); - hook->helper_info8.func = exec8; - } - if (execN) { - memcpy(&hook->helper_infoN, &libafl_exec_write_hookN_info, sizeof(TCGHelperInfo)); - hook->helper_infoN.func = execN; - } - - return hook->num; -} - -GEN_REMOVE_HOOK(write) - -static void libafl_gen_rw(TCGTemp *addr, MemOpIdx oi, struct libafl_rw_hook* hook) -{ - size_t size = memop_size(get_memop(oi)); - - while (hook) { - uint64_t cur_id = 0; - if (hook->gen) - cur_id = hook->gen(hook->data, libafl_gen_cur_pc, addr, oi); - TCGHelperInfo* info = NULL; - if (size == 1 && hook->helper_info1.func) info = &hook->helper_info1; - else if (size == 2 && hook->helper_info2.func) info = &hook->helper_info2; - else if (size == 4 && hook->helper_info4.func) info = &hook->helper_info4; - else if (size == 8 && hook->helper_info8.func) info = &hook->helper_info8; - if (cur_id != (uint64_t)-1) { - if (info) { - TCGv_i64 tmp0 = tcg_constant_i64(hook->data); - TCGv_i64 tmp1 = tcg_constant_i64(cur_id); - TCGTemp *tmp2[3] = { tcgv_i64_temp(tmp0), - tcgv_i64_temp(tmp1), - addr }; - tcg_gen_callN(info, NULL, tmp2); - tcg_temp_free_i64(tmp0); - tcg_temp_free_i64(tmp1); - } else if (hook->helper_infoN.func) { - TCGv_i64 tmp0 = tcg_constant_i64(hook->data); - TCGv_i64 tmp1 = tcg_constant_i64(cur_id); - TCGv tmp2 = tcg_constant_tl(size); - TCGTemp *tmp3[4] = { tcgv_i64_temp(tmp0), - tcgv_i64_temp(tmp1), - addr, -#if TARGET_LONG_BITS == 32 - tcgv_i32_temp(tmp2) }; -#else - tcgv_i64_temp(tmp2) }; -#endif - tcg_gen_callN(&hook->helper_infoN, NULL, tmp3); - tcg_temp_free_i64(tmp0); - tcg_temp_free_i64(tmp1); -#if TARGET_LONG_BITS == 32 - tcg_temp_free_i32(tmp2); -#else - tcg_temp_free_i64(tmp2); -#endif - } - } - hook = hook->next; - } -} - -void libafl_gen_read(TCGTemp *addr, MemOpIdx oi) -{ - libafl_gen_rw(addr, oi, libafl_read_hooks); -} - -void libafl_gen_write(TCGTemp *addr, MemOpIdx oi) -{ - libafl_gen_rw(addr, oi, libafl_write_hooks); -} - -static TCGHelperInfo libafl_exec_cmp_hook1_info = { - .func = NULL, .name = "libafl_exec_cmp_hook1", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) - | dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4) -}; -static TCGHelperInfo libafl_exec_cmp_hook2_info = { - .func = NULL, .name = "libafl_exec_cmp_hook2", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) - | dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4) -}; -static TCGHelperInfo libafl_exec_cmp_hook4_info = { - .func = NULL, .name = "libafl_exec_cmp_hook4", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) - | dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4) -}; -static TCGHelperInfo libafl_exec_cmp_hook8_info = { - .func = NULL, .name = "libafl_exec_cmp_hook8", - .flags = dh_callflag(void), - .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) - | dh_typemask(i64, 2) | dh_typemask(i64, 3) | dh_typemask(i64, 4) -}; - -struct libafl_cmp_hook* libafl_cmp_hooks; -size_t libafl_cmp_hooks_num = 0; - -size_t libafl_add_cmp_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size), - void (*exec1)(uint64_t data, uint64_t id, uint8_t v0, uint8_t v1), - void (*exec2)(uint64_t data, uint64_t id, uint16_t v0, uint16_t v1), - void (*exec4)(uint64_t data, uint64_t id, uint32_t v0, uint32_t v1), - void (*exec8)(uint64_t data, uint64_t id, uint64_t v0, uint64_t v1), - uint64_t data) -{ - CPUState *cpu; - CPU_FOREACH(cpu) { - tb_flush(cpu); - } - - struct libafl_cmp_hook* hook = calloc(sizeof(struct libafl_cmp_hook), 1); - hook->gen = gen; - /*hook->exec1 = exec1; - hook->exec2 = exec2; - hook->exec4 = exec4; - hook->exec8 = exec8;*/ - hook->data = data; - hook->num = libafl_cmp_hooks_num++; - hook->next = libafl_cmp_hooks; - libafl_cmp_hooks = hook; - - if (exec1) { - memcpy(&hook->helper_info1, &libafl_exec_cmp_hook1_info, sizeof(TCGHelperInfo)); - hook->helper_info1.func = exec1; - } - if (exec2) { - memcpy(&hook->helper_info2, &libafl_exec_cmp_hook2_info, sizeof(TCGHelperInfo)); - hook->helper_info2.func = exec2; - } - if (exec4) { - memcpy(&hook->helper_info4, &libafl_exec_cmp_hook4_info, sizeof(TCGHelperInfo)); - hook->helper_info4.func = exec4; - } - if (exec8) { - memcpy(&hook->helper_info8, &libafl_exec_cmp_hook8_info, sizeof(TCGHelperInfo)); - hook->helper_info8.func = exec8; - } - - return hook->num; -} - -GEN_REMOVE_HOOK(cmp) - -void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot) -{ - size_t size = 0; - switch (ot & MO_SIZE) { - case MO_64: - size = 8; - break; - case MO_32: - size = 4; - break; - case MO_16: - size = 2; - break; - case MO_8: - size = 1; - break; - default: - return; - } - - struct libafl_cmp_hook* hook = libafl_cmp_hooks; - while (hook) { - uint64_t cur_id = 0; - if (hook->gen) - cur_id = hook->gen(hook->data, pc, size); - TCGHelperInfo* info = NULL; - if (size == 1 && hook->helper_info1.func) info = &hook->helper_info1; - else if (size == 2 && hook->helper_info2.func) info = &hook->helper_info2; - else if (size == 4 && hook->helper_info4.func) info = &hook->helper_info4; - else if (size == 8 && hook->helper_info8.func) info = &hook->helper_info8; - if (cur_id != (uint64_t)-1 && info) { - TCGv_i64 tmp0 = tcg_constant_i64(hook->data); - TCGv_i64 tmp1 = tcg_constant_i64(cur_id); - TCGTemp *tmp2[4] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1), -#if TARGET_LONG_BITS == 32 - tcgv_i32_temp(op0), tcgv_i32_temp(op1) }; -#else - tcgv_i64_temp(op0), tcgv_i64_temp(op1) }; -#endif - tcg_gen_callN(info, NULL, tmp2); - tcg_temp_free_i64(tmp0); - tcg_temp_free_i64(tmp1); - } - hook = hook->next; - } -} - -struct libafl_pre_syscall_hook* libafl_pre_syscall_hooks; -struct libafl_post_syscall_hook* libafl_post_syscall_hooks; - -size_t libafl_pre_syscall_hooks_num = 0; -size_t libafl_post_syscall_hooks_num = 0; - -size_t libafl_add_pre_syscall_hook(struct syshook_ret (*callback)( - uint64_t data, int sys_num, target_ulong arg0, - target_ulong arg1, target_ulong arg2, - target_ulong arg3, target_ulong arg4, - target_ulong arg5, target_ulong arg6, - target_ulong arg7), - uint64_t data) -{ - struct libafl_pre_syscall_hook* hook = calloc(sizeof(struct libafl_pre_syscall_hook), 1); - hook->callback = callback; - hook->data = data; - hook->num = libafl_pre_syscall_hooks_num++; - hook->next = libafl_pre_syscall_hooks; - libafl_pre_syscall_hooks = hook; - - return hook->num; -} - -size_t libafl_add_post_syscall_hook(target_ulong (*callback)( - uint64_t data, target_ulong ret, int sys_num, - target_ulong arg0, target_ulong arg1, - target_ulong arg2, target_ulong arg3, - target_ulong arg4, target_ulong arg5, - target_ulong arg6, target_ulong arg7), - uint64_t data) -{ - struct libafl_post_syscall_hook* hook = calloc(sizeof(struct libafl_post_syscall_hook), 1); - hook->callback = callback; - hook->data = data; - hook->num = libafl_post_syscall_hooks_num++; - hook->next = libafl_post_syscall_hooks; - libafl_post_syscall_hooks = hook; - - return hook->num; -} - -GEN_REMOVE_HOOK1(pre_syscall) -GEN_REMOVE_HOOK1(post_syscall) - -struct libafl_new_thread_hook* libafl_new_thread_hooks; -size_t libafl_new_thread_hooks_num = 0; - -size_t libafl_add_new_thread_hook(bool (*callback)(uint64_t data, uint32_t tid), - uint64_t data) { - struct libafl_new_thread_hook* hook = calloc(sizeof(struct libafl_new_thread_hook), 1); - hook->callback = callback; - hook->data = data; - hook->num = libafl_new_thread_hooks_num++; - hook->next = libafl_new_thread_hooks; - libafl_new_thread_hooks = hook; - - return hook->num; -} - -GEN_REMOVE_HOOK1(new_thread) - #if TARGET_LONG_BITS == 32 #define SHADOW_BASE (0x20000000) #elif TARGET_LONG_BITS == 64 @@ -696,7 +20,7 @@ GEN_REMOVE_HOOK1(new_thread) #error Unhandled TARGET_LONG_BITS value #endif -void libafl_tcg_gen_asan(TCGTemp * addr, size_t size) +void libafl_tcg_gen_asan(TCGTemp* addr, size_t size) { if (size == 0) return; @@ -729,15 +53,12 @@ void libafl_tcg_gen_asan(TCGTemp * addr, size_t size) * detects an invalid access, we will instead attempt to write the value * at 0x0. */ - tcg_gen_movcond_tl(TCG_COND_EQ, test_addr, - shadow_val, tcg_constant_tl(0), - shadow_addr, tcg_constant_tl(0)); + tcg_gen_movcond_tl(TCG_COND_EQ, test_addr, shadow_val, tcg_constant_tl(0), + shadow_addr, tcg_constant_tl(0)); - if (size < 8) - { - tcg_gen_movcond_tl(TCG_COND_GE, test_addr, - k, shadow_val, - test_addr, shadow_addr); + if (size < 8) { + tcg_gen_movcond_tl(TCG_COND_GE, test_addr, k, shadow_val, test_addr, + shadow_addr); } tcg_gen_tl_ptr(test_ptr, test_addr); diff --git a/libafl/hooks/cpu_run.c b/libafl/hooks/cpu_run.c new file mode 100644 index 0000000000..a072727327 --- /dev/null +++ b/libafl/hooks/cpu_run.c @@ -0,0 +1,41 @@ +#include "libafl/hooks/cpu_run.h" + +static struct libafl_cpu_run_hook* libafl_cpu_run_hooks = NULL; +static size_t libafl_cpu_run_hooks_num = 0; + +GEN_REMOVE_HOOK1(cpu_run) + +size_t libafl_hook_cpu_run_add(libafl_cpu_run_fn pre_cpu_run, + libafl_cpu_run_fn post_cpu_run, uint64_t data) +{ + struct libafl_cpu_run_hook* hook = + calloc(sizeof(struct libafl_cpu_run_hook), 1); + + hook->pre_cpu_run = pre_cpu_run; + hook->post_cpu_run = post_cpu_run; + + hook->data = data; + hook->num = libafl_cpu_run_hooks_num++; + hook->next = libafl_cpu_run_hooks; + libafl_cpu_run_hooks = hook; + + return hook->num; +} + +void libafl_hook_cpu_run_pre_exec(CPUState* cpu) +{ + struct libafl_cpu_run_hook* h = libafl_cpu_run_hooks; + while (h) { + h->pre_cpu_run(h->data, cpu); + h = h->next; + } +} + +void libafl_hook_cpu_run_post_exec(CPUState* cpu) +{ + struct libafl_cpu_run_hook* h = libafl_cpu_run_hooks; + while (h) { + h->post_cpu_run(h->data, cpu); + h = h->next; + } +} diff --git a/libafl/hooks/syscall.c b/libafl/hooks/syscall.c new file mode 100644 index 0000000000..9583b77241 --- /dev/null +++ b/libafl/hooks/syscall.c @@ -0,0 +1,89 @@ +#include "libafl/hooks/syscall.h" + +struct libafl_pre_syscall_hook* libafl_pre_syscall_hooks; +size_t libafl_pre_syscall_hooks_num = 0; + +struct libafl_post_syscall_hook* libafl_post_syscall_hooks; +size_t libafl_post_syscall_hooks_num = 0; + +GEN_REMOVE_HOOK1(pre_syscall) +GEN_REMOVE_HOOK1(post_syscall) + +size_t libafl_add_pre_syscall_hook( + struct syshook_ret (*callback)(uint64_t data, int sys_num, + target_ulong arg0, target_ulong arg1, + target_ulong arg2, target_ulong arg3, + target_ulong arg4, target_ulong arg5, + target_ulong arg6, target_ulong arg7), + uint64_t data) +{ + struct libafl_pre_syscall_hook* hook = + calloc(sizeof(struct libafl_pre_syscall_hook), 1); + hook->callback = callback; + hook->data = data; + hook->num = libafl_pre_syscall_hooks_num++; + hook->next = libafl_pre_syscall_hooks; + libafl_pre_syscall_hooks = hook; + + return hook->num; +} + +size_t libafl_add_post_syscall_hook( + target_ulong (*callback)(uint64_t data, target_ulong ret, int sys_num, + target_ulong arg0, target_ulong arg1, + target_ulong arg2, target_ulong arg3, + target_ulong arg4, target_ulong arg5, + target_ulong arg6, target_ulong arg7), + uint64_t data) +{ + struct libafl_post_syscall_hook* hook = + calloc(sizeof(struct libafl_post_syscall_hook), 1); + hook->callback = callback; + hook->data = data; + hook->num = libafl_post_syscall_hooks_num++; + hook->next = libafl_post_syscall_hooks; + libafl_post_syscall_hooks = hook; + + return hook->num; +} + +bool libafl_hook_syscall_pre_run(CPUArchState* env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6, abi_long arg7, + abi_long arg8, abi_long* ret) +{ + bool skip_syscall = false; + + struct libafl_pre_syscall_hook* h = libafl_pre_syscall_hooks; + while (h) { + // no null check + struct syshook_ret hook_ret = h->callback( + h->data, num, (target_ulong)arg1, (target_ulong)arg2, + (target_ulong)arg3, (target_ulong)arg4, (target_ulong)arg5, + (target_ulong)arg6, (target_ulong)arg7, (target_ulong)arg8); + if (hook_ret.skip_syscall) { + skip_syscall = true; + *ret = (abi_ulong)hook_ret.retval; + } + h = h->next; + } + + return skip_syscall; +} + +void libafl_hook_syscall_post_run(int num, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5, + abi_long arg6, abi_long arg7, abi_long arg8, + abi_long* ret) +{ + struct libafl_post_syscall_hook* p = libafl_post_syscall_hooks; + while (p) { + // no null check + *ret = (abi_ulong)p->callback(p->data, (target_ulong)*ret, num, + (target_ulong)arg1, (target_ulong)arg2, + (target_ulong)arg3, (target_ulong)arg4, + (target_ulong)arg5, (target_ulong)arg6, + (target_ulong)arg7, (target_ulong)arg8); + p = p->next; + } +} diff --git a/libafl/hooks/tcg/backdoor.c b/libafl/hooks/tcg/backdoor.c new file mode 100644 index 0000000000..913e0def17 --- /dev/null +++ b/libafl/hooks/tcg/backdoor.c @@ -0,0 +1,47 @@ +#include "libafl/hooks/tcg/backdoor.h" + +struct libafl_backdoor_hook* libafl_backdoor_hooks; +size_t libafl_backdoor_hooks_num = 0; + +static TCGHelperInfo libafl_exec_backdoor_hook_info = { + .func = NULL, + .name = "libafl_exec_backdoor_hook", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(env, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3)}; + +GEN_REMOVE_HOOK(backdoor) + +size_t libafl_add_backdoor_hook(void (*exec)(uint64_t data, CPUArchState* cpu, + target_ulong pc), + uint64_t data) +{ + struct libafl_backdoor_hook* hook = + calloc(sizeof(struct libafl_backdoor_hook), 1); + // hook->exec = exec; + hook->data = data; + hook->num = libafl_backdoor_hooks_num++; + hook->next = libafl_backdoor_hooks; + libafl_backdoor_hooks = hook; + + memcpy(&hook->helper_info, &libafl_exec_backdoor_hook_info, + sizeof(TCGHelperInfo)); + hook->helper_info.func = exec; + + return hook->num; +} + +void libafl_qemu_hook_backdoor_run(vaddr pc_next) +{ + struct libafl_backdoor_hook* bhk = libafl_backdoor_hooks; + while (bhk) { + TCGv_i64 tmp0 = tcg_constant_i64(bhk->data); + TCGv tmp2 = tcg_constant_tl(pc_next); + TCGTemp* args[3] = {tcgv_i64_temp(tmp0), tcgv_ptr_temp(tcg_env), + tcgv_tl_temp(tmp2)}; + + tcg_gen_callN(&bhk->helper_info, NULL, args); + + bhk = bhk->next; + } +} diff --git a/libafl/hooks/tcg/block.c b/libafl/hooks/tcg/block.c new file mode 100644 index 0000000000..cf8c790054 --- /dev/null +++ b/libafl/hooks/tcg/block.c @@ -0,0 +1,89 @@ +#include "libafl/hooks/tcg/block.h" + +struct libafl_block_hook* libafl_block_hooks; +size_t libafl_block_hooks_num = 0; + +static TCGHelperInfo libafl_exec_block_hook_info = { + .func = NULL, + .name = "libafl_exec_block_hook", + .flags = dh_callflag(void), + .typemask = + dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2)}; + +GEN_REMOVE_HOOK(block) + +size_t libafl_add_block_hook(uint64_t (*gen)(uint64_t data, target_ulong pc), + void (*post_gen)(uint64_t data, target_ulong pc, + target_ulong block_length), + void (*exec)(uint64_t data, uint64_t id), + uint64_t data) +{ + CPUState* cpu; + CPU_FOREACH(cpu) { tb_flush(cpu); } + + struct libafl_block_hook* hook = + calloc(sizeof(struct libafl_block_hook), 1); + hook->gen = gen; + hook->post_gen = post_gen; + // hook->exec = exec; + hook->data = data; + hook->num = libafl_block_hooks_num++; + hook->next = libafl_block_hooks; + libafl_block_hooks = hook; + + if (exec) { + memcpy(&hook->helper_info, &libafl_exec_block_hook_info, + sizeof(TCGHelperInfo)); + hook->helper_info.func = exec; + } + + return hook->num; +} + +bool libafl_qemu_block_hook_set_jit(size_t num, + size_t (*jit)(uint64_t data, uint64_t id)) +{ + struct libafl_block_hook* hk = libafl_block_hooks; + while (hk) { + if (hk->num == num) { + hk->jit = jit; + return true; + } else { + hk = hk->next; + } + } + return false; +} + +void libafl_qemu_hook_block_post_gen(TranslationBlock* tb, vaddr pc) +{ + struct libafl_block_hook* hook = libafl_block_hooks; + while (hook) { + if (hook->post_gen) + hook->post_gen(hook->data, pc, tb->size); + hook = hook->next; + } +} + +void libafl_qemu_hook_block_run(target_ulong pc) +{ + struct libafl_block_hook* hook = libafl_block_hooks; + + while (hook) { + uint64_t cur_id = 0; + if (hook->gen) + cur_id = hook->gen(hook->data, pc); + if (cur_id != (uint64_t)-1 && hook->helper_info.func) { + TCGv_i64 tmp0 = tcg_constant_i64(hook->data); + TCGv_i64 tmp1 = tcg_constant_i64(cur_id); + TCGTemp* tmp2[2] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1)}; + tcg_gen_callN(&hook->helper_info, NULL, tmp2); + tcg_temp_free_i64(tmp0); + tcg_temp_free_i64(tmp1); + } + if (cur_id != (uint64_t)-1 && hook->jit) { + hook->jit(hook->data, cur_id); + } + hook = hook->next; + } +} diff --git a/libafl/hooks/tcg/cmp.c b/libafl/hooks/tcg/cmp.c new file mode 100644 index 0000000000..6bd723e9f7 --- /dev/null +++ b/libafl/hooks/tcg/cmp.c @@ -0,0 +1,129 @@ +#include "libafl/hooks/tcg/cmp.h" + +struct libafl_cmp_hook* libafl_cmp_hooks; +size_t libafl_cmp_hooks_num = 0; + +static TCGHelperInfo libafl_exec_cmp_hook1_info = { + .func = NULL, + .name = "libafl_exec_cmp_hook1", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4)}; +static TCGHelperInfo libafl_exec_cmp_hook2_info = { + .func = NULL, + .name = "libafl_exec_cmp_hook2", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4)}; +static TCGHelperInfo libafl_exec_cmp_hook4_info = { + .func = NULL, + .name = "libafl_exec_cmp_hook4", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4)}; +static TCGHelperInfo libafl_exec_cmp_hook8_info = { + .func = NULL, + .name = "libafl_exec_cmp_hook8", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(i64, 3) | + dh_typemask(i64, 4)}; + +GEN_REMOVE_HOOK(cmp) + +size_t libafl_add_cmp_hook( + uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size), + void (*exec1)(uint64_t data, uint64_t id, uint8_t v0, uint8_t v1), + void (*exec2)(uint64_t data, uint64_t id, uint16_t v0, uint16_t v1), + void (*exec4)(uint64_t data, uint64_t id, uint32_t v0, uint32_t v1), + void (*exec8)(uint64_t data, uint64_t id, uint64_t v0, uint64_t v1), + uint64_t data) +{ + CPUState* cpu; + CPU_FOREACH(cpu) { tb_flush(cpu); } + + struct libafl_cmp_hook* hook = calloc(sizeof(struct libafl_cmp_hook), 1); + hook->gen = gen; + /*hook->exec1 = exec1; + hook->exec2 = exec2; + hook->exec4 = exec4; + hook->exec8 = exec8;*/ + hook->data = data; + hook->num = libafl_cmp_hooks_num++; + hook->next = libafl_cmp_hooks; + libafl_cmp_hooks = hook; + + if (exec1) { + memcpy(&hook->helper_info1, &libafl_exec_cmp_hook1_info, + sizeof(TCGHelperInfo)); + hook->helper_info1.func = exec1; + } + if (exec2) { + memcpy(&hook->helper_info2, &libafl_exec_cmp_hook2_info, + sizeof(TCGHelperInfo)); + hook->helper_info2.func = exec2; + } + if (exec4) { + memcpy(&hook->helper_info4, &libafl_exec_cmp_hook4_info, + sizeof(TCGHelperInfo)); + hook->helper_info4.func = exec4; + } + if (exec8) { + memcpy(&hook->helper_info8, &libafl_exec_cmp_hook8_info, + sizeof(TCGHelperInfo)); + hook->helper_info8.func = exec8; + } + + return hook->num; +} + +void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot) +{ + size_t size = 0; + switch (ot & MO_SIZE) { + case MO_64: + size = 8; + break; + case MO_32: + size = 4; + break; + case MO_16: + size = 2; + break; + case MO_8: + size = 1; + break; + default: + return; + } + + struct libafl_cmp_hook* hook = libafl_cmp_hooks; + while (hook) { + uint64_t cur_id = 0; + if (hook->gen) + cur_id = hook->gen(hook->data, pc, size); + TCGHelperInfo* info = NULL; + if (size == 1 && hook->helper_info1.func) + info = &hook->helper_info1; + else if (size == 2 && hook->helper_info2.func) + info = &hook->helper_info2; + else if (size == 4 && hook->helper_info4.func) + info = &hook->helper_info4; + else if (size == 8 && hook->helper_info8.func) + info = &hook->helper_info8; + if (cur_id != (uint64_t)-1 && info) { + TCGv_i64 tmp0 = tcg_constant_i64(hook->data); + TCGv_i64 tmp1 = tcg_constant_i64(cur_id); + TCGTemp* tmp2[4] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1), +#if TARGET_LONG_BITS == 32 + tcgv_i32_temp(op0), tcgv_i32_temp(op1)}; +#else + tcgv_i64_temp(op0), tcgv_i64_temp(op1)}; +#endif + tcg_gen_callN(info, NULL, tmp2); + tcg_temp_free_i64(tmp0); + tcg_temp_free_i64(tmp1); + } + hook = hook->next; + } +} diff --git a/libafl/hooks/tcg/edge.c b/libafl/hooks/tcg/edge.c new file mode 100644 index 0000000000..5ecdde3240 --- /dev/null +++ b/libafl/hooks/tcg/edge.c @@ -0,0 +1,89 @@ +#include "libafl/hooks/tcg/edge.h" + +struct libafl_edge_hook* libafl_edge_hooks; +size_t libafl_edge_hooks_num = 0; + +static TCGHelperInfo libafl_exec_edge_hook_info = { + .func = NULL, + .name = "libafl_exec_edge_hook", + .flags = dh_callflag(void), + .typemask = + dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2)}; + +GEN_REMOVE_HOOK(edge) + +size_t libafl_add_edge_hook(uint64_t (*gen)(uint64_t data, target_ulong src, + target_ulong dst), + void (*exec)(uint64_t data, uint64_t id), + uint64_t data) +{ + CPUState* cpu; + CPU_FOREACH(cpu) { tb_flush(cpu); } + + struct libafl_edge_hook* hook = calloc(sizeof(struct libafl_edge_hook), 1); + hook->gen = gen; + // hook->exec = exec; + hook->data = data; + hook->num = libafl_edge_hooks_num++; + hook->next = libafl_edge_hooks; + libafl_edge_hooks = hook; + + if (exec) { + memcpy(&hook->helper_info, &libafl_exec_edge_hook_info, + sizeof(TCGHelperInfo)); + hook->helper_info.func = exec; + } + + return hook->num; +} + +bool libafl_qemu_edge_hook_set_jit(size_t num, + size_t (*jit)(uint64_t data, uint64_t id)) +{ + struct libafl_edge_hook* hk = libafl_edge_hooks; + while (hk) { + if (hk->num == num) { + hk->jit = jit; + return true; + } else { + hk = hk->next; + } + } + return false; +} + +bool libafl_qemu_hook_edge_gen(target_ulong src_block, target_ulong dst_block) +{ + struct libafl_edge_hook* hook = libafl_edge_hooks; + bool no_exec_hook = true; + while (hook) { + hook->cur_id = 0; + if (hook->gen) + hook->cur_id = hook->gen(hook->data, src_block, dst_block); + if (hook->cur_id != (uint64_t)-1 && + (hook->helper_info.func || hook->jit)) + no_exec_hook = false; + hook = hook->next; + } + return no_exec_hook; +} + +void libafl_qemu_hook_edge_run(void) +{ + struct libafl_edge_hook* hook = libafl_edge_hooks; + + while (hook) { + if (hook->cur_id != (uint64_t)-1 && hook->helper_info.func) { + TCGv_i64 tmp0 = tcg_constant_i64(hook->data); + TCGv_i64 tmp1 = tcg_constant_i64(hook->cur_id); + TCGTemp* tmp2[2] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1)}; + tcg_gen_callN(&hook->helper_info, NULL, tmp2); + tcg_temp_free_i64(tmp0); + tcg_temp_free_i64(tmp1); + } + if (hook->cur_id != (uint64_t)-1 && hook->jit) { + hook->jit(hook->data, hook->cur_id); + } + hook = hook->next; + } +} diff --git a/libafl/hooks/tcg/instruction.c b/libafl/hooks/tcg/instruction.c new file mode 100644 index 0000000000..1e0fdbc650 --- /dev/null +++ b/libafl/hooks/tcg/instruction.c @@ -0,0 +1,133 @@ +#include "libafl/hooks/tcg/instruction.h" + +target_ulong libafl_gen_cur_pc; +struct libafl_instruction_hook* + libafl_qemu_instruction_hooks[LIBAFL_TABLES_SIZE]; +size_t libafl_qemu_hooks_num = 0; + +size_t libafl_qemu_add_instruction_hooks(target_ulong pc, + void (*callback)(uint64_t data, + target_ulong pc), + uint64_t + + data, + int invalidate) +{ + CPUState* cpu; + + if (invalidate) { + CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, pc); } + } + + size_t idx = LIBAFL_TABLES_HASH(pc); + + struct libafl_instruction_hook* hk = + calloc(sizeof(struct libafl_instruction_hook), 1); + hk->addr = pc; + // hk->callback = callback; + hk->data = data; + hk->helper_info.func = callback; + hk->helper_info.name = "libafl_instruction_hook"; + hk->helper_info.flags = dh_callflag(void); + hk->helper_info.typemask = + dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(tl, 2); + // TODO check for overflow + hk->num = libafl_qemu_hooks_num++; + hk->next = libafl_qemu_instruction_hooks[idx]; + libafl_qemu_instruction_hooks[idx] = hk; + return hk->num; +} + +size_t libafl_qemu_remove_instruction_hooks_at(target_ulong addr, + int invalidate) +{ + CPUState* cpu; + size_t r = 0; + + size_t idx = LIBAFL_TABLES_HASH(addr); + struct libafl_instruction_hook** hk = &libafl_qemu_instruction_hooks[idx]; + while (*hk) { + if ((*hk)->addr == addr) { + if (invalidate) { + CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, addr); } + } + + void* tmp = *hk; + *hk = (*hk)->next; + free(tmp); + r++; + } else { + hk = &(*hk)->next; + } + } + return r; +} + +int libafl_qemu_remove_instruction_hook(size_t num, int invalidate) +{ + CPUState* cpu; + size_t idx; + + for (idx = 0; idx < LIBAFL_TABLES_SIZE; ++idx) { + struct libafl_instruction_hook** hk = + &libafl_qemu_instruction_hooks[idx]; + while (*hk) { + if ((*hk)->num == num) { + if (invalidate) { + CPU_FOREACH(cpu) + { + libafl_breakpoint_invalidate(cpu, (*hk)->addr); + } + } + + void* tmp = *hk; + *hk = (*hk)->next; + free(tmp); + return 1; + } else { + hk = &(*hk)->next; + } + } + } + return 0; +} + +struct libafl_instruction_hook* +libafl_search_instruction_hook(target_ulong addr) +{ + size_t idx = LIBAFL_TABLES_HASH(addr); + + struct libafl_instruction_hook* hk = libafl_qemu_instruction_hooks[idx]; + while (hk) { + if (hk->addr == addr) { + return hk; + } + hk = hk->next; + } + + return NULL; +} + +void libafl_qemu_hook_instruction_run(vaddr pc_next) +{ + struct libafl_instruction_hook* hk = + libafl_search_instruction_hook(pc_next); + if (hk) { + TCGv_i64 tmp0 = tcg_constant_i64(hk->data); +#if TARGET_LONG_BITS == 32 + TCGv_i32 tmp1 = tcg_constant_i32(pc_next); + TCGTemp* tmp2[2] = {tcgv_i64_temp(tmp0), tcgv_i32_temp(tmp1)}; +#else + TCGv_i64 tmp1 = tcg_constant_i64(pc_next); + TCGTemp* tmp2[2] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1)}; +#endif + // tcg_gen_callN(hk->callback, NULL, 2, tmp2); + tcg_gen_callN(&hk->helper_info, NULL, tmp2); +#if TARGET_LONG_BITS == 32 + tcg_temp_free_i32(tmp1); +#else + tcg_temp_free_i64(tmp1); +#endif + tcg_temp_free_i64(tmp0); + } +} diff --git a/libafl/hooks/tcg/read_write.c b/libafl/hooks/tcg/read_write.c new file mode 100644 index 0000000000..e55894fb5b --- /dev/null +++ b/libafl/hooks/tcg/read_write.c @@ -0,0 +1,240 @@ +#include "libafl/hooks/tcg/read_write.h" + +struct libafl_rw_hook* libafl_read_hooks; +size_t libafl_read_hooks_num = 0; + +struct libafl_rw_hook* libafl_write_hooks; +size_t libafl_write_hooks_num = 0; + +static TCGHelperInfo libafl_exec_read_hook1_info = { + .func = NULL, + .name = "libafl_exec_read_hook1", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3)}; +static TCGHelperInfo libafl_exec_read_hook2_info = { + .func = NULL, + .name = "libafl_exec_read_hook2", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3)}; +static TCGHelperInfo libafl_exec_read_hook4_info = { + .func = NULL, + .name = "libafl_exec_read_hook4", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3)}; +static TCGHelperInfo libafl_exec_read_hook8_info = { + .func = NULL, + .name = "libafl_exec_read_hook8", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3)}; +static TCGHelperInfo libafl_exec_read_hookN_info = { + .func = NULL, + .name = "libafl_exec_read_hookN", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(i64, 4)}; +static TCGHelperInfo libafl_exec_write_hook1_info = { + .func = NULL, + .name = "libafl_exec_write_hook1", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3)}; +static TCGHelperInfo libafl_exec_write_hook2_info = { + .func = NULL, + .name = "libafl_exec_write_hook2", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3)}; +static TCGHelperInfo libafl_exec_write_hook4_info = { + .func = NULL, + .name = "libafl_exec_write_hook4", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3)}; +static TCGHelperInfo libafl_exec_write_hook8_info = { + .func = NULL, + .name = "libafl_exec_write_hook8", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3)}; +static TCGHelperInfo libafl_exec_write_hookN_info = { + .func = NULL, + .name = "libafl_exec_write_hookN", + .flags = dh_callflag(void), + .typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | + dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(i64, 4)}; + +GEN_REMOVE_HOOK(read) + +GEN_REMOVE_HOOK(write) + +size_t libafl_add_read_hook( + uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi), + void (*exec1)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec2)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec4)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec8)(uint64_t data, uint64_t id, target_ulong addr), + void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size), + uint64_t data) +{ + CPUState* cpu; + CPU_FOREACH(cpu) { tb_flush(cpu); } + + struct libafl_rw_hook* hook = calloc(sizeof(struct libafl_rw_hook), 1); + hook->gen = gen; + /*hook->exec1 = exec1; + hook->exec2 = exec2; + hook->exec4 = exec4; + hook->exec8 = exec8; + hook->execN = execN;*/ + hook->data = data; + hook->num = libafl_read_hooks_num++; + hook->next = libafl_read_hooks; + libafl_read_hooks = hook; + + if (exec1) { + memcpy(&hook->helper_info1, &libafl_exec_read_hook1_info, + sizeof(TCGHelperInfo)); + hook->helper_info1.func = exec1; + } + if (exec2) { + memcpy(&hook->helper_info2, &libafl_exec_read_hook2_info, + sizeof(TCGHelperInfo)); + hook->helper_info2.func = exec2; + } + if (exec4) { + memcpy(&hook->helper_info4, &libafl_exec_read_hook4_info, + sizeof(TCGHelperInfo)); + hook->helper_info4.func = exec4; + } + if (exec8) { + memcpy(&hook->helper_info8, &libafl_exec_read_hook8_info, + sizeof(TCGHelperInfo)); + hook->helper_info8.func = exec8; + } + if (execN) { + memcpy(&hook->helper_infoN, &libafl_exec_read_hookN_info, + sizeof(TCGHelperInfo)); + hook->helper_infoN.func = execN; + } + + return hook->num; +} + +size_t libafl_add_write_hook( + uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi), + void (*exec1)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec2)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec4)(uint64_t data, uint64_t id, target_ulong addr), + void (*exec8)(uint64_t data, uint64_t id, target_ulong addr), + void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size), + uint64_t data) +{ + CPUState* cpu; + CPU_FOREACH(cpu) { tb_flush(cpu); } + + struct libafl_rw_hook* hook = calloc(sizeof(struct libafl_rw_hook), 1); + hook->gen = gen; + /*hook->exec1 = exec1; + hook->exec2 = exec2; + hook->exec4 = exec4; + hook->exec8 = exec8; + hook->execN = execN;*/ + hook->data = data; + hook->num = libafl_write_hooks_num++; + hook->next = libafl_write_hooks; + libafl_write_hooks = hook; + + if (exec1) { + memcpy(&hook->helper_info1, &libafl_exec_write_hook1_info, + sizeof(TCGHelperInfo)); + hook->helper_info1.func = exec1; + } + if (exec2) { + memcpy(&hook->helper_info2, &libafl_exec_write_hook2_info, + sizeof(TCGHelperInfo)); + hook->helper_info2.func = exec2; + } + if (exec4) { + memcpy(&hook->helper_info4, &libafl_exec_write_hook4_info, + sizeof(TCGHelperInfo)); + hook->helper_info4.func = exec4; + } + if (exec8) { + memcpy(&hook->helper_info8, &libafl_exec_write_hook8_info, + sizeof(TCGHelperInfo)); + hook->helper_info8.func = exec8; + } + if (execN) { + memcpy(&hook->helper_infoN, &libafl_exec_write_hookN_info, + sizeof(TCGHelperInfo)); + hook->helper_infoN.func = execN; + } + + return hook->num; +} + +static void libafl_gen_rw(TCGTemp* addr, MemOpIdx oi, + struct libafl_rw_hook* hook) +{ + size_t size = memop_size(get_memop(oi)); + + while (hook) { + uint64_t cur_id = 0; + if (hook->gen) + cur_id = hook->gen(hook->data, libafl_gen_cur_pc, addr, oi); + TCGHelperInfo* info = NULL; + if (size == 1 && hook->helper_info1.func) + info = &hook->helper_info1; + else if (size == 2 && hook->helper_info2.func) + info = &hook->helper_info2; + else if (size == 4 && hook->helper_info4.func) + info = &hook->helper_info4; + else if (size == 8 && hook->helper_info8.func) + info = &hook->helper_info8; + if (cur_id != (uint64_t)-1) { + if (info) { + TCGv_i64 tmp0 = tcg_constant_i64(hook->data); + TCGv_i64 tmp1 = tcg_constant_i64(cur_id); + TCGTemp* tmp2[3] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1), + addr}; + tcg_gen_callN(info, NULL, tmp2); + tcg_temp_free_i64(tmp0); + tcg_temp_free_i64(tmp1); + } else if (hook->helper_infoN.func) { + TCGv_i64 tmp0 = tcg_constant_i64(hook->data); + TCGv_i64 tmp1 = tcg_constant_i64(cur_id); + TCGv tmp2 = tcg_constant_tl(size); + TCGTemp* tmp3[4] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1), + addr, +#if TARGET_LONG_BITS == 32 + tcgv_i32_temp(tmp2)}; +#else + tcgv_i64_temp(tmp2)}; +#endif + tcg_gen_callN(&hook->helper_infoN, NULL, tmp3); + tcg_temp_free_i64(tmp0); + tcg_temp_free_i64(tmp1); +#if TARGET_LONG_BITS == 32 + tcg_temp_free_i32(tmp2); +#else + tcg_temp_free_i64(tmp2); +#endif + } + } + hook = hook->next; + } +} + +void libafl_gen_read(TCGTemp* addr, MemOpIdx oi) +{ + libafl_gen_rw(addr, oi, libafl_read_hooks); +} + +void libafl_gen_write(TCGTemp* addr, MemOpIdx oi) +{ + libafl_gen_rw(addr, oi, libafl_write_hooks); +} diff --git a/libafl/hooks/thread.c b/libafl/hooks/thread.c new file mode 100644 index 0000000000..bc5f19e668 --- /dev/null +++ b/libafl/hooks/thread.c @@ -0,0 +1,47 @@ +#include "libafl/hooks/thread.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; + +GEN_REMOVE_HOOK1(new_thread) + +size_t libafl_add_new_thread_hook(bool (*callback)(uint64_t data, + CPUArchState* env, + uint32_t tid), + uint64_t data) +{ + struct libafl_new_thread_hook* hook = + calloc(sizeof(struct libafl_new_thread_hook), 1); + hook->callback = callback; + hook->data = data; + hook->num = libafl_new_thread_hooks_num++; + hook->next = libafl_new_thread_hooks; + libafl_new_thread_hooks = hook; + + return hook->num; +} + +bool libafl_hook_new_thread_run(CPUArchState* env) +{ + libafl_qemu_env = env; + + if (libafl_new_thread_hooks) { + bool continue_execution = true; + int tid = gettid(); + + struct libafl_new_thread_hook* h = libafl_new_thread_hooks; + while (h) { + continue_execution = + h->callback(h->data, env, tid) && continue_execution; + h = h->next; + } + + return continue_execution; + } + + return true; +} diff --git a/libafl/jit.c b/libafl/jit.c index 9e4dc8e9eb..cd6b7f71fe 100644 --- a/libafl/jit.c +++ b/libafl/jit.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" + #include "qapi/error.h" #include "exec/exec-all.h" @@ -26,9 +27,10 @@ pub extern "C" fn trace_edge_single(id: u64, _data: u64) { // from libafl_targets coverage.rs // correct size doesn't matter here uint8_t __afl_area_ptr_local[65536] __attribute__((weak)); -size_t __afl_map_size __attribute__((weak)); +size_t __afl_map_size __attribute__((weak)); -size_t libafl_jit_trace_edge_hitcount(uint64_t data, uint64_t id) { +size_t libafl_jit_trace_edge_hitcount(uint64_t data, uint64_t id) +{ TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local); TCGv_i32 counter = tcg_temp_new_i32(); tcg_gen_ld8u_i32(counter, map_ptr, (tcg_target_long)id); @@ -37,7 +39,8 @@ size_t libafl_jit_trace_edge_hitcount(uint64_t data, uint64_t id) { return 3; // # instructions } -size_t libafl_jit_trace_edge_single(uint64_t data, uint64_t id) { +size_t libafl_jit_trace_edge_single(uint64_t data, uint64_t id) +{ TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local); TCGv_i32 counter = tcg_temp_new_i32(); tcg_gen_movi_i32(counter, 1); @@ -47,7 +50,8 @@ size_t libafl_jit_trace_edge_single(uint64_t data, uint64_t id) { uint64_t __prev_loc = 0; -size_t libafl_jit_trace_block_hitcount(uint64_t data, uint64_t id) { +size_t libafl_jit_trace_block_hitcount(uint64_t data, uint64_t id) +{ TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local); TCGv_ptr prev_loc_ptr = tcg_constant_ptr(&__prev_loc); @@ -58,8 +62,8 @@ size_t libafl_jit_trace_block_hitcount(uint64_t data, uint64_t id) { // Compute location => 5 insn tcg_gen_ld_i64(prev_loc, prev_loc_ptr, 0); - tcg_gen_xori_i64(prev_loc, prev_loc, (int64_t) id); - tcg_gen_andi_i64(prev_loc, prev_loc, (int64_t) (__afl_map_size - 1)); + tcg_gen_xori_i64(prev_loc, prev_loc, (int64_t)id); + tcg_gen_andi_i64(prev_loc, prev_loc, (int64_t)(__afl_map_size - 1)); tcg_gen_trunc_i64_ptr(prev_loc2, prev_loc); tcg_gen_add_ptr(prev_loc2, map_ptr, prev_loc2); @@ -69,13 +73,14 @@ size_t libafl_jit_trace_block_hitcount(uint64_t data, uint64_t id) { tcg_gen_st8_i32(counter, prev_loc2, 0); // Update prev_loc => 3 insn - tcg_gen_movi_i64(id_r, (int64_t) id); + tcg_gen_movi_i64(id_r, (int64_t)id); tcg_gen_shri_i64(id_r, id_r, 1); tcg_gen_st_i64(id_r, prev_loc_ptr, 0); return 11; // # instructions } -size_t libafl_jit_trace_block_single(uint64_t data, uint64_t id) { +size_t libafl_jit_trace_block_single(uint64_t data, uint64_t id) +{ TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local); TCGv_ptr prev_loc_ptr = tcg_constant_ptr(&__prev_loc); @@ -86,8 +91,8 @@ size_t libafl_jit_trace_block_single(uint64_t data, uint64_t id) { // Compute location => 5 insn tcg_gen_ld_i64(prev_loc, prev_loc_ptr, 0); - tcg_gen_xori_i64(prev_loc, prev_loc, (int64_t) id); - tcg_gen_andi_i64(prev_loc, prev_loc, (int64_t) (__afl_map_size - 1)); + tcg_gen_xori_i64(prev_loc, prev_loc, (int64_t)id); + tcg_gen_andi_i64(prev_loc, prev_loc, (int64_t)(__afl_map_size - 1)); tcg_gen_trunc_i64_ptr(prev_loc2, prev_loc); tcg_gen_add_ptr(map_ptr, map_ptr, prev_loc2); @@ -96,7 +101,7 @@ size_t libafl_jit_trace_block_single(uint64_t data, uint64_t id) { tcg_gen_st8_i32(counter, map_ptr, 0); // Update prev_loc => 3 insn - tcg_gen_movi_i64(id_r, (int64_t) id); + tcg_gen_movi_i64(id_r, (int64_t)id); tcg_gen_shri_i64(id_r, id_r, 1); tcg_gen_st_i64(id_r, prev_loc_ptr, 0); return 10; // # instructions diff --git a/libafl/meson.build b/libafl/meson.build index 938dfa41a7..9db973199e 100644 --- a/libafl/meson.build +++ b/libafl/meson.build @@ -1,14 +1,30 @@ specific_ss.add(files( - 'exit.c', - 'hook.c', - 'jit.c', - 'utils.c', -)) + 'exit.c', + 'hook.c', + 'jit.c', + 'utils.c', -specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files( - 'syx-snapshot/device-save.c', - 'syx-snapshot/syx-snapshot.c', - 'syx-snapshot/syx-cow-cache.c', - 'syx-snapshot/channel-buffer-writeback.c', -)]) + # TCG-related hooks + 'hooks/tcg/backdoor.c', + 'hooks/tcg/block.c', + 'hooks/tcg/cmp.c', + 'hooks/tcg/edge.c', + 'hooks/tcg/instruction.c', + 'hooks/tcg/read_write.c', + + # General hooks + 'hooks/cpu_run.c', + )) + +specific_ss.add(when : 'CONFIG_SOFTMMU', if_true : [files( + 'syx-snapshot/device-save.c', + 'syx-snapshot/syx-snapshot.c', + 'syx-snapshot/syx-cow-cache.c', + 'syx-snapshot/channel-buffer-writeback.c', + )]) + +specific_ss.add(when : 'CONFIG_USER_ONLY', if_true : [files( + 'hooks/syscall.c', + 'hooks/thread.c', + )]) diff --git a/libafl/syx-snapshot/channel-buffer-writeback.c b/libafl/syx-snapshot/channel-buffer-writeback.c index 3fc659f60d..c2b1c1c800 100644 --- a/libafl/syx-snapshot/channel-buffer-writeback.c +++ b/libafl/syx-snapshot/channel-buffer-writeback.c @@ -4,13 +4,18 @@ #include "libafl/syx-misc.h" #include "libafl/syx-snapshot/channel-buffer-writeback.h" -QIOChannelBufferWriteback* qio_channel_buffer_writeback_new(size_t capacity, uint8_t* writeback_buf, size_t writeback_buf_capacity, size_t* writeback_buf_usage) { +QIOChannelBufferWriteback* +qio_channel_buffer_writeback_new(size_t capacity, uint8_t* writeback_buf, + size_t writeback_buf_capacity, + size_t* writeback_buf_usage) +{ assert(writeback_buf != NULL); assert(writeback_buf_usage != NULL); - QIOChannelBufferWriteback *ioc; + QIOChannelBufferWriteback* ioc; - ioc = QIO_CHANNEL_BUFFER_WRITEBACK(object_new(TYPE_QIO_CHANNEL_BUFFER_WRITEBACK)); + ioc = QIO_CHANNEL_BUFFER_WRITEBACK( + object_new(TYPE_QIO_CHANNEL_BUFFER_WRITEBACK)); assert(writeback_buf != NULL); @@ -27,16 +32,19 @@ QIOChannelBufferWriteback* qio_channel_buffer_writeback_new(size_t capacity, uin return ioc; } -QIOChannelBufferWriteback* -qio_channel_buffer_writeback_new_external(uint8_t* buf, size_t capacity, size_t usage, uint8_t* writeback_buf, size_t writeback_buf_capacity, size_t* writeback_buf_usage) { +QIOChannelBufferWriteback* qio_channel_buffer_writeback_new_external( + uint8_t* buf, size_t capacity, size_t usage, uint8_t* writeback_buf, + size_t writeback_buf_capacity, size_t* writeback_buf_usage) +{ assert(buf != NULL); assert(usage <= capacity); assert(writeback_buf != NULL); assert(writeback_buf_usage != NULL); - QIOChannelBufferWriteback *ioc; + QIOChannelBufferWriteback* ioc; - ioc = QIO_CHANNEL_BUFFER_WRITEBACK(object_new(TYPE_QIO_CHANNEL_BUFFER_WRITEBACK)); + ioc = QIO_CHANNEL_BUFFER_WRITEBACK( + object_new(TYPE_QIO_CHANNEL_BUFFER_WRITEBACK)); assert(writeback_buf != NULL); @@ -52,8 +60,8 @@ qio_channel_buffer_writeback_new_external(uint8_t* buf, size_t capacity, size_t return ioc; } - -static void qio_channel_buffer_writeback_finalize(Object *obj) { +static void qio_channel_buffer_writeback_finalize(Object* obj) +{ QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(obj); assert(bwioc->writeback_buf_capacity >= bwioc->usage); @@ -70,14 +78,11 @@ static void qio_channel_buffer_writeback_finalize(Object *obj) { } } - -static ssize_t qio_channel_buffer_writeback_readv(QIOChannel *ioc, - const struct iovec *iov, - size_t niov, - int **fds, - size_t *nfds, - int flags, - Error **errp) +static ssize_t qio_channel_buffer_writeback_readv(QIOChannel* ioc, + const struct iovec* iov, + size_t niov, int** fds, + size_t* nfds, int flags, + Error** errp) { QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc); ssize_t ret = 0; @@ -90,7 +95,7 @@ static ssize_t qio_channel_buffer_writeback_readv(QIOChannel *ioc, break; } - if ((bwioc->offset + want) > bwioc->usage) { + if ((bwioc->offset + want) > bwioc->usage) { want = bwioc->usage - bwioc->offset; } @@ -103,12 +108,10 @@ static ssize_t qio_channel_buffer_writeback_readv(QIOChannel *ioc, } static ssize_t qio_channel_buffer_writeback_writev(QIOChannel* ioc, - const struct iovec *iov, - size_t niov, - int *fds, - size_t nfds, - int flags, - Error **errp) + const struct iovec* iov, + size_t niov, int* fds, + size_t nfds, int flags, + Error** errp) { QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc); ssize_t ret = 0; @@ -123,9 +126,7 @@ static ssize_t qio_channel_buffer_writeback_writev(QIOChannel* ioc, assert(bwioc->offset <= bwioc->usage); for (i = 0; i < niov; i++) { - memcpy(bwioc->data + bwioc->offset, - iov[i].iov_base, - iov[i].iov_len); + memcpy(bwioc->data + bwioc->offset, iov[i].iov_base, iov[i].iov_len); bwioc->offset += iov[i].iov_len; bwioc->usage += iov[i].iov_len; ret += iov[i].iov_len; @@ -134,33 +135,32 @@ static ssize_t qio_channel_buffer_writeback_writev(QIOChannel* ioc, return ret; } -static int qio_channel_buffer_writeback_set_blocking(QIOChannel *ioc G_GNUC_UNUSED, - bool enabled G_GNUC_UNUSED, - Error **errp G_GNUC_UNUSED) +static int +qio_channel_buffer_writeback_set_blocking(QIOChannel* ioc G_GNUC_UNUSED, + bool enabled G_GNUC_UNUSED, + Error** errp G_GNUC_UNUSED) { return 0; } -static off_t qio_channel_buffer_writeback_seek(QIOChannel *ioc, - off_t offset, - int whence, - Error **errp) +static off_t qio_channel_buffer_writeback_seek(QIOChannel* ioc, off_t offset, + int whence, Error** errp) { - QIOChannelBufferWriteback *bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc); + QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc); off_t new_pos; - switch(whence) { - case SEEK_SET: - new_pos = offset; - break; - case SEEK_CUR: - new_pos = (off_t) bwioc->offset + offset; - break; - case SEEK_END: - new_pos = (off_t) bwioc->usage + offset; - break; - default: - assert(false); + switch (whence) { + case SEEK_SET: + new_pos = offset; + break; + case SEEK_CUR: + new_pos = (off_t)bwioc->offset + offset; + break; + case SEEK_END: + new_pos = (off_t)bwioc->usage + offset; + break; + default: + assert(false); } assert(new_pos >= 0 && new_pos <= bwioc->usage); @@ -170,8 +170,7 @@ static off_t qio_channel_buffer_writeback_seek(QIOChannel *ioc, return new_pos; } -static int qio_channel_buffer_writeback_close(QIOChannel *ioc, - Error **errp) +static int qio_channel_buffer_writeback_close(QIOChannel* ioc, Error** errp) { QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc); @@ -194,67 +193,65 @@ static int qio_channel_buffer_writeback_close(QIOChannel *ioc, typedef struct QIOChannelBufferWritebackSource QIOChannelBufferWritebackSource; struct QIOChannelBufferWritebackSource { GSource parent; - QIOChannelBufferWriteback *bioc; + QIOChannelBufferWriteback* bioc; GIOCondition condition; }; -static gboolean -qio_channel_buffer_writeback_source_prepare(GSource *source, - gint *timeout) +static gboolean qio_channel_buffer_writeback_source_prepare(GSource* source, + gint* timeout) { - QIOChannelBufferWritebackSource *bsource = (QIOChannelBufferWritebackSource *)source; + QIOChannelBufferWritebackSource* bsource = + (QIOChannelBufferWritebackSource*)source; *timeout = -1; return (G_IO_IN | G_IO_OUT) & bsource->condition; } -static gboolean -qio_channel_buffer_writeback_source_check(GSource *source) +static gboolean qio_channel_buffer_writeback_source_check(GSource* source) { - QIOChannelBufferWritebackSource *bsource = (QIOChannelBufferWritebackSource *)source; + QIOChannelBufferWritebackSource* bsource = + (QIOChannelBufferWritebackSource*)source; return (G_IO_IN | G_IO_OUT) & bsource->condition; } -static gboolean -qio_channel_buffer_writeback_source_dispatch(GSource *source, - GSourceFunc callback, - gpointer user_data) +static gboolean qio_channel_buffer_writeback_source_dispatch( + GSource* source, GSourceFunc callback, gpointer user_data) { QIOChannelFunc func = (QIOChannelFunc)callback; - QIOChannelBufferWritebackSource *bsource = (QIOChannelBufferWritebackSource *)source; + QIOChannelBufferWritebackSource* bsource = + (QIOChannelBufferWritebackSource*)source; return (*func)(QIO_CHANNEL(bsource->bioc), - ((G_IO_IN | G_IO_OUT) & bsource->condition), - user_data); + ((G_IO_IN | G_IO_OUT) & bsource->condition), user_data); } -static void -qio_channel_buffer_writeback_source_finalize(GSource *source) +static void qio_channel_buffer_writeback_source_finalize(GSource* source) { - QIOChannelBufferWritebackSource *ssource = (QIOChannelBufferWritebackSource *)source; + QIOChannelBufferWritebackSource* ssource = + (QIOChannelBufferWritebackSource*)source; object_unref(OBJECT(ssource->bioc)); } GSourceFuncs qio_channel_buffer_writeback_source_funcs = { - qio_channel_buffer_writeback_source_prepare, - qio_channel_buffer_writeback_source_check, - qio_channel_buffer_writeback_source_dispatch, - qio_channel_buffer_writeback_source_finalize -}; + qio_channel_buffer_writeback_source_prepare, + qio_channel_buffer_writeback_source_check, + qio_channel_buffer_writeback_source_dispatch, + qio_channel_buffer_writeback_source_finalize}; -static GSource *qio_channel_buffer_writeback_create_watch(QIOChannel *ioc, - GIOCondition condition) +static GSource* +qio_channel_buffer_writeback_create_watch(QIOChannel* ioc, + GIOCondition condition) { - QIOChannelBufferWriteback *bioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc); - QIOChannelBufferWritebackSource *ssource; - GSource *source; + QIOChannelBufferWriteback* bioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc); + QIOChannelBufferWritebackSource* ssource; + GSource* source; source = g_source_new(&qio_channel_buffer_writeback_source_funcs, sizeof(QIOChannelBufferWritebackSource)); - ssource = (QIOChannelBufferWritebackSource *)source; + ssource = (QIOChannelBufferWritebackSource*)source; ssource->bioc = bioc; object_ref(OBJECT(bioc)); @@ -264,10 +261,11 @@ static GSource *qio_channel_buffer_writeback_create_watch(QIOChannel *ioc, return source; } -static void qio_channel_buffer_writeback_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) +static void +qio_channel_buffer_writeback_class_init(ObjectClass* klass, + void* class_data G_GNUC_UNUSED) { - QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); + QIOChannelClass* ioc_klass = QIO_CHANNEL_CLASS(klass); ioc_klass->io_writev = qio_channel_buffer_writeback_writev; ioc_klass->io_readv = qio_channel_buffer_writeback_readv; @@ -278,11 +276,11 @@ static void qio_channel_buffer_writeback_class_init(ObjectClass *klass, } static const TypeInfo qio_channel_buffer_writeback_info = { - .parent = TYPE_QIO_CHANNEL, - .name = TYPE_QIO_CHANNEL_BUFFER_WRITEBACK, - .instance_size = sizeof(QIOChannelBufferWriteback), - .instance_finalize = qio_channel_buffer_writeback_finalize, - .class_init = qio_channel_buffer_writeback_class_init, + .parent = TYPE_QIO_CHANNEL, + .name = TYPE_QIO_CHANNEL_BUFFER_WRITEBACK, + .instance_size = sizeof(QIOChannelBufferWriteback), + .instance_finalize = qio_channel_buffer_writeback_finalize, + .class_init = qio_channel_buffer_writeback_class_init, }; static void qio_channel_buffer_writeback_register_types(void) diff --git a/libafl/syx-snapshot/device-save.c b/libafl/syx-snapshot/device-save.c index 2df2442761..53140ec31d 100644 --- a/libafl/syx-snapshot/device-save.c +++ b/libafl/syx-snapshot/device-save.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" + #include "migration/qemu-file.h" #include "io/channel-buffer.h" #include "migration/vmstate.h" @@ -14,14 +15,16 @@ int libafl_restoring_devices; extern SaveState savevm_state; -extern int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc); +extern int vmstate_save(QEMUFile* f, SaveStateEntry* se, JSONWriter* vmdesc); // iothread must be locked -DeviceSaveState* device_save_all(void) { +DeviceSaveState* device_save_all(void) +{ return device_save_kind(DEVICE_SNAPSHOT_ALL, NULL); } -static int is_in_list(char* str, char** list) { +static int is_in_list(char* str, char** list) +{ while (*list) { if (!strcmp(str, *list)) { return 1; @@ -31,19 +34,23 @@ static int is_in_list(char* str, char** list) { return 0; } -DeviceSaveState* device_save_kind(DeviceSnapshotKind kind, char** names) { +DeviceSaveState* device_save_kind(DeviceSnapshotKind kind, char** names) +{ DeviceSaveState* dss = g_new0(DeviceSaveState, 1); - SaveStateEntry *se; + SaveStateEntry* se; dss->kind = DEVICE_SAVE_KIND_FULL; dss->save_buffer = g_new(uint8_t, QEMU_FILE_RAM_LIMIT); - QIOChannelBufferWriteback* wbioc = qio_channel_buffer_writeback_new(QEMU_FILE_RAM_LIMIT, dss->save_buffer, QEMU_FILE_RAM_LIMIT, &dss->save_buffer_size); + QIOChannelBufferWriteback* wbioc = qio_channel_buffer_writeback_new( + QEMU_FILE_RAM_LIMIT, dss->save_buffer, QEMU_FILE_RAM_LIMIT, + &dss->save_buffer_size); QIOChannel* ioc = QIO_CHANNEL(wbioc); QEMUFile* f = qemu_file_new_output(ioc); - - QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { + + QTAILQ_FOREACH(se, &savevm_state.handlers, entry) + { int ret; if (se->is_ram) { @@ -53,18 +60,18 @@ DeviceSaveState* device_save_kind(DeviceSnapshotKind kind, char** names) { continue; } switch (kind) { - case DEVICE_SNAPSHOT_ALLOWLIST: - if (!is_in_list(se->idstr, names)) { - continue; - } - break; - case DEVICE_SNAPSHOT_DENYLIST: - if (is_in_list(se->idstr, names)) { - continue; - } - break; - default: - break; + case DEVICE_SNAPSHOT_ALLOWLIST: + if (!is_in_list(se->idstr, names)) { + continue; + } + break; + case DEVICE_SNAPSHOT_DENYLIST: + if (is_in_list(se->idstr, names)) { + continue; + } + break; + default: + break; } // SYX_PRINTF("Saving section %s...\n", se->idstr); @@ -84,51 +91,51 @@ DeviceSaveState* device_save_kind(DeviceSnapshotKind kind, char** names) { return dss; } -void device_restore_all(DeviceSaveState* dss) { +void device_restore_all(DeviceSaveState* dss) +{ assert(dss->save_buffer != NULL); - QIOChannelBuffer* bioc = qio_channel_buffer_new_external(dss->save_buffer, QEMU_FILE_RAM_LIMIT, dss->save_buffer_size); + QIOChannelBuffer* bioc = qio_channel_buffer_new_external( + dss->save_buffer, QEMU_FILE_RAM_LIMIT, dss->save_buffer_size); QIOChannel* ioc = QIO_CHANNEL(bioc); QEMUFile* f = qemu_file_new_input(ioc); - + int save_libafl_restoring_devices = libafl_restoring_devices; - libafl_restoring_devices = 1; - + libafl_restoring_devices = 1; + qemu_load_device_state(f); - + libafl_restoring_devices = save_libafl_restoring_devices; object_unref(OBJECT(bioc)); qemu_fclose(f); } -void device_free_all(DeviceSaveState* dss) { - g_free(dss->save_buffer); -} +void device_free_all(DeviceSaveState* dss) { g_free(dss->save_buffer); } + +char** device_list_all(void) +{ + SaveStateEntry* se; -char** device_list_all(void) { - SaveStateEntry *se; - size_t size = 1; - QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { - size++; - } - + QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { size++; } + char** list = malloc(size * sizeof(char*)); size_t i = 0; - QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { + QTAILQ_FOREACH(se, &savevm_state.handlers, entry) + { if (se->is_ram) { continue; } if (!strcmp(se->idstr, "globalstate")) { continue; } - + list[i] = se->idstr; i++; } list[i] = NULL; - + return list; } diff --git a/libafl/syx-snapshot/syx-cow-cache.c b/libafl/syx-snapshot/syx-cow-cache.c index 3628c46ceb..10f5de0fe2 100644 --- a/libafl/syx-snapshot/syx-cow-cache.c +++ b/libafl/syx-snapshot/syx-cow-cache.c @@ -19,11 +19,13 @@ static gchar* g_array_element_ptr(GArray* array, guint position) return array->data + position * g_array_get_element_size(array); } -void syx_cow_cache_push_layer(SyxCowCache* scc, uint64_t chunk_size, uint64_t max_size) +void syx_cow_cache_push_layer(SyxCowCache* scc, uint64_t chunk_size, + uint64_t max_size) { SyxCowCacheLayer* new_layer = g_new0(SyxCowCacheLayer, 1); - new_layer->cow_cache_devices = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); + new_layer->cow_cache_devices = + g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); new_layer->chunk_size = chunk_size; new_layer->max_nb_chunks = max_size; @@ -38,9 +40,10 @@ void syx_cow_cache_pop_layer(SyxCowCache* scc) // TODO } -static void flush_device_layer(gpointer _blk_name_hash, gpointer cache_device, gpointer _user_data) +static void flush_device_layer(gpointer _blk_name_hash, gpointer cache_device, + gpointer _user_data) { - SyxCowCacheDevice* sccd = (SyxCowCacheDevice*) cache_device; + SyxCowCacheDevice* sccd = (SyxCowCacheDevice*)cache_device; g_hash_table_remove_all(sccd->positions); g_array_set_size(sccd->data, 0); @@ -51,7 +54,8 @@ void syx_cow_cache_flush_highest_layer(SyxCowCache* scc) SyxCowCacheLayer* highest_layer = QTAILQ_FIRST(&scc->layers); // highest_layer->cow_cache_devices - g_hash_table_foreach(highest_layer->cow_cache_devices, flush_device_layer, NULL); + g_hash_table_foreach(highest_layer->cow_cache_devices, flush_device_layer, + NULL); } void syx_cow_cache_move(SyxCowCache* lhs, SyxCowCache** rhs) @@ -61,22 +65,30 @@ void syx_cow_cache_move(SyxCowCache* lhs, SyxCowCache** rhs) *rhs = NULL; } -static bool read_chunk_from_cache_layer_device(SyxCowCacheDevice* sccd, QEMUIOVector* qiov, size_t qiov_offset, uint64_t blk_offset) +static bool read_chunk_from_cache_layer_device(SyxCowCacheDevice* sccd, + QEMUIOVector* qiov, + size_t qiov_offset, + uint64_t blk_offset) { gpointer data_position = NULL; - bool found = g_hash_table_lookup_extended(sccd->positions, GUINT_TO_POINTER(blk_offset), NULL, &data_position); + bool found = g_hash_table_lookup_extended( + sccd->positions, GUINT_TO_POINTER(blk_offset), NULL, &data_position); // cache hit if (found) { - void* data_position_ptr = g_array_element_ptr(sccd->data, GPOINTER_TO_UINT(data_position)); - assert(qemu_iovec_from_buf(qiov, qiov_offset, data_position_ptr, g_array_get_element_size(sccd->data)) == g_array_get_element_size(sccd->data)); + void* data_position_ptr = + g_array_element_ptr(sccd->data, GPOINTER_TO_UINT(data_position)); + assert(qemu_iovec_from_buf(qiov, qiov_offset, data_position_ptr, + g_array_get_element_size(sccd->data)) == + g_array_get_element_size(sccd->data)); } return found; } // len must be smaller than nb bytes to next aligned to chunk of blk_offset. -// static void write_to_cache_layer_device_unaligned(SyxCowCacheDevice* sccd, QEMUIOVector* qiov, size_t qiov_offset, uint64_t blk_offset, uint64_t len) +// static void write_to_cache_layer_device_unaligned(SyxCowCacheDevice* sccd, +// QEMUIOVector* qiov, size_t qiov_offset, uint64_t blk_offset, uint64_t len) // { // const uint64_t chunk_size = g_array_get_element_size(sccd->data); // @@ -86,45 +98,58 @@ static bool read_chunk_from_cache_layer_device(SyxCowCacheDevice* sccd, QEMUIOVe // uint64_t blk_offset_aligned = ROUND_DOWN(blk_offset, chunk_size); // // gpointer data_position = NULL; -// bool found = g_hash_table_lookup_extended(sccd->positions, GUINT_TO_POINTER(blk_offset_aligned), NULL, &data_position); +// bool found = g_hash_table_lookup_extended(sccd->positions, +// GUINT_TO_POINTER(blk_offset_aligned), NULL, &data_position); // // if (!found) { // data_position = GUINT_TO_POINTER(sccd->data->len); // sccd->data = g_array_set_size(sccd->data, sccd->data->len + 1); -// g_hash_table_insert(sccd->positions, GUINT_TO_POINTER(blk_offset), data_position); +// g_hash_table_insert(sccd->positions, GUINT_TO_POINTER(blk_offset), +// data_position); // } // -// void* data_position_ptr = g_array_element_ptr(sccd->data, GPOINTER_TO_UINT(data_position)); +// void* data_position_ptr = g_array_element_ptr(sccd->data, +// GPOINTER_TO_UINT(data_position)); // -// assert(qemu_iovec_to_buf(qiov, qiov_offset, data_position_ptr, g_array_get_element_size(sccd->data)) == +// assert(qemu_iovec_to_buf(qiov, qiov_offset, data_position_ptr, +// g_array_get_element_size(sccd->data)) == // g_array_get_element_size(sccd->data)); // } // cache layer is allocated and all the basic checks are already done. -static void write_chunk_to_cache_layer_device(SyxCowCacheDevice* sccd, QEMUIOVector* qiov, size_t qiov_offset, uint64_t blk_offset) +static void write_chunk_to_cache_layer_device(SyxCowCacheDevice* sccd, + QEMUIOVector* qiov, + size_t qiov_offset, + uint64_t blk_offset) { const uint64_t chunk_size = g_array_get_element_size(sccd->data); gpointer data_position = NULL; - bool found = g_hash_table_lookup_extended(sccd->positions, GUINT_TO_POINTER(blk_offset), NULL, &data_position); + bool found = g_hash_table_lookup_extended( + sccd->positions, GUINT_TO_POINTER(blk_offset), NULL, &data_position); if (!found) { data_position = GUINT_TO_POINTER(sccd->data->len); sccd->data = g_array_set_size(sccd->data, sccd->data->len + 1); - g_hash_table_insert(sccd->positions, GUINT_TO_POINTER(blk_offset), data_position); + g_hash_table_insert(sccd->positions, GUINT_TO_POINTER(blk_offset), + data_position); } - void* data_position_ptr = g_array_element_ptr(sccd->data, GPOINTER_TO_UINT(data_position)); + void* data_position_ptr = + g_array_element_ptr(sccd->data, GPOINTER_TO_UINT(data_position)); - assert(qemu_iovec_to_buf(qiov, qiov_offset, data_position_ptr, chunk_size) == - chunk_size); + assert(qemu_iovec_to_buf(qiov, qiov_offset, data_position_ptr, + chunk_size) == chunk_size); } -static bool read_chunk_from_cache_layer(SyxCowCacheLayer* sccl, BlockBackend* blk, QEMUIOVector* qiov, size_t qiov_offset, uint64_t blk_offset) +static bool read_chunk_from_cache_layer(SyxCowCacheLayer* sccl, + BlockBackend* blk, QEMUIOVector* qiov, + size_t qiov_offset, uint64_t blk_offset) { assert(!(qiov->size % sccl->chunk_size)); - SyxCowCacheDevice* cache_entry = g_hash_table_lookup(sccl->cow_cache_devices, GINT_TO_POINTER(blk_name_hash(blk))); + SyxCowCacheDevice* cache_entry = g_hash_table_lookup( + sccl->cow_cache_devices, GINT_TO_POINTER(blk_name_hash(blk))); // return early if nothing is registered if (!cache_entry) { @@ -134,62 +159,79 @@ static bool read_chunk_from_cache_layer(SyxCowCacheLayer* sccl, BlockBackend* bl assert(cache_entry && cache_entry->data); // try to read cached pages in current layer if something is registered. - return read_chunk_from_cache_layer_device(cache_entry, qiov, qiov_offset, blk_offset); + return read_chunk_from_cache_layer_device(cache_entry, qiov, qiov_offset, + blk_offset); } // Returns false if could not write to current layer. -static bool write_to_cache_layer(SyxCowCacheLayer* sccl, BlockBackend* blk, int64_t offset, int64_t bytes, QEMUIOVector* qiov) +static bool write_to_cache_layer(SyxCowCacheLayer* sccl, BlockBackend* blk, + int64_t offset, int64_t bytes, + QEMUIOVector* qiov) { if (qiov->size % sccl->chunk_size) { - // todo: determine if it is worth developing an unaligned access version. - printf("error: 0x%zx %% 0x%lx == 0x%lx\n", qiov->size, sccl->chunk_size, qiov->size % sccl->chunk_size); + // todo: determine if it is worth developing an unaligned access + // version. + printf("error: 0x%zx %% 0x%lx == 0x%lx\n", qiov->size, sccl->chunk_size, + qiov->size % sccl->chunk_size); exit(1); } - SyxCowCacheDevice* cache_entry = g_hash_table_lookup(sccl->cow_cache_devices, GINT_TO_POINTER(blk_name_hash(blk))); + SyxCowCacheDevice* cache_entry = g_hash_table_lookup( + sccl->cow_cache_devices, GINT_TO_POINTER(blk_name_hash(blk))); if (unlikely(!cache_entry)) { cache_entry = g_new0(SyxCowCacheDevice, 1); - cache_entry->data = g_array_sized_new(false, false, sccl->chunk_size, INITIAL_NB_CHUNKS_PER_DEVICE); - cache_entry->positions = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); - g_hash_table_insert(sccl->cow_cache_devices, GINT_TO_POINTER(blk_name_hash(blk)), cache_entry); + cache_entry->data = g_array_sized_new(false, false, sccl->chunk_size, + INITIAL_NB_CHUNKS_PER_DEVICE); + cache_entry->positions = + g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); + g_hash_table_insert(sccl->cow_cache_devices, + GINT_TO_POINTER(blk_name_hash(blk)), cache_entry); } assert(cache_entry && cache_entry->data); - if (cache_entry->data->len + (qiov->size / sccl->chunk_size) > sccl->max_nb_chunks) { + if (cache_entry->data->len + (qiov->size / sccl->chunk_size) > + sccl->max_nb_chunks) { return false; } // write cached page uint64_t blk_offset = offset; size_t qiov_offset = 0; - for (; qiov_offset < qiov->size; blk_offset += sccl->chunk_size, qiov_offset += sccl->chunk_size) { - write_chunk_to_cache_layer_device(cache_entry, qiov, qiov_offset, blk_offset); + for (; qiov_offset < qiov->size; + blk_offset += sccl->chunk_size, qiov_offset += sccl->chunk_size) { + write_chunk_to_cache_layer_device(cache_entry, qiov, qiov_offset, + blk_offset); } return true; } -void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t _qiov_offset, - BdrvRequestFlags flags) +void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend* blk, + int64_t offset, int64_t bytes, QEMUIOVector* qiov, + size_t _qiov_offset, BdrvRequestFlags flags) { SyxCowCacheLayer* layer; uint64_t blk_offset = offset; size_t qiov_offset = 0; uint64_t chunk_size = 0; - // printf("[%s] Read 0x%zx bytes @addr %lx\n", blk_name(blk), qiov->size, offset); + // printf("[%s] Read 0x%zx bytes @addr %lx\n", blk_name(blk), qiov->size, + // offset); // First read the backing block device normally. assert(blk_co_preadv(blk, offset, bytes, qiov, flags) >= 0); // Then fix the chunks that have been read from before. if (!QTAILQ_EMPTY(&scc->layers)) { - for (;qiov_offset < qiov->size; blk_offset += chunk_size, qiov_offset += chunk_size) { - QTAILQ_FOREACH(layer, &scc->layers, next) { + for (; qiov_offset < qiov->size; + blk_offset += chunk_size, qiov_offset += chunk_size) { + QTAILQ_FOREACH(layer, &scc->layers, next) + { chunk_size = layer->chunk_size; - if (read_chunk_from_cache_layer(layer, blk, qiov, qiov_offset, blk_offset)) { + if (read_chunk_from_cache_layer(layer, blk, qiov, qiov_offset, + blk_offset)) { break; } } @@ -197,12 +239,15 @@ void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offse } } -bool syx_cow_cache_write_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, - BdrvRequestFlags flags) +bool syx_cow_cache_write_entry(SyxCowCache* scc, BlockBackend* blk, + int64_t offset, int64_t bytes, + QEMUIOVector* qiov, size_t qiov_offset, + BdrvRequestFlags flags) { SyxCowCacheLayer* layer; - // printf("[%s] Write 0x%zx bytes @addr %lx\n", blk_name(blk), qiov->size, offset); + // printf("[%s] Write 0x%zx bytes @addr %lx\n", blk_name(blk), qiov->size, + // offset); layer = QTAILQ_FIRST(&scc->layers); if (layer) { diff --git a/libafl/syx-snapshot/syx-snapshot.c b/libafl/syx-snapshot/syx-snapshot.c index 507e8e1eae..b4eef46ca3 100644 --- a/libafl/syx-snapshot/syx-snapshot.c +++ b/libafl/syx-snapshot/syx-snapshot.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" + #include "qemu/main-loop.h" #include "sysemu/sysemu.h" #include "migration/vmstate.h" @@ -11,16 +12,16 @@ #include "libafl/syx-snapshot/syx-snapshot.h" #include "libafl/syx-snapshot/device-save.h" -#define SYX_SNAPSHOT_LIST_INIT_SIZE 4096 -#define SYX_SNAPSHOT_LIST_GROW_FACTOR 2 -#define TARGET_NEXT_PAGE_ADDR(p) \ - ((typeof(p))(((uintptr_t) p + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK)) +#define SYX_SNAPSHOT_LIST_INIT_SIZE 4096 +#define SYX_SNAPSHOT_LIST_GROW_FACTOR 2 +#define TARGET_NEXT_PAGE_ADDR(p) \ + ((typeof(p))(((uintptr_t)p + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK)) /** * Saved ramblock */ typedef struct SyxSnapshotRAMBlock { - uint8_t *ram; // RAM block + uint8_t* ram; // RAM block uint64_t used_length; // Length of the ram block } SyxSnapshotRAMBlock; @@ -37,11 +38,11 @@ typedef struct SyxSnapshotRoot { */ typedef struct SyxSnapshotDirtyPage { ram_addr_t offset_within_rb; - uint8_t *data; + uint8_t* data; } SyxSnapshotDirtyPage; typedef struct SyxSnapshotDirtyPageList { - SyxSnapshotDirtyPage *dirty_pages; + SyxSnapshotDirtyPage* dirty_pages; uint64_t length; } SyxSnapshotDirtyPageList; @@ -51,36 +52,57 @@ typedef struct SyxSnapshotDirtyPageList { */ typedef struct SyxSnapshotIncrement { // Back to root snapshot if NULL - struct SyxSnapshotIncrement *parent; + struct SyxSnapshotIncrement* parent; - DeviceSaveState *dss; + DeviceSaveState* dss; - GHashTable *rbs_dirty_pages; // hash map: H(rb) -> SyxSnapshotDirtyPageList + GHashTable* rbs_dirty_pages; // hash map: H(rb) -> SyxSnapshotDirtyPageList } SyxSnapshotIncrement; - SyxSnapshotState syx_snapshot_state = {0}; static MemoryRegion* mr_to_enable = NULL; static void destroy_ramblock_snapshot(gpointer root_snapshot); + static void syx_snapshot_dirty_list_flush(SyxSnapshot* snapshot); -static void rb_save_dirty_addr_to_table(gpointer offset_within_rb, gpointer unused, gpointer rb_dirty_list_to_page_args_ptr); -static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash, gpointer rb_dirty_list_hash_table_ptr, gpointer rbs_dirty_pages_ptr); -static inline void syx_snapshot_dirty_list_add_internal(RAMBlock* rb, ram_addr_t offset); -static void empty_rb_dirty_list(gpointer rb_idstr_hash, gpointer rb_dirty_list_hash_table_ptr, gpointer user_data); -static void destroy_snapshot_dirty_page_list(gpointer snapshot_dirty_page_list_ptr); +static void +rb_save_dirty_addr_to_table(gpointer offset_within_rb, gpointer unused, + gpointer rb_dirty_list_to_page_args_ptr); -static void root_restore_rb_page(gpointer offset_within_rb, gpointer unused, gpointer root_restore_args_ptr); -static void root_restore_rb(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr, gpointer snapshot_ptr); -static void root_restore_check_memory_rb(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr, gpointer snapshot_ptr); +static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash, + gpointer rb_dirty_list_hash_table_ptr, + gpointer rbs_dirty_pages_ptr); -static SyxSnapshotIncrement* syx_snapshot_increment_free(SyxSnapshotIncrement* increment); +static inline void syx_snapshot_dirty_list_add_internal(RAMBlock* rb, + ram_addr_t offset); + +static void empty_rb_dirty_list(gpointer rb_idstr_hash, + gpointer rb_dirty_list_hash_table_ptr, + gpointer user_data); + +static void +destroy_snapshot_dirty_page_list(gpointer snapshot_dirty_page_list_ptr); + +static void root_restore_rb_page(gpointer offset_within_rb, gpointer unused, + gpointer root_restore_args_ptr); + +static void root_restore_rb(gpointer rb_idstr_hash, + gpointer rb_dirty_pages_hash_table_ptr, + gpointer snapshot_ptr); + +static void root_restore_check_memory_rb(gpointer rb_idstr_hash, + gpointer rb_dirty_pages_hash_table_ptr, + gpointer snapshot_ptr); + +static SyxSnapshotIncrement* +syx_snapshot_increment_free(SyxSnapshotIncrement* increment); static RAMBlock* ramblock_lookup(gpointer rb_idstr_hash) { RAMBlock* block; - RAMBLOCK_FOREACH(block) { + RAMBLOCK_FOREACH(block) + { if (rb_idstr_hash == GINT_TO_POINTER(block->idstr_hash)) { return block; } @@ -90,7 +112,9 @@ static RAMBlock* ramblock_lookup(gpointer rb_idstr_hash) } // Root snapshot API -static SyxSnapshotRoot* syx_snapshot_root_new(DeviceSnapshotKind kind, char** devices); +static SyxSnapshotRoot* syx_snapshot_root_new(DeviceSnapshotKind kind, + char** devices); + static void syx_snapshot_root_free(SyxSnapshotRoot* root); struct rb_dirty_list_to_page_args { @@ -116,52 +140,55 @@ struct rb_page_increment_restore_args { }; struct rb_check_memory_args { - SyxSnapshot* snapshot; // IN + SyxSnapshot* snapshot; // IN uint64_t nb_inconsistent_pages; // OUT }; -void syx_snapshot_init(bool cached_bdrvs) { +void syx_snapshot_init(bool cached_bdrvs) +{ uint64_t page_size = TARGET_PAGE_SIZE; syx_snapshot_state.page_size = page_size; - syx_snapshot_state.page_mask = ((uint64_t) -1) << __builtin_ctz(page_size); + syx_snapshot_state.page_mask = ((uint64_t)-1) << __builtin_ctz(page_size); syx_snapshot_state.tracked_snapshots = syx_snapshot_tracker_init(); if (cached_bdrvs) { syx_snapshot_state.before_fuzz_cache = syx_cow_cache_new(); - syx_cow_cache_push_layer(syx_snapshot_state.before_fuzz_cache, SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE, SYX_SNAPSHOT_COW_CACHE_DEFAULT_MAX_BLOCKS); + syx_cow_cache_push_layer(syx_snapshot_state.before_fuzz_cache, + SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE, + SYX_SNAPSHOT_COW_CACHE_DEFAULT_MAX_BLOCKS); } syx_snapshot_state.is_enabled = false; } -SyxSnapshot *syx_snapshot_new(bool track, bool is_active_bdrv_cache, DeviceSnapshotKind kind, char **devices) { - SyxSnapshot *snapshot = g_new0(SyxSnapshot, 1); +SyxSnapshot* syx_snapshot_new(bool track, bool is_active_bdrv_cache, + DeviceSnapshotKind kind, char** devices) +{ + SyxSnapshot* snapshot = g_new0(SyxSnapshot, 1); snapshot->root_snapshot = syx_snapshot_root_new(kind, devices); snapshot->last_incremental_snapshot = NULL; - snapshot->rbs_dirty_list = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) g_hash_table_remove_all); + snapshot->rbs_dirty_list = + g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, + (GDestroyNotify)g_hash_table_remove_all); snapshot->bdrvs_cow_cache = syx_cow_cache_new(); if (is_active_bdrv_cache) { - syx_cow_cache_move(snapshot->bdrvs_cow_cache, &syx_snapshot_state.before_fuzz_cache); + syx_cow_cache_move(snapshot->bdrvs_cow_cache, + &syx_snapshot_state.before_fuzz_cache); syx_snapshot_state.active_bdrv_cache_snapshot = snapshot; } else { - syx_cow_cache_push_layer(snapshot->bdrvs_cow_cache, SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE, SYX_SNAPSHOT_COW_CACHE_DEFAULT_MAX_BLOCKS); + syx_cow_cache_push_layer(snapshot->bdrvs_cow_cache, + SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE, + SYX_SNAPSHOT_COW_CACHE_DEFAULT_MAX_BLOCKS); } if (track) { syx_snapshot_track(&syx_snapshot_state.tracked_snapshots, snapshot); } -#ifdef CONFIG_DEBUG_TCG - SYX_PRINTF("[Snapshot Creation] Checking snapshot memory consistency\n"); - g_hash_table_foreach(snapshot->rbs_dirty_list, root_restore_check_memory_rb, snapshot); - SYX_PRINTF("[Snapshot Creation] Memory is consistent.\n"); -#endif - syx_snapshot_state.is_enabled = true; return snapshot; @@ -190,55 +217,67 @@ static void destroy_ramblock_snapshot(gpointer root_snapshot) g_free(snapshot_rb); } -static SyxSnapshotRoot* syx_snapshot_root_new(DeviceSnapshotKind kind, char **devices) { +static SyxSnapshotRoot* syx_snapshot_root_new(DeviceSnapshotKind kind, + char** devices) +{ SyxSnapshotRoot* root = g_new0(SyxSnapshotRoot, 1); - RAMBlock *block; - RAMBlock *inner_block; - DeviceSaveState *dss = device_save_kind(kind, devices); + RAMBlock* block; + RAMBlock* inner_block; + DeviceSaveState* dss = device_save_kind(kind, devices); - root->rbs_snapshot = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_ramblock_snapshot); + root->rbs_snapshot = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, destroy_ramblock_snapshot); root->dss = dss; - RAMBLOCK_FOREACH(block) { - RAMBLOCK_FOREACH(inner_block) { - if (block != inner_block && inner_block->idstr_hash == block->idstr_hash) { - SYX_ERROR("Hash collision detected on RAMBlocks %s and %s, snapshotting will not work correctly.", + RAMBLOCK_FOREACH(block) + { + RAMBLOCK_FOREACH(inner_block) + { + if (block != inner_block && + inner_block->idstr_hash == block->idstr_hash) { + SYX_ERROR("Hash collision detected on RAMBlocks %s and %s, " + "snapshotting will not work correctly.", inner_block->idstr, block->idstr); exit(1); } } - SyxSnapshotRAMBlock *snapshot_rb = g_new(SyxSnapshotRAMBlock, 1); + SyxSnapshotRAMBlock* snapshot_rb = g_new(SyxSnapshotRAMBlock, 1); snapshot_rb->used_length = block->used_length; snapshot_rb->ram = g_new(uint8_t, block->used_length); memcpy(snapshot_rb->ram, block->host, block->used_length); - g_hash_table_insert(root->rbs_snapshot, GINT_TO_POINTER(block->idstr_hash), snapshot_rb); + g_hash_table_insert(root->rbs_snapshot, + GINT_TO_POINTER(block->idstr_hash), snapshot_rb); } return root; } -static void syx_snapshot_root_free(SyxSnapshotRoot *root) { +static void syx_snapshot_root_free(SyxSnapshotRoot* root) +{ g_hash_table_destroy(root->rbs_snapshot); g_free(root); } -SyxSnapshotTracker syx_snapshot_tracker_init(void) { +SyxSnapshotTracker syx_snapshot_tracker_init(void) +{ SyxSnapshotTracker tracker = { - .length = 0, - .capacity = SYX_SNAPSHOT_LIST_INIT_SIZE, - .tracked_snapshots = g_new(SyxSnapshot*, SYX_SNAPSHOT_LIST_INIT_SIZE) - }; + .length = 0, + .capacity = SYX_SNAPSHOT_LIST_INIT_SIZE, + .tracked_snapshots = g_new(SyxSnapshot*, SYX_SNAPSHOT_LIST_INIT_SIZE)}; return tracker; } -void syx_snapshot_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot) { +void syx_snapshot_track(SyxSnapshotTracker* tracker, SyxSnapshot* snapshot) +{ if (tracker->length == tracker->capacity) { tracker->capacity *= SYX_SNAPSHOT_LIST_GROW_FACTOR; - tracker->tracked_snapshots = g_realloc(tracker->tracked_snapshots, tracker->capacity * sizeof(SyxSnapshot *)); + tracker->tracked_snapshots = + g_realloc(tracker->tracked_snapshots, + tracker->capacity * sizeof(SyxSnapshot*)); } assert(tracker->length < tracker->capacity); @@ -247,11 +286,13 @@ void syx_snapshot_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot) { tracker->length++; } -void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot) { +void syx_snapshot_stop_track(SyxSnapshotTracker* tracker, SyxSnapshot* snapshot) +{ for (uint64_t i = 0; i < tracker->length; ++i) { if (tracker->tracked_snapshots[i] == snapshot) { for (uint64_t j = i + i; j < tracker->length; ++j) { - tracker->tracked_snapshots[j - 1] = tracker->tracked_snapshots[j]; + tracker->tracked_snapshots[j - 1] = + tracker->tracked_snapshots[j]; } tracker->length--; return; @@ -262,39 +303,45 @@ void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot) abort(); } -static void -rb_save_dirty_addr_to_table(gpointer offset_within_rb, gpointer unused, gpointer rb_dirty_list_to_page_args_ptr) { - struct rb_dirty_list_to_page_args *args = rb_dirty_list_to_page_args_ptr; - RAMBlock *rb = args->rb; - SyxSnapshotDirtyPage *dirty_page = &args->dirty_page_list->dirty_pages[*args->table_idx]; - dirty_page->offset_within_rb = (ram_addr_t) offset_within_rb; +static void rb_save_dirty_addr_to_table(gpointer offset_within_rb, + gpointer unused, + gpointer rb_dirty_list_to_page_args_ptr) +{ + struct rb_dirty_list_to_page_args* args = rb_dirty_list_to_page_args_ptr; + RAMBlock* rb = args->rb; + SyxSnapshotDirtyPage* dirty_page = + &args->dirty_page_list->dirty_pages[*args->table_idx]; + dirty_page->offset_within_rb = (ram_addr_t)offset_within_rb; - memcpy((gpointer) dirty_page->data, rb->host + (ram_addr_t) offset_within_rb, syx_snapshot_state.page_size); + memcpy((gpointer)dirty_page->data, rb->host + (ram_addr_t)offset_within_rb, + syx_snapshot_state.page_size); *args->table_idx += 1; } -static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash, gpointer rb_dirty_list_hash_table_ptr, - gpointer rbs_dirty_pages_ptr) { - GHashTable *rbs_dirty_pages = rbs_dirty_pages_ptr; - GHashTable *rb_dirty_list = rb_dirty_list_hash_table_ptr; +static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash, + gpointer rb_dirty_list_hash_table_ptr, + gpointer rbs_dirty_pages_ptr) +{ + GHashTable* rbs_dirty_pages = rbs_dirty_pages_ptr; + GHashTable* rb_dirty_list = rb_dirty_list_hash_table_ptr; - RAMBlock *rb = ramblock_lookup(rb_idstr_hash); + RAMBlock* rb = ramblock_lookup(rb_idstr_hash); if (rb) { - SyxSnapshotDirtyPageList *dirty_page_list = g_new(SyxSnapshotDirtyPageList, 1); + SyxSnapshotDirtyPageList* dirty_page_list = + g_new(SyxSnapshotDirtyPageList, 1); dirty_page_list->length = g_hash_table_size(rb_dirty_list); - dirty_page_list->dirty_pages = g_new(SyxSnapshotDirtyPage, dirty_page_list->length); + dirty_page_list->dirty_pages = + g_new(SyxSnapshotDirtyPage, dirty_page_list->length); - uint64_t *ctr = g_new0(uint64_t, 1); + uint64_t* ctr = g_new0(uint64_t, 1); struct rb_dirty_list_to_page_args dirty_list_to_page_args = { - .rb = rb, - .table_idx = ctr, - .dirty_page_list = dirty_page_list - }; + .rb = rb, .table_idx = ctr, .dirty_page_list = dirty_page_list}; - g_hash_table_foreach(rbs_dirty_pages, rb_save_dirty_addr_to_table, &dirty_list_to_page_args); + g_hash_table_foreach(rbs_dirty_pages, rb_save_dirty_addr_to_table, + &dirty_list_to_page_args); g_free(dirty_list_to_page_args.table_idx); } else { @@ -302,8 +349,11 @@ static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash, gpointer rb_dir } } -static void destroy_snapshot_dirty_page_list(gpointer snapshot_dirty_page_list_ptr) { - SyxSnapshotDirtyPageList *snapshot_dirty_page_list = snapshot_dirty_page_list_ptr; +static void +destroy_snapshot_dirty_page_list(gpointer snapshot_dirty_page_list_ptr) +{ + SyxSnapshotDirtyPageList* snapshot_dirty_page_list = + snapshot_dirty_page_list_ptr; for (uint64_t i = 0; i < snapshot_dirty_page_list->length; ++i) { g_free(snapshot_dirty_page_list->dirty_pages[i].data); @@ -313,26 +363,32 @@ static void destroy_snapshot_dirty_page_list(gpointer snapshot_dirty_page_list_p g_free(snapshot_dirty_page_list); } -void syx_snapshot_increment_push(SyxSnapshot *snapshot, DeviceSnapshotKind kind, char **devices) { - SyxSnapshotIncrement *increment = g_new0(SyxSnapshotIncrement, 1); +void syx_snapshot_increment_push(SyxSnapshot* snapshot, DeviceSnapshotKind kind, + char** devices) +{ + SyxSnapshotIncrement* increment = g_new0(SyxSnapshotIncrement, 1); increment->parent = snapshot->last_incremental_snapshot; snapshot->last_incremental_snapshot = increment; - increment->rbs_dirty_pages = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, - destroy_snapshot_dirty_page_list); - g_hash_table_foreach(snapshot->rbs_dirty_list, rb_dirty_list_to_dirty_pages, increment->rbs_dirty_pages); + increment->rbs_dirty_pages = g_hash_table_new_full( + g_direct_hash, g_direct_equal, NULL, destroy_snapshot_dirty_page_list); + g_hash_table_foreach(snapshot->rbs_dirty_list, rb_dirty_list_to_dirty_pages, + increment->rbs_dirty_pages); increment->dss = device_save_kind(kind, devices); g_hash_table_remove_all(snapshot->rbs_dirty_list); } -static SyxSnapshotDirtyPage * -get_dirty_page_from_addr_rec(SyxSnapshotIncrement *increment, RAMBlock *rb, ram_addr_t offset_within_rb) { +static SyxSnapshotDirtyPage* +get_dirty_page_from_addr_rec(SyxSnapshotIncrement* increment, RAMBlock* rb, + ram_addr_t offset_within_rb) +{ if (increment == NULL) { return NULL; } - SyxSnapshotDirtyPageList *dpl = g_hash_table_lookup(increment->rbs_dirty_pages, GINT_TO_POINTER(rb->idstr_hash)); + SyxSnapshotDirtyPageList* dpl = g_hash_table_lookup( + increment->rbs_dirty_pages, GINT_TO_POINTER(rb->idstr_hash)); if (dpl) { for (uint64_t i = 0; i < dpl->length; ++i) { @@ -342,55 +398,62 @@ get_dirty_page_from_addr_rec(SyxSnapshotIncrement *increment, RAMBlock *rb, ram_ } } - return get_dirty_page_from_addr_rec(increment->parent, rb, offset_within_rb); + return get_dirty_page_from_addr_rec(increment->parent, rb, + offset_within_rb); } +static void restore_dirty_page_to_increment(gpointer offset_within_rb, + gpointer _unused, gpointer args_ptr) +{ + struct rb_page_increment_restore_args* args = args_ptr; + RAMBlock* rb = args->rb; + SyxSnapshot* snapshot = args->snapshot; + SyxSnapshotIncrement* increment = args->increment; + ram_addr_t offset = (ram_addr_t)offset_within_rb; -static void restore_dirty_page_to_increment(gpointer offset_within_rb, gpointer _unused, gpointer args_ptr) { - struct rb_page_increment_restore_args *args = args_ptr; - RAMBlock *rb = args->rb; - SyxSnapshot *snapshot = args->snapshot; - SyxSnapshotIncrement *increment = args->increment; - ram_addr_t offset = (ram_addr_t) offset_within_rb; - - SyxSnapshotDirtyPage *dp = get_dirty_page_from_addr_rec(increment, rb, offset); + SyxSnapshotDirtyPage* dp = + get_dirty_page_from_addr_rec(increment, rb, offset); if (dp) { memcpy(rb->host + offset, dp->data, syx_snapshot_state.page_size); } else { - SyxSnapshotRAMBlock *rrb = g_hash_table_lookup(snapshot->root_snapshot->rbs_snapshot, - GINT_TO_POINTER(rb->idstr_hash)); + SyxSnapshotRAMBlock* rrb = + g_hash_table_lookup(snapshot->root_snapshot->rbs_snapshot, + GINT_TO_POINTER(rb->idstr_hash)); assert(rrb); memcpy(rb->host + offset, rrb->ram, syx_snapshot_state.page_size); } } -static void restore_rb_to_increment(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr, gpointer args_ptr) { - struct rb_increment_restore_args *args = args_ptr; - GHashTable *rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_ptr; +static void restore_rb_to_increment(gpointer rb_idstr_hash, + gpointer rb_dirty_pages_hash_table_ptr, + gpointer args_ptr) +{ + struct rb_increment_restore_args* args = args_ptr; + GHashTable* rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_ptr; - RAMBlock *rb = ramblock_lookup(rb_idstr_hash); + RAMBlock* rb = ramblock_lookup(rb_idstr_hash); struct rb_page_increment_restore_args page_args = { - .snapshot = args->snapshot, - .increment = args->increment, - .rb = rb - }; + .snapshot = args->snapshot, .increment = args->increment, .rb = rb}; - g_hash_table_foreach(rb_dirty_pages_hash_table, restore_dirty_page_to_increment, &page_args); + g_hash_table_foreach(rb_dirty_pages_hash_table, + restore_dirty_page_to_increment, &page_args); } -static void restore_to_increment(SyxSnapshot *snapshot, SyxSnapshotIncrement *increment) { - struct rb_increment_restore_args args = { - .snapshot = snapshot, - .increment = increment - }; +static void restore_to_increment(SyxSnapshot* snapshot, + SyxSnapshotIncrement* increment) +{ + struct rb_increment_restore_args args = {.snapshot = snapshot, + .increment = increment}; - g_hash_table_foreach(snapshot->rbs_dirty_list, restore_rb_to_increment, &args); + g_hash_table_foreach(snapshot->rbs_dirty_list, restore_rb_to_increment, + &args); } -void syx_snapshot_increment_pop(SyxSnapshot *snapshot) { - SyxSnapshotIncrement *last_increment = snapshot->last_incremental_snapshot; +void syx_snapshot_increment_pop(SyxSnapshot* snapshot) +{ + SyxSnapshotIncrement* last_increment = snapshot->last_incremental_snapshot; device_restore_all(last_increment->dss); restore_to_increment(snapshot, last_increment); @@ -401,8 +464,9 @@ void syx_snapshot_increment_pop(SyxSnapshot *snapshot) { syx_snapshot_dirty_list_flush(snapshot); } -void syx_snapshot_increment_restore_last(SyxSnapshot *snapshot) { - SyxSnapshotIncrement *last_increment = snapshot->last_incremental_snapshot; +void syx_snapshot_increment_restore_last(SyxSnapshot* snapshot) +{ + SyxSnapshotIncrement* last_increment = snapshot->last_incremental_snapshot; device_restore_all(last_increment->dss); restore_to_increment(snapshot, last_increment); @@ -410,51 +474,62 @@ void syx_snapshot_increment_restore_last(SyxSnapshot *snapshot) { syx_snapshot_dirty_list_flush(snapshot); } -static SyxSnapshotIncrement *syx_snapshot_increment_free(SyxSnapshotIncrement *increment) { - SyxSnapshotIncrement *parent_increment = increment->parent; +static SyxSnapshotIncrement* +syx_snapshot_increment_free(SyxSnapshotIncrement* increment) +{ + SyxSnapshotIncrement* parent_increment = increment->parent; g_hash_table_destroy(increment->rbs_dirty_pages); device_free_all(increment->dss); g_free(increment); return parent_increment; } -static void syx_snapshot_dirty_list_flush(SyxSnapshot *snapshot) { - g_hash_table_foreach(snapshot->rbs_dirty_list, empty_rb_dirty_list, (gpointer) snapshot); +static void syx_snapshot_dirty_list_flush(SyxSnapshot* snapshot) +{ + g_hash_table_foreach(snapshot->rbs_dirty_list, empty_rb_dirty_list, + (gpointer)snapshot); } -static inline void syx_snapshot_dirty_list_add_internal(RAMBlock *rb, ram_addr_t offset) { - assert((offset & syx_snapshot_state.page_mask) == offset); // offsets should always be page-aligned. +static inline void syx_snapshot_dirty_list_add_internal(RAMBlock* rb, + ram_addr_t offset) +{ + assert((offset & syx_snapshot_state.page_mask) == + offset); // offsets should always be page-aligned. for (uint64_t i = 0; i < syx_snapshot_state.tracked_snapshots.length; ++i) { - SyxSnapshot *snapshot = syx_snapshot_state.tracked_snapshots.tracked_snapshots[i]; + SyxSnapshot* snapshot = + syx_snapshot_state.tracked_snapshots.tracked_snapshots[i]; - GHashTable *rb_dirty_list = g_hash_table_lookup(snapshot->rbs_dirty_list, GINT_TO_POINTER(rb->idstr_hash)); + GHashTable* rb_dirty_list = g_hash_table_lookup( + snapshot->rbs_dirty_list, GINT_TO_POINTER(rb->idstr_hash)); if (unlikely(!rb_dirty_list)) { #ifdef SYX_SNAPSHOT_DEBUG printf("rb_dirty_list did not exit, creating...\n"); #endif rb_dirty_list = g_hash_table_new(g_direct_hash, g_direct_equal); - g_hash_table_insert(snapshot->rbs_dirty_list, GINT_TO_POINTER(rb->idstr_hash), rb_dirty_list); + g_hash_table_insert(snapshot->rbs_dirty_list, + GINT_TO_POINTER(rb->idstr_hash), rb_dirty_list); } if (g_hash_table_add(rb_dirty_list, GINT_TO_POINTER(offset))) { #ifdef SYX_SNAPSHOT_DEBUG - SYX_PRINTF("[%s] Marking offset 0x%lx as dirty\n", rb->idstr, offset); + SYX_PRINTF("[%s] Marking offset 0x%lx as dirty\n", rb->idstr, + offset); #endif } } } -bool syx_snapshot_is_enabled(void) { - return syx_snapshot_state.is_enabled; -} +bool syx_snapshot_is_enabled(void) { return syx_snapshot_state.is_enabled; } /* // TODO: Check if using this method is better for performances. -// The implementation is pretty bad, it would be nice to store host addr directly for +// The implementation is pretty bad, it would be nice to store host addr +directly for // the memcopy happening later on. -__attribute__((target("no-3dnow,no-sse,no-mmx"),no_caller_saved_registers)) void syx_snapshot_dirty_list_add_tcg_target(uint64_t dummy, void* host_addr) { +__attribute__((target("no-3dnow,no-sse,no-mmx"),no_caller_saved_registers)) void +syx_snapshot_dirty_list_add_tcg_target(uint64_t dummy, void* host_addr) { // early check to know whether we should log the page access or not if (!syx_snapshot_is_enabled()) { return; @@ -472,14 +547,15 @@ __attribute__((target("no-3dnow,no-sse,no-mmx"),no_caller_saved_registers)) void */ // host_addr should be page-aligned. -void syx_snapshot_dirty_list_add_hostaddr(void *host_addr) { +void syx_snapshot_dirty_list_add_hostaddr(void* host_addr) +{ // early check to know whether we should log the page access or not if (!syx_snapshot_is_enabled()) { return; } ram_addr_t offset; - RAMBlock *rb = qemu_ram_block_from_host((void *) host_addr, true, &offset); + RAMBlock* rb = qemu_ram_block_from_host((void*)host_addr, true, &offset); #ifdef SYX_SNAPSHOT_DEBUG SYX_PRINTF("Should mark offset 0x%lx as dirty\n", offset); @@ -492,17 +568,19 @@ void syx_snapshot_dirty_list_add_hostaddr(void *host_addr) { syx_snapshot_dirty_list_add_internal(rb, offset); } -void syx_snapshot_dirty_list_add_hostaddr_range(void *host_addr, uint64_t len) { +void syx_snapshot_dirty_list_add_hostaddr_range(void* host_addr, uint64_t len) +{ // early check to know whether we should log the page access or not if (!syx_snapshot_is_enabled()) { return; } assert(len < INT64_MAX); - int64_t len_signed = (int64_t) len; + int64_t len_signed = (int64_t)len; - syx_snapshot_dirty_list_add_hostaddr(QEMU_ALIGN_PTR_DOWN(host_addr, syx_snapshot_state.page_size)); - void *next_page_addr = TARGET_NEXT_PAGE_ADDR(host_addr); + syx_snapshot_dirty_list_add_hostaddr( + QEMU_ALIGN_PTR_DOWN(host_addr, syx_snapshot_state.page_size)); + void* next_page_addr = TARGET_NEXT_PAGE_ADDR(host_addr); assert(next_page_addr > host_addr); assert(QEMU_PTR_IS_ALIGNED(next_page_addr, TARGET_PAGE_SIZE)); @@ -519,73 +597,79 @@ void syx_snapshot_dirty_list_add_hostaddr_range(void *host_addr, uint64_t len) { } } -static void empty_rb_dirty_list(gpointer _rb_idstr_hash, gpointer rb_dirty_list_hash_table_ptr, gpointer _user_data) { - GHashTable *rb_dirty_hash_table = rb_dirty_list_hash_table_ptr; +static void empty_rb_dirty_list(gpointer _rb_idstr_hash, + gpointer rb_dirty_list_hash_table_ptr, + gpointer _user_data) +{ + GHashTable* rb_dirty_hash_table = rb_dirty_list_hash_table_ptr; g_hash_table_remove_all(rb_dirty_hash_table); } -static void root_restore_rb_page(gpointer offset_within_rb, gpointer _unused, gpointer root_restore_args_ptr) { - struct rb_page_root_restore_args *args = root_restore_args_ptr; - RAMBlock *rb = args->rb; - SyxSnapshotRAMBlock *snapshot_rb = args->snapshot_rb; - +static void root_restore_rb_page(gpointer offset_within_rb, gpointer _unused, + gpointer root_restore_args_ptr) +{ + struct rb_page_root_restore_args* args = root_restore_args_ptr; + RAMBlock* rb = args->rb; + SyxSnapshotRAMBlock* snapshot_rb = args->snapshot_rb; // safe cast because ram_addr_t is also an alias to void* - void *host_rb_restore = rb->host + (ram_addr_t) offset_within_rb; - void *host_snapshot_rb_restore = (gpointer) snapshot_rb->ram + (ram_addr_t) offset_within_rb; + void* host_rb_restore = rb->host + (ram_addr_t)offset_within_rb; + void* host_snapshot_rb_restore = + (gpointer)snapshot_rb->ram + (ram_addr_t)offset_within_rb; #ifdef SYX_SNAPSHOT_DEBUG - SYX_PRINTF("\t[%s] Restore at offset 0x%lx of size %lu...\n", rb->idstr, (uint64_t) offset_within_rb, syx_snapshot_state.page_size); + SYX_PRINTF("\t[%s] Restore at offset 0x%lx of size %lu...\n", rb->idstr, + (uint64_t)offset_within_rb, syx_snapshot_state.page_size); #endif - memcpy(host_rb_restore, host_snapshot_rb_restore, syx_snapshot_state.page_size); - //TODO: manage special case of TSEG. + memcpy(host_rb_restore, host_snapshot_rb_restore, + syx_snapshot_state.page_size); + // TODO: manage special case of TSEG. } -static void root_restore_rb(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr, gpointer snapshot_ptr) { - SyxSnapshot *snapshot = snapshot_ptr; - GHashTable *rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_ptr; - RAMBlock *rb = ramblock_lookup(rb_idstr_hash); +static void root_restore_rb(gpointer rb_idstr_hash, + gpointer rb_dirty_pages_hash_table_ptr, + gpointer snapshot_ptr) +{ + SyxSnapshot* snapshot = snapshot_ptr; + GHashTable* rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_ptr; + RAMBlock* rb = ramblock_lookup(rb_idstr_hash); if (rb) { - SyxSnapshotRAMBlock *snapshot_ramblock = g_hash_table_lookup(snapshot->root_snapshot->rbs_snapshot, - rb_idstr_hash); + SyxSnapshotRAMBlock* snapshot_ramblock = g_hash_table_lookup( + snapshot->root_snapshot->rbs_snapshot, rb_idstr_hash); struct rb_page_root_restore_args root_restore_args = { - .rb = rb, - .snapshot_rb = snapshot_ramblock - }; + .rb = rb, .snapshot_rb = snapshot_ramblock}; -#ifdef CONFIG_DEBUG_TCG - SYX_PRINTF("Restoring RB %s...\n", rb->idstr); -#endif - - g_hash_table_foreach(rb_dirty_pages_hash_table, root_restore_rb_page, &root_restore_args); - -#ifdef CONFIG_DEBUG_TCG - SYX_PRINTF("Finished to restore RB %s\n", rb->idstr); -#endif + g_hash_table_foreach(rb_dirty_pages_hash_table, root_restore_rb_page, + &root_restore_args); } else { SYX_ERROR("Saved RAMBlock not found."); exit(1); } } -static void root_restore_check_memory_rb(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr, - gpointer check_memory_args_ptr) { - struct rb_check_memory_args *args = check_memory_args_ptr; - SyxSnapshot *snapshot = args->snapshot; - RAMBlock *rb = ramblock_lookup(rb_idstr_hash); +static void root_restore_check_memory_rb(gpointer rb_idstr_hash, + gpointer rb_dirty_pages_hash_table_ptr, + gpointer check_memory_args_ptr) +{ + struct rb_check_memory_args* args = check_memory_args_ptr; + SyxSnapshot* snapshot = args->snapshot; + RAMBlock* rb = ramblock_lookup(rb_idstr_hash); if (rb) { SYX_PRINTF("Checking memory consistency of %s... ", rb->idstr); - SyxSnapshotRAMBlock *rb_snapshot = g_hash_table_lookup(snapshot->root_snapshot->rbs_snapshot, rb_idstr_hash); + SyxSnapshotRAMBlock* rb_snapshot = g_hash_table_lookup( + snapshot->root_snapshot->rbs_snapshot, rb_idstr_hash); assert(rb_snapshot); assert(rb->used_length == rb_snapshot->used_length); - for (uint64_t i = 0; i < rb->used_length; i += syx_snapshot_state.page_size) { - if (memcmp(rb->host + i, rb_snapshot->ram + i, syx_snapshot_state.page_size) != 0) { + for (uint64_t i = 0; i < rb->used_length; + i += syx_snapshot_state.page_size) { + if (memcmp(rb->host + i, rb_snapshot->ram + i, + syx_snapshot_state.page_size) != 0) { SYX_ERROR("\nFound incorrect page at offset 0x%lx\n", i); for (uint64_t j = 0; j < syx_snapshot_state.page_size; j++) { if (*(rb->host + i + j) != *(rb_snapshot->ram + i + j)) { @@ -594,12 +678,13 @@ static void root_restore_check_memory_rb(gpointer rb_idstr_hash, gpointer rb_dir } args->nb_inconsistent_pages++; } - } if (args->nb_inconsistent_pages > 0) { - SYX_ERROR("[%s] Found %lu page %s.\n", rb->idstr, args->nb_inconsistent_pages, - args->nb_inconsistent_pages > 1 ? "inconsistencies" : "inconsistency"); + SYX_ERROR("[%s] Found %lu page %s.\n", rb->idstr, + args->nb_inconsistent_pages, + args->nb_inconsistent_pages > 1 ? "inconsistencies" + : "inconsistency"); } else { SYX_PRINTF("OK.\n"); } @@ -609,27 +694,27 @@ static void root_restore_check_memory_rb(gpointer rb_idstr_hash, gpointer rb_dir } } -SyxSnapshotCheckResult syx_snapshot_check(SyxSnapshot* ref_snapshot) { +SyxSnapshotCheckResult syx_snapshot_check(SyxSnapshot* ref_snapshot) +{ struct rb_check_memory_args args = { - .snapshot = ref_snapshot, - .nb_inconsistent_pages = 0, + .snapshot = ref_snapshot, + .nb_inconsistent_pages = 0, }; - g_hash_table_foreach(ref_snapshot->rbs_dirty_list, root_restore_check_memory_rb, &args); + g_hash_table_foreach(ref_snapshot->rbs_dirty_list, + root_restore_check_memory_rb, &args); - struct SyxSnapshotCheckResult res = { - .nb_inconsistencies = args.nb_inconsistent_pages - }; + struct SyxSnapshotCheckResult res = {.nb_inconsistencies = + args.nb_inconsistent_pages}; return res; } -void syx_snapshot_root_restore(SyxSnapshot *snapshot) { +void syx_snapshot_root_restore(SyxSnapshot* snapshot) +{ // health check. - CPUState *cpu; - CPU_FOREACH(cpu) { - assert(cpu->stopped); - } + CPUState* cpu; + CPU_FOREACH(cpu) { assert(cpu->stopped); } bool must_unlock_bql = false; @@ -638,7 +723,8 @@ void syx_snapshot_root_restore(SyxSnapshot *snapshot) { must_unlock_bql = true; } - // In case, we first restore devices if there is a modification of memory layout + // In case, we first restore devices if there is a modification of memory + // layout device_restore_all(snapshot->root_snapshot->dss); g_hash_table_foreach(snapshot->rbs_dirty_list, root_restore_rb, snapshot); @@ -656,34 +742,46 @@ void syx_snapshot_root_restore(SyxSnapshot *snapshot) { bql_unlock(); } } -bool syx_snapshot_cow_cache_read_entry(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, + +bool syx_snapshot_cow_cache_read_entry(BlockBackend* blk, int64_t offset, + int64_t bytes, QEMUIOVector* qiov, + size_t qiov_offset, BdrvRequestFlags flags) { if (!syx_snapshot_state.active_bdrv_cache_snapshot) { if (syx_snapshot_state.before_fuzz_cache) { - syx_cow_cache_read_entry(syx_snapshot_state.before_fuzz_cache, blk, offset, bytes, qiov, qiov_offset, flags); + syx_cow_cache_read_entry(syx_snapshot_state.before_fuzz_cache, blk, + offset, bytes, qiov, qiov_offset, flags); return true; } return false; } else { - syx_cow_cache_read_entry(syx_snapshot_state.active_bdrv_cache_snapshot->bdrvs_cow_cache, blk, offset, bytes, qiov, qiov_offset, flags); + syx_cow_cache_read_entry( + syx_snapshot_state.active_bdrv_cache_snapshot->bdrvs_cow_cache, blk, + offset, bytes, qiov, qiov_offset, flags); return true; } } -bool syx_snapshot_cow_cache_write_entry(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, +bool syx_snapshot_cow_cache_write_entry(BlockBackend* blk, int64_t offset, + int64_t bytes, QEMUIOVector* qiov, + size_t qiov_offset, BdrvRequestFlags flags) { if (!syx_snapshot_state.active_bdrv_cache_snapshot) { if (syx_snapshot_state.before_fuzz_cache) { - assert(syx_cow_cache_write_entry(syx_snapshot_state.before_fuzz_cache, blk, offset, bytes, qiov, qiov_offset, flags)); + assert(syx_cow_cache_write_entry( + syx_snapshot_state.before_fuzz_cache, blk, offset, bytes, qiov, + qiov_offset, flags)); return true; } return false; } else { - assert(syx_cow_cache_write_entry(syx_snapshot_state.active_bdrv_cache_snapshot->bdrvs_cow_cache, blk, offset, bytes, qiov, qiov_offset, flags)); + assert(syx_cow_cache_write_entry( + syx_snapshot_state.active_bdrv_cache_snapshot->bdrvs_cow_cache, blk, + offset, bytes, qiov, qiov_offset, flags)); return true; } } diff --git a/libafl/utils.c b/libafl/utils.c index 281c5591cb..de8b06aa66 100644 --- a/libafl/utils.c +++ b/libafl/utils.c @@ -7,6 +7,7 @@ uintptr_t libafl_qemu_host_page_size(void) } #ifndef CONFIG_USER_ONLY + uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write) { if (addr == -1) { @@ -15,10 +16,13 @@ uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write) hwaddr xlat; MemoryRegion* mr; - WITH_RCU_READ_LOCK_GUARD() { - mr = address_space_translate(cpu->as, addr, &xlat, NULL, is_write, MEMTXATTRS_UNSPECIFIED); + 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 \ No newline at end of file + +#endif diff --git a/linux-user/signal.c b/linux-user/signal.c index df5cca6c9a..d3df87dd59 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -977,7 +977,6 @@ static uintptr_t host_sigbus_handler(CPUState *cpu, siginfo_t *info, // int libafl_qemu_is_tb_protected_write(int host_sig, siginfo_t *info, // host_sigcontext *uc); -void libafl_qemu_handle_crash(int host_sig, siginfo_t *info, void *puc); /* int libafl_qemu_is_tb_protected_write(int host_sig, siginfo_t *info, host_sigcontext *uc) @@ -998,6 +997,8 @@ void libafl_qemu_handle_crash(int host_sig, siginfo_t *info, void *puc); 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); } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b05fbfe1a0..82338df63c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -54,6 +54,11 @@ #include #include //#include +//// --- Begin LibAFL code --- + +#include "libafl/hooks/syscall.h" + +//// --- End LibAFL code --- #include #include #include @@ -6529,9 +6534,7 @@ typedef struct { //// --- Begin LibAFL code --- -#include "libafl/hook.h" - -extern __thread CPUArchState *libafl_qemu_env; +#include "libafl/hooks/thread.h" //// --- End LibAFL code --- @@ -6567,17 +6570,7 @@ static void *clone_func(void *arg) //// --- Begin LibAFL code --- - libafl_qemu_env = env; - if (libafl_new_thread_hooks) { - bool continue_execution = true; - int tid = sys_gettid(); - struct libafl_new_thread_hook* h = libafl_new_thread_hooks; - while (h) { - continue_execution = h->callback(h->data, tid) && continue_execution; - h = h->next; - } - if (continue_execution) cpu_loop(env); - } else { + if (libafl_hook_new_thread_run(env)) { cpu_loop(env); } @@ -13886,25 +13879,7 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1, //// --- Begin LibAFL code --- - bool skip_syscall = false; - struct libafl_pre_syscall_hook* h = libafl_pre_syscall_hooks; - while (h) { - // no null check - struct syshook_ret hook_ret = h->callback(h->data, num, - (target_ulong)arg1, - (target_ulong)arg2, - (target_ulong)arg3, - (target_ulong)arg4, - (target_ulong)arg5, - (target_ulong)arg6, - (target_ulong)arg7, - (target_ulong)arg8); - if (hook_ret.skip_syscall) { - skip_syscall = true; - ret = (abi_ulong)hook_ret.retval; - } - h = h->next; - } + bool skip_syscall = libafl_hook_syscall_pre_run(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, &ret); if (skip_syscall) goto after_syscall; //// --- End LibAFL code --- @@ -13915,21 +13890,8 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1, //// --- Begin LibAFL code --- after_syscall:; - struct libafl_post_syscall_hook* p = libafl_post_syscall_hooks; - while (p) { - // no null check - ret = (abi_ulong)p->callback(p->data, (target_ulong)ret, num, - (target_ulong)arg1, - (target_ulong)arg2, - (target_ulong)arg3, - (target_ulong)arg4, - (target_ulong)arg5, - (target_ulong)arg6, - (target_ulong)arg7, - (target_ulong)arg8); - p = p->next; - } - + libafl_hook_syscall_post_run(num, arg1, arg2, arg3, arg4, + arg5, arg6, arg7, arg8, &ret); //// --- End LibAFL code --- if (unlikely(qemu_loglevel_mask(LOG_STRACE))) { diff --git a/scripts/libafl-format.sh b/scripts/libafl-format.sh new file mode 100755 index 0000000000..b1d9cb94ca --- /dev/null +++ b/scripts/libafl-format.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +ROOT_DIR="$SCRIPT_DIR/.." + +if [ "$1" = "check" ]; then + CHECK="--dry-run --Werror" +elif [ "$1" != "" ]; then + echo "Unknown option: $1. Type 'check' to check without modifying any file; do not provide any argument to format automatically." + exit 1 +fi + +cd "$SCRIPT_DIR" || exit 1 +find "$ROOT_DIR/libafl" -name "*.c" -exec clang-format $CHECK -style="file:$ROOT_DIR/libafl/.clang-format" -i {} \; +find "$ROOT_DIR/include/libafl" -name "*.h" -exec clang-format $CHECK -style=file:"$ROOT_DIR/libafl/.clang-format" -i {} \; diff --git a/system/cpus.c b/system/cpus.c index de8fb01b5a..fe2ff359dd 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -647,6 +647,12 @@ const AccelOpsClass *cpus_get_accel(void) return cpus_accel; } +//// --- Begin LibAFL code --- + +// #include "libafl/hooks/thread.h" + +//// --- End LibAFL code --- + void qemu_init_vcpu(CPUState *cpu) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -671,6 +677,23 @@ void qemu_init_vcpu(CPUState *cpu) while (!cpu->created) { qemu_cond_wait(&qemu_cpu_cond, &bql); } + + //// --- Begin LibAFL code --- + + // if (libafl_new_thread_hooks) { + // bool continue_execution = true; + // struct libafl_new_thread_hook* h = libafl_new_thread_hooks; + // while (h) { + // continue_execution &= h->callback(h->data, cpu, 0); // TODO: should we keep TID in systemmode? could be useful for identification + // h = h->next; + // } + // if (!continue_execution) { + // // TODO: check if this is correct + // qemu_cpu_stop(cpu, true); + // } + // } + + //// --- End LibAFL code --- } void cpu_stop_current(void) diff --git a/target/arm/machine.c b/target/arm/machine.c index b2b39b2475..2da3528dbf 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -741,10 +741,14 @@ static int cpu_pre_save(void *opaque) } cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len; - memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes, - cpu->cpreg_array_len * sizeof(uint64_t)); - memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values, - cpu->cpreg_array_len * sizeof(uint64_t)); + + // Some ARM cpus like Cortex M do not have coprocessors + if (cpu->cpreg_array_len > 0) { + memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes, + cpu->cpreg_array_len * sizeof(uint64_t)); + memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values, + cpu->cpreg_array_len * sizeof(uint64_t)); + } return 0; }