improve afl_maybe_log tcg call generation + merge elfload diffs

This commit is contained in:
Andrea Fioraldi
2019-06-05 11:48:36 +02:00
parent bcc0347eef
commit b59d71546b
7 changed files with 218 additions and 231 deletions

View File

@ -133,7 +133,6 @@ patch -p1 <../patches/cpu-exec.diff || exit 1
patch -p1 <../patches/syscall.diff || exit 1 patch -p1 <../patches/syscall.diff || exit 1
patch -p1 <../patches/translate-all.diff || exit 1 patch -p1 <../patches/translate-all.diff || exit 1
patch -p1 <../patches/tcg.diff || exit 1 patch -p1 <../patches/tcg.diff || exit 1
patch -p1 <../patches/elfload2.diff || exit 1
echo "[+] Patching done." echo "[+] Patching done."

View File

@ -9,6 +9,8 @@
TCG instrumentation and block chaining support by Andrea Biondo TCG instrumentation and block chaining support by Andrea Biondo
<andrea.biondo965@gmail.com> <andrea.biondo965@gmail.com>
QEMU 3.1.0 port and thread-safety by Andrea Fioraldi
<andreafioraldi@gmail.com>
Copyright 2015, 2016, 2017 Google Inc. All rights reserved. Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
@ -19,7 +21,7 @@
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
This code is a shim patched into the separately-distributed source This code is a shim patched into the separately-distributed source
code of QEMU 2.10.0. It leverages the built-in QEMU tracing functionality 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 to implement AFL-style instrumentation and to take care of the remaining
parts of the AFL fork server logic. parts of the AFL fork server logic.

View File

@ -0,0 +1,165 @@
/*
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 and thread-safety 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.
*/
void afl_maybe_log(void* cur_loc);
/* Note: we convert the 64 bit args to 32 bit and do some alignment
and endian swap. Maybe it would be better to do the alignment
and endian swap in tcg_reg_alloc_call(). */
void tcg_gen_afl_maybe_log_call(target_ulong cur_loc)
{
int real_args, pi;
unsigned sizemask, flags;
TCGOp *op;
TCGTemp *arg = tcgv_ptr_temp( tcg_const_tl(cur_loc) );
flags = 0;
sizemask = dh_sizemask(void, 0) | dh_sizemask(ptr, 1);
#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;
TCGv_i64 retl, reth;
TCGTemp *split_args[MAX_OPC_PARAM];
retl = NULL;
reth = NULL;
if (sizemask != 0) {
real_args = 0;
int is_64bit = sizemask & (1 << 2);
if (is_64bit) {
TCGv_i64 orig = temp_tcgv_i64(arg);
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++] = arg;
}
nargs = real_args;
args = split_args;
sizemask = 0;
}
#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
int is_64bit = sizemask & (1 << 2);
int is_signed = sizemask & (2 << 2);
if (!is_64bit) {
TCGv_i64 temp = tcg_temp_new_i64();
TCGv_i64 orig = temp_tcgv_i64(arg);
if (is_signed) {
tcg_gen_ext32s_i64(temp, orig);
} else {
tcg_gen_ext32u_i64(temp, orig);
}
arg = tcgv_i64_temp(temp);
}
#endif /* TCG_TARGET_EXTEND_ARGS */
op = tcg_emit_op(INDEX_op_call);
pi = 0;
TCGOP_CALLO(op) = 0;
real_args = 0;
int is_64bit = sizemask & (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(arg + 1);
op->args[pi++] = temp_arg(arg);
#else
op->args[pi++] = temp_arg(arg);
op->args[pi++] = temp_arg(arg + 1);
#endif
real_args += 2;
}
op->args[pi++] = temp_arg(arg);
real_args++;
op->args[pi++] = (uintptr_t)&afl_maybe_log;
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. */
real_args = 0;
int is_64bit = orig_sizemask & (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(ret), retl, reth);
tcg_temp_free_i64(retl);
tcg_temp_free_i64(reth);
}
#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
int is_64bit = sizemask & (1 << 2);
if (!is_64bit) {
tcg_temp_free_internal(arg);
}
#endif /* TCG_TARGET_EXTEND_ARGS */
}

View File

