experimental x86 support for compcov in QEMU
MODIFY
qemu_mode/build_qemu_support.sh
qemu_mode/build_qemu_support.sh
@@ -133,6 +133,7 @@ patch -p1 <../patches/cpu-exec.diff || exit 1
patch -p1 <../patches/syscall.diff || exit 1
patch -p1 <../patches/translate-all.diff || exit 1
patch -p1 <../patches/tcg.diff || exit 1
+patch -p1 <../patches/i386-translate.diff || exit 1
echo "[+] Patching done."

MODIFY
qemu_mode/patches/afl-qemu-cpu-inl.h
qemu_mode/patches/afl-qemu-cpu-inl.h
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;
@@ -157,6 +160,12 @@ static void afl_setup(void) {
}
+ 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
behaviour, and seems to work alright? */

ADD
qemu_mode/patches/afl-qemu-cpu-translate-inl.h
+/*
+ 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);
+}

MODIFY
qemu_mode/patches/afl-qemu-tcg-inl.h
qemu_mode/patches/afl-qemu-tcg-inl.h
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 */
+}
+

MODIFY
qemu_mode/patches/afl-qemu-translate-inl.h
qemu_mode/patches/afl-qemu-translate-inl.h
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. */

ADD
qemu_mode/patches/i386-translate.diff
+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;
+ }

experimental x86 support for compcov in QEMU