diff options
Diffstat (limited to 'qemu_mode/patches')
-rw-r--r-- | qemu_mode/patches/afl-qemu-cpu-inl.h | 11 | ||||
-rw-r--r-- | qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 125 | ||||
-rw-r--r-- | qemu_mode/patches/afl-qemu-tcg-inl.h | 149 | ||||
-rw-r--r-- | qemu_mode/patches/afl-qemu-translate-inl.h | 11 | ||||
-rw-r--r-- | qemu_mode/patches/i386-translate.diff | 33 |
5 files changed, 319 insertions, 10 deletions
diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 32030408..a6a36de5 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -9,7 +9,8 @@ TCG instrumentation and block chaining support by Andrea Biondo <andrea.biondo965@gmail.com> - QEMU 3.1.0 port and thread-safety by Andrea Fioraldi + + QEMU 3.1.0 port, TCG thread-safety and CompareCoverage by Andrea Fioraldi <andreafioraldi@gmail.com> Copyright 2015, 2016, 2017 Google Inc. All rights reserved. @@ -65,6 +66,8 @@ abi_ulong afl_entry_point, /* ELF entry point (_start) */ afl_start_code, /* .text start pointer */ afl_end_code; /* .text end pointer */ +u8 afl_enable_compcov; + /* Set in the child process in forkserver mode: */ static int forkserver_installed = 0; @@ -156,6 +159,12 @@ static void afl_setup(void) { afl_end_code = (abi_ulong)-1; } + + if (getenv("AFL_QEMU_COMPCOV")) { + +fprintf(stderr, "EEe\n"); + afl_enable_compcov = 1; + } /* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm not entirely sure what is the cause. This disables that diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h new file mode 100644 index 00000000..07ef9e11 --- /dev/null +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -0,0 +1,125 @@ +/* + american fuzzy lop - high-performance binary-only instrumentation + ----------------------------------------------------------------- + + Written by Andrew Griffiths <agriffiths@google.com> and + Michal Zalewski <lcamtuf@google.com> + + Idea & design very much by Andrew Griffiths. + + TCG instrumentation and block chaining support by Andrea Biondo + <andrea.biondo965@gmail.com> + + QEMU 3.1.0 port, TCG thread-safety and CompareCoverage by Andrea Fioraldi + <andreafioraldi@gmail.com> + + Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This code is a shim patched into the separately-distributed source + code of QEMU 3.1.0. It leverages the built-in QEMU tracing functionality + to implement AFL-style instrumentation and to take care of the remaining + parts of the AFL fork server logic. + + The resulting QEMU binary is essentially a standalone instrumentation + tool; for an example of how to leverage it for other purposes, you can + have a look at afl-showmap.c. + + */ + +#include "../../config.h" +#include "tcg.h" +#include "tcg-op.h" + +/* Declared in afl-qemu-cpu-inl.h */ +extern unsigned char *afl_area_ptr; +extern unsigned int afl_inst_rms; +extern abi_ulong afl_start_code, afl_end_code; +extern u8 afl_enable_compcov; + +void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc, + TCGv_i64 arg1, TCGv_i64 arg2); + +static void afl_compcov_log_16(target_ulong cur_loc, target_ulong arg1, + target_ulong arg2) { + + if ((arg1 & 0xff) == (arg2 & 0xff)) { + afl_area_ptr[cur_loc]++; + } +} + +static void afl_compcov_log_32(target_ulong cur_loc, target_ulong arg1, + target_ulong arg2) { + + if ((arg1 & 0xff) == (arg2 & 0xff)) { + afl_area_ptr[cur_loc]++; + if ((arg1 & 0xffff) == (arg2 & 0xffff)) { + afl_area_ptr[cur_loc +1]++; + if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { + afl_area_ptr[cur_loc +2]++; + } + } + } +} + +static void afl_compcov_log_64(target_ulong cur_loc, target_ulong arg1, + target_ulong arg2) { + + if ((arg1 & 0xff) == (arg2 & 0xff)) { + afl_area_ptr[cur_loc]++; + if ((arg1 & 0xffff) == (arg2 & 0xffff)) { + afl_area_ptr[cur_loc +1]++; + if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { + afl_area_ptr[cur_loc +2]++; + if ((arg1 & 0xffffffff) == (arg2 & 0xffffffff)) { + afl_area_ptr[cur_loc +3]++; + if ((arg1 & 0xffffffff) == (arg2 & 0xffffffffff)) { + afl_area_ptr[cur_loc +4]++; + if ((arg1 & 0xffffffff) == (arg2 & 0xffffffffffff)) { + afl_area_ptr[cur_loc +5]++; + if ((arg1 & 0xffffffff) == (arg2 & 0xffffffffffffff)) { + afl_area_ptr[cur_loc +6]++; + } + } + } + } + } + } + } +} + + +static void afl_gen_compcov(target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2, + TCGMemOp ot) { + + void *func; + + if (!afl_enable_compcov || cur_loc > afl_end_code || cur_loc < afl_start_code) + return; + + switch (ot) { + case MO_64: + func = &afl_compcov_log_64; + break; + case MO_32: + func = &afl_compcov_log_32; + break; + case MO_16: + func = &afl_compcov_log_16; + break; + default: + return; + } + + cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); + cur_loc &= MAP_SIZE - 1; + + if (cur_loc >= afl_inst_rms) return; + + tcg_gen_afl_compcov_log_call(func, cur_loc, arg1, arg2); +} diff --git a/qemu_mode/patches/afl-qemu-tcg-inl.h b/qemu_mode/patches/afl-qemu-tcg-inl.h index fab3d9e3..ff90d1b9 100644 --- a/qemu_mode/patches/afl-qemu-tcg-inl.h +++ b/qemu_mode/patches/afl-qemu-tcg-inl.h @@ -9,7 +9,8 @@ TCG instrumentation and block chaining support by Andrea Biondo <andrea.biondo965@gmail.com> - QEMU 3.1.0 port and thread-safety by Andrea Fioraldi + + QEMU 3.1.0 port, TCG thread-safety and CompareCoverage by Andrea Fioraldi <andreafioraldi@gmail.com> Copyright 2015, 2016, 2017 Google Inc. All rights reserved. @@ -42,10 +43,10 @@ void tcg_gen_afl_maybe_log_call(target_ulong cur_loc) unsigned sizemask, flags; TCGOp *op; - TCGTemp *arg = tcgv_ptr_temp( tcg_const_tl(cur_loc) ); + TCGTemp *arg = tcgv_i64_temp( tcg_const_tl(cur_loc) ); flags = 0; - sizemask = dh_sizemask(void, 0) | dh_sizemask(ptr, 1); + sizemask = dh_sizemask(void, 0) | dh_sizemask(i64, 1); #if defined(__sparc__) && !defined(__arch64__) \ && !defined(CONFIG_TCG_INTERPRETER) @@ -151,7 +152,7 @@ void tcg_gen_afl_maybe_log_call(target_ulong cur_loc) /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. Note that describing these as TCGv_i64 eliminates an unnecessary zero-extension that tcg_gen_concat_i32_i64 would create. */ - tcg_gen_concat32_i64(temp_tcgv_i64(ret), retl, reth); + tcg_gen_concat32_i64(temp_tcgv_i64(NULL), retl, reth); tcg_temp_free_i64(retl); tcg_temp_free_i64(reth); } @@ -163,3 +164,143 @@ void tcg_gen_afl_maybe_log_call(target_ulong cur_loc) #endif /* TCG_TARGET_EXTEND_ARGS */ } +void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2) +{ + int i, real_args, nb_rets, pi; + unsigned sizemask, flags; + TCGOp *op; + + const int nargs = 3; + TCGTemp *args[3] = { tcgv_i64_temp( tcg_const_tl(cur_loc) ), + tcgv_i64_temp(arg1), + tcgv_i64_temp(arg2) }; + + flags = 0; + sizemask = dh_sizemask(void, 0) | dh_sizemask(i64, 1) | + dh_sizemask(i64, 2) | dh_sizemask(i64, 3); + +#if defined(__sparc__) && !defined(__arch64__) \ + && !defined(CONFIG_TCG_INTERPRETER) + /* We have 64-bit values in one register, but need to pass as two + separate parameters. Split them. */ + int orig_sizemask = sizemask; + int orig_nargs = nargs; + TCGv_i64 retl, reth; + TCGTemp *split_args[MAX_OPC_PARAM]; + + retl = NULL; + reth = NULL; + if (sizemask != 0) { + for (i = real_args = 0; i < nargs; ++i) { + int is_64bit = sizemask & (1 << (i+1)*2); + if (is_64bit) { + TCGv_i64 orig = temp_tcgv_i64(args[i]); + TCGv_i32 h = tcg_temp_new_i32(); + TCGv_i32 l = tcg_temp_new_i32(); + tcg_gen_extr_i64_i32(l, h, orig); + split_args[real_args++] = tcgv_i32_temp(h); + split_args[real_args++] = tcgv_i32_temp(l); + } else { + split_args[real_args++] = args[i]; + } + } + nargs = real_args; + args = split_args; + sizemask = 0; + } +#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 + for (i = 0; i < nargs; ++i) { + int is_64bit = sizemask & (1 << (i+1)*2); + int is_signed = sizemask & (2 << (i+1)*2); + if (!is_64bit) { + TCGv_i64 temp = tcg_temp_new_i64(); + TCGv_i64 orig = temp_tcgv_i64(args[i]); + if (is_signed) { + tcg_gen_ext32s_i64(temp, orig); + } else { + tcg_gen_ext32u_i64(temp, orig); + } + args[i] = tcgv_i64_temp(temp); + } + } +#endif /* TCG_TARGET_EXTEND_ARGS */ + + op = tcg_emit_op(INDEX_op_call); + + pi = 0; + nb_rets = 0; + TCGOP_CALLO(op) = nb_rets; + + real_args = 0; + for (i = 0; i < nargs; i++) { + int is_64bit = sizemask & (1 << (i+1)*2); + if (TCG_TARGET_REG_BITS < 64 && is_64bit) { +#ifdef TCG_TARGET_CALL_ALIGN_ARGS + /* some targets want aligned 64 bit args */ + if (real_args & 1) { + op->args[pi++] = TCG_CALL_DUMMY_ARG; + real_args++; + } +#endif + /* If stack grows up, then we will be placing successive + arguments at lower addresses, which means we need to + reverse the order compared to how we would normally + treat either big or little-endian. For those arguments + that will wind up in registers, this still works for + HPPA (the only current STACK_GROWSUP target) since the + argument registers are *also* allocated in decreasing + order. If another such target is added, this logic may + have to get more complicated to differentiate between + stack arguments and register arguments. */ +#if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) + op->args[pi++] = temp_arg(args[i] + 1); + op->args[pi++] = temp_arg(args[i]); +#else + op->args[pi++] = temp_arg(args[i]); + op->args[pi++] = temp_arg(args[i] + 1); +#endif + real_args += 2; + continue; + } + + op->args[pi++] = temp_arg(args[i]); + real_args++; + } + op->args[pi++] = (uintptr_t)func; + op->args[pi++] = flags; + TCGOP_CALLI(op) = real_args; + + /* Make sure the fields didn't overflow. */ + tcg_debug_assert(TCGOP_CALLI(op) == real_args); + tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); + +#if defined(__sparc__) && !defined(__arch64__) \ + && !defined(CONFIG_TCG_INTERPRETER) + /* Free all of the parts we allocated above. */ + for (i = real_args = 0; i < orig_nargs; ++i) { + int is_64bit = orig_sizemask & (1 << (i+1)*2); + if (is_64bit) { + tcg_temp_free_internal(args[real_args++]); + tcg_temp_free_internal(args[real_args++]); + } else { + real_args++; + } + } + if (orig_sizemask & 1) { + /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. + Note that describing these as TCGv_i64 eliminates an unnecessary + zero-extension that tcg_gen_concat_i32_i64 would create. */ + tcg_gen_concat32_i64(temp_tcgv_i64(NULL), retl, reth); + tcg_temp_free_i64(retl); + tcg_temp_free_i64(reth); + } +#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 + for (i = 0; i < nargs; ++i) { + int is_64bit = sizemask & (1 << (i+1)*2); + if (!is_64bit) { + tcg_temp_free_internal(args[i]); + } + } +#endif /* TCG_TARGET_EXTEND_ARGS */ +} + diff --git a/qemu_mode/patches/afl-qemu-translate-inl.h b/qemu_mode/patches/afl-qemu-translate-inl.h index 74c827f5..bfb2897e 100644 --- a/qemu_mode/patches/afl-qemu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-translate-inl.h @@ -9,7 +9,8 @@ TCG instrumentation and block chaining support by Andrea Biondo <andrea.biondo965@gmail.com> - QEMU 3.1.0 port and thread-safety by Andrea Fioraldi + + QEMU 3.1.0 port, TCG thread-safety and CompareCoverage by Andrea Fioraldi <andreafioraldi@gmail.com> Copyright 2015, 2016, 2017 Google Inc. All rights reserved. @@ -41,12 +42,12 @@ extern abi_ulong afl_start_code, afl_end_code; void tcg_gen_afl_maybe_log_call(target_ulong cur_loc); -void afl_maybe_log(void* cur_loc) { +void afl_maybe_log(target_ulong cur_loc) { static __thread abi_ulong prev_loc; - afl_area_ptr[(abi_ulong)cur_loc ^ prev_loc]++; - prev_loc = (abi_ulong)cur_loc >> 1; + afl_area_ptr[cur_loc ^ prev_loc]++; + prev_loc = cur_loc >> 1; } @@ -59,7 +60,7 @@ static void afl_gen_trace(target_ulong cur_loc) { if (cur_loc > afl_end_code || cur_loc < afl_start_code /*|| !afl_area_ptr*/) // not needed because of static dummy buffer return; - /* Looks like QEMU always maps to fixed locations, so ASAN is not a + /* Looks like QEMU always maps to fixed locations, so ASLR is not a concern. Phew. But instruction addresses may be aligned. Let's mangle the value to get something quasi-uniform. */ diff --git a/qemu_mode/patches/i386-translate.diff b/qemu_mode/patches/i386-translate.diff new file mode 100644 index 00000000..0bc48828 --- /dev/null +++ b/qemu_mode/patches/i386-translate.diff @@ -0,0 +1,33 @@ +diff --git a/target/i386/translate.c b/target/i386/translate.c +index 0dd5fbe4..b95d341e 100644 +--- a/target/i386/translate.c ++++ b/target/i386/translate.c +@@ -32,6 +32,8 @@ + #include "trace-tcg.h" + #include "exec/log.h" + ++#include "../patches/afl-qemu-cpu-translate-inl.h" ++ + #define PREFIX_REPZ 0x01 + #define PREFIX_REPNZ 0x02 + #define PREFIX_LOCK 0x04 +@@ -1343,9 +1345,11 @@ static void gen_op(DisasContext *s1, int op, TCGMemOp ot, int d) + tcg_gen_atomic_fetch_add_tl(s1->cc_srcT, s1->A0, s1->T0, + s1->mem_index, ot | MO_LE); + tcg_gen_sub_tl(s1->T0, s1->cc_srcT, s1->T1); ++ afl_gen_compcov(s1->pc, s1->cc_srcT, s1->T1, ot); + } else { + tcg_gen_mov_tl(s1->cc_srcT, s1->T0); + tcg_gen_sub_tl(s1->T0, s1->T0, s1->T1); ++ afl_gen_compcov(s1->pc, s1->T0, s1->T1, ot); + gen_op_st_rm_T0_A0(s1, ot, d); + } + gen_op_update2_cc(s1); +@@ -1389,6 +1393,7 @@ static void gen_op(DisasContext *s1, int op, TCGMemOp ot, int d) + tcg_gen_mov_tl(cpu_cc_src, s1->T1); + tcg_gen_mov_tl(s1->cc_srcT, s1->T0); + tcg_gen_sub_tl(cpu_cc_dst, s1->T0, s1->T1); ++ afl_gen_compcov(s1->pc, s1->T0, s1->T1, ot); + set_cc_op(s1, CC_OP_SUBB + ot); + break; + } |