@ -9,6 +9,8 @@
TCG instrumentation and block chaining support by Andrea Biondo TCG instrumentation and block chaining support by Andrea Biondo
<andrea.biondo965@gmail.com> <andrea.biondo965@gmail.com>
QEMU 3.1.0 port and thread-safety by Andrea Fioraldi
<andreafioraldi@gmail.com>
Copyright 2015, 2016, 2017 Google Inc. All rights reserved. Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
@ -19,7 +21,7 @@
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
This code is a shim patched into the separately-distributed source This code is a shim patched into the separately-distributed source
code of QEMU 2.10.0. It leverages the built-in QEMU tracing functionality 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 to implement AFL-style instrumentation and to take care of the remaining
parts of the AFL fork server logic. parts of the AFL fork server logic.
@ -37,19 +39,17 @@ extern unsigned char *afl_area_ptr;
extern unsigned int afl_inst_rms; extern unsigned int afl_inst_rms;
extern abi_ulong afl_start_code, afl_end_code; extern abi_ulong afl_start_code, afl_end_code;
void tcg_gen_afl_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args); void tcg_gen_afl_maybe_log_call(target_ulong cur_loc);
void afl_maybe_log(void* cur_loc) {
void afl_maybe_log(abi_ulong cur_loc) {
static __thread abi_ulong prev_loc; static __thread abi_ulong prev_loc;
afl_area_ptr[cur_loc ^ prev_loc]++; afl_area_ptr[(abi_ulong)cur_loc ^ prev_loc]++;
prev_loc = cur_loc >> 1; prev_loc = (abi_ulong)cur_loc >> 1;
} }
/* Generates TCG code for AFL's tracing instrumentation. */ /* Generates TCG code for AFL's tracing instrumentation. */
static void afl_gen_trace(target_ulong cur_loc) { static void afl_gen_trace(target_ulong cur_loc) {
@ -71,7 +71,6 @@ static void afl_gen_trace(target_ulong cur_loc) {
if (cur_loc >= afl_inst_rms) return; if (cur_loc >= afl_inst_rms) return;
TCGTemp *args[1] = { tcgv_i64_temp( tcg_const_tl(cur_loc) ) }; tcg_gen_afl_maybe_log_call(cur_loc);
tcg_gen_afl_callN(afl_maybe_log, NULL, 1, args);
} }

View File

@ -1,5 +1,5 @@
diff --git a/linux-user/elfload.c b/linux-user/elfload.c diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 5bccd2e2..94e928a4 100644 index 5bccd2e2..fd7460b3 100644
--- a/linux-user/elfload.c --- a/linux-user/elfload.c
+++ b/linux-user/elfload.c +++ b/linux-user/elfload.c
@@ -20,6 +20,8 @@ @@ -20,6 +20,8 @@
@ -11,16 +11,29 @@ index 5bccd2e2..94e928a4 100644
/* from personality.h */ /* from personality.h */
/* /*
@@ -2301,6 +2303,8 @@ static void load_elf_image(const char *image_name, int image_fd, @@ -2301,6 +2303,21 @@ static void load_elf_image(const char *image_name, int image_fd,
info->brk = 0; info->brk = 0;
info->elf_flags = ehdr->e_flags; info->elf_flags = ehdr->e_flags;
+ if (!afl_entry_point) afl_entry_point = info->entry; + if (!afl_entry_point) {
+ char *ptr;
+ if ((ptr = getenv("AFL_ENTRYPOINT")) != NULL) {
+ afl_entry_point = strtoul(ptr, NULL, 16);
+ } else {
+ afl_entry_point = info->entry;
+ }
+#ifdef TARGET_ARM
+ /* The least significant bit indicates Thumb mode. */
+ afl_entry_point = afl_entry_point & ~(target_ulong)1;
+#endif
+ }
+ if (getenv("AFL_DEBUG") != NULL)
+ fprintf(stderr, "AFL forkserver entrypoint: %p\n", (void*)afl_entry_point);
+ +
for (i = 0; i < ehdr->e_phnum; i++) { for (i = 0; i < ehdr->e_phnum; i++) {
struct elf_phdr *eppnt = phdr + i; struct elf_phdr *eppnt = phdr + i;
if (eppnt->p_type == PT_LOAD) { if (eppnt->p_type == PT_LOAD) {
@@ -2335,9 +2339,11 @@ static void load_elf_image(const char *image_name, int image_fd, @@ -2335,9 +2352,11 @@ static void load_elf_image(const char *image_name, int image_fd,
if (elf_prot & PROT_EXEC) { if (elf_prot & PROT_EXEC) {
if (vaddr < info->start_code) { if (vaddr < info->start_code) {
info->start_code = vaddr; info->start_code = vaddr;
@ -32,3 +45,26 @@ index 5bccd2e2..94e928a4 100644
} }
} }
if (elf_prot & PROT_WRITE) { if (elf_prot & PROT_WRITE) {
@@ -2662,6 +2681,22 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
change some of these later */
bprm->p = setup_arg_pages(bprm, info);
+ // On PowerPC64 the entry point is the _function descriptor_
+ // of the entry function. For AFL to properly initialize,
+ // afl_entry_point needs to be set to the actual first instruction
+ // as opposed executed by the target program. This as opposed to
+ // where the function's descriptor sits in memory.
+ // copied from PPC init_thread
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+ if (get_ppc64_abi(infop) < 2) {
+ uint64_t val;
+ get_user_u64(val, infop->entry + 8);
+ _regs->gpr[2] = val + infop->load_bias;
+ get_user_u64(val, infop->entry);
+ infop->entry = val + infop->load_bias;
+ }
+#endif
+
scratch = g_new0(char, TARGET_PAGE_SIZE);
if (STACK_GROWS_DOWN) {
bprm->p = copy_elf_strings(1, &bprm->filename, scratch,

View File

@ -1,47 +0,0 @@
--- a/linux-user/elfload.c 2019-06-03 13:06:40.755755923 +0200
+++ b/linux-user/elfload.c 2019-06-03 13:33:01.315709801 +0200
@@ -2303,7 +2303,20 @@
info->brk = 0;
info->elf_flags = ehdr->e_flags;
- if (!afl_entry_point) afl_entry_point = info->entry;
+ if (!afl_entry_point) {
+ char *ptr;
+ if ((ptr = getenv("AFL_ENTRYPOINT")) != NULL) {
+ afl_entry_point = strtoul(ptr, NULL, 16);
+ } else {
+ afl_entry_point = info->entry;
+ }
+#ifdef TARGET_ARM
+ /* The least significant bit indicates Thumb mode. */
+ afl_entry_point = afl_entry_point & ~(target_ulong)1;
+#endif
+ }
+ if (getenv("AFL_DEBUG") != NULL)
+ fprintf(stderr, "AFL forkserver entrypoint: %p\n", (void*)afl_entry_point);
for (i = 0; i < ehdr->e_phnum; i++) {
struct elf_phdr *eppnt = phdr + i;
@@ -2668,6 +2681,22 @@
change some of these later */
bprm->p = setup_arg_pages(bprm, info);
+ // On PowerPC64 the entry point is the _function descriptor_
+ // of the entry function. For AFL to properly initialize,
+ // afl_entry_point needs to be set to the actual first instruction
+ // as opposed executed by the target program. This as opposed to
+ // where the function's descriptor sits in memory.
+ // copied from PPC init_thread
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+ if (get_ppc64_abi(infop) < 2) {
+ uint64_t val;
+ get_user_u64(val, infop->entry + 8);
+ _regs->gpr[2] = val + infop->load_bias;
+ get_user_u64(val, infop->entry);
+ infop->entry = val + infop->load_bias;
+ }
+#endif
+
scratch = g_new0(char, TARGET_PAGE_SIZE);
if (STACK_GROWS_DOWN) {
bprm->p = copy_elf_strings(1, &bprm->filename, scratch,

View File

@ -2,179 +2,12 @@ diff --git a/tcg/tcg.c b/tcg/tcg.c
index e85133ef..54b9b390 100644 index e85133ef..54b9b390 100644
--- a/tcg/tcg.c --- a/tcg/tcg.c
+++ b/tcg/tcg.c +++ b/tcg/tcg.c
@@ -1612,6 +1612,176 @@ bool tcg_op_supported(TCGOpcode op) @@ -1612,6 +1612,9 @@ bool tcg_op_supported(TCGOpcode op)
} }
} }
+ +
+/* Call the instrumentation function from the TCG IR */ +#include "../../patches/afl-qemu-tcg-inl.h"
+void tcg_gen_afl_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
+{
+ int i, real_args, nb_rets, pi;
+ unsigned sizemask, flags;
+ TCGOp *op;
+
+ flags = 0;
+ sizemask = 0;
+
+#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;
+ if (ret != NULL) {
+#if defined(__sparc__) && !defined(__arch64__) \
+ && !defined(CONFIG_TCG_INTERPRETER)
+ if (orig_sizemask & 1) {
+ /* The 32-bit ABI is going to return the 64-bit value in
+ the %o0/%o1 register pair. Prepare for this by using
+ two return temporaries, and reassemble below. */
+ retl = tcg_temp_new_i64();
+ reth = tcg_temp_new_i64();
+ op->args[pi++] = tcgv_i64_arg(reth);
+ op->args[pi++] = tcgv_i64_arg(retl);
+ nb_rets = 2;
+ } else {
+ op->args[pi++] = temp_arg(ret);
+ nb_rets = 1;
+ }
+#else
+ if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
+#ifdef HOST_WORDS_BIGENDIAN
+ op->args[pi++] = temp_arg(ret + 1);
+ op->args[pi++] = temp_arg(ret);
+#else
+ op->args[pi++] = temp_arg(ret);
+ op->args[pi++] = temp_arg(ret + 1);
+#endif
+ nb_rets = 2;
+ } else {
+ op->args[pi++] = temp_arg(ret);
+ nb_rets = 1;
+ }
+#endif
+ } else {
+ 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(ret), 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 */
+}
+
+ +
/* Note: we convert the 64 bit args to 32 bit and do some alignment /* Note: we convert the 64 bit args to 32 bit and do some alignment
and endian swap. Maybe it would be better to do the alignment and endian swap. Maybe it would be better to do the alignment