compcov levels to enable the instrumentation of only immediates

This commit is contained in:
Andrea Fioraldi
2019-07-29 16:09:28 +02:00
parent 7ca22cd552
commit d6beac5235
5 changed files with 71 additions and 15 deletions

View File

@ -18,15 +18,19 @@ For optimized binaries this is an issue, those functions are often inlined
and this module is not capable to log the coverage in this case.
If you have the source code of the fuzzing target you should nto use this
library and QEMU but build ot with afl-clang-fast and the laf-intel options.
library and QEMU but build it with afl-clang-fast and the laf-intel options.
To use this library make sure to preload it with AFL_PRELOAD.
export AFL_PRELOAD=/path/to/libcompcov.so
export AFL_QEMU_COMPCOV=1
export AFL_COMPCOV_LEVEL=1
afl-fuzz -Q -i input -o output <your options> -- <target args>
The AFL_COMPCOV_LEVEL tells to QEMU and libcompcov how to log comaprisons.
Level 1 logs just comparison with immediates / read-only memory and level 2
logs all the comparisons.
The library make use of https://github.com/ouadev/proc_maps_parser and so it is
Linux specific. However this is not a strict dependency, other UNIX operating
systems can be supported simply replacing the code related to the

View File

@ -45,6 +45,8 @@ static void *__compcov_code_start,
static u8 *__compcov_afl_map;
static u32 __compcov_level;
static int (*__libc_strcmp)(const char*, const char*);
static int (*__libc_strncmp)(const char*, const char*, size_t);
static int (*__libc_strcasecmp)(const char*, const char*);
@ -54,6 +56,28 @@ static int (*__libc_memcmp)(const void*, const void*, size_t);
static int debug_fd = -1;
#define MAX_MAPPINGS 1024
static struct mapping {
void *st, *en;
} __compcov_ro[MAX_MAPPINGS];
static u32 __compcov_ro_cnt;
/* Check an address against the list of read-only mappings. */
static u8 __compcov_is_ro(const void* ptr) {
u32 i;
for (i = 0; i < __compcov_ro_cnt; i++)
if (ptr >= __compcov_ro[i].st && ptr <= __compcov_ro[i].en) return 1;
return 0;
}
static size_t __strlen2(const char *s1, const char *s2, size_t max_length) {
// from https://github.com/googleprojectzero/CompareCoverage
@ -72,6 +96,15 @@ static void __compcov_load(void) {
__libc_strncasecmp = dlsym(RTLD_NEXT, "strncasecmp");
__libc_memcmp = dlsym(RTLD_NEXT, "memcmp");
if (getenv("AFL_QEMU_COMPCOV")) {
__compcov_level = 1;
}
if (getenv("AFL_COMPCOV_LEVEL")) {
__compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL"));
}
char *id_str = getenv(SHM_ENV_VAR);
int shm_id;
@ -110,6 +143,12 @@ static void __compcov_load(void) {
__compcov_code_end = maps_tmp->addr_end;
}
}
if ((maps_tmp->is_w && !maps_tmp->is_r) || __compcov_ro_cnt == MAX_MAPPINGS)
continue;
__compcov_ro[__compcov_ro_cnt].st = maps_tmp->addr_start;
__compcov_ro[__compcov_ro_cnt].en = maps_tmp->addr_end;
}
pmparser_free(maps);
@ -149,7 +188,8 @@ int strcmp(const char* str1, const char* str2) {
void* retaddr = __builtin_return_address(0);
if (__compcov_is_in_bound(retaddr)) {
if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 &&
!__compcov_is_ro(str1) && !__compcov_is_ro(str2))) {
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1);
@ -173,7 +213,8 @@ int strncmp(const char* str1, const char* str2, size_t len) {
void* retaddr = __builtin_return_address(0);
if (__compcov_is_in_bound(retaddr)) {
if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 &&
!__compcov_is_ro(str1) && !__compcov_is_ro(str2))) {
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1);
n = MIN(n, len);
@ -198,7 +239,8 @@ int strcasecmp(const char* str1, const char* str2) {
void* retaddr = __builtin_return_address(0);
if (__compcov_is_in_bound(retaddr)) {
if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 &&
!__compcov_is_ro(str1) && !__compcov_is_ro(str2))) {
/* Fallback to strcmp, maybe improve in future */
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1);
@ -223,7 +265,8 @@ int strncasecmp(const char* str1, const char* str2, size_t len) {
void* retaddr = __builtin_return_address(0);
if (__compcov_is_in_bound(retaddr)) {
if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 &&
!__compcov_is_ro(str1) && !__compcov_is_ro(str2))) {
/* Fallback to strncmp, maybe improve in future */
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1);
@ -249,7 +292,8 @@ int memcmp(const void* mem1, const void* mem2, size_t len) {
void* retaddr = __builtin_return_address(0);
if (__compcov_is_in_bound(retaddr)) {
if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 &&
!__compcov_is_ro(mem1) && !__compcov_is_ro(mem2))) {
size_t n = len;

View File

@ -66,7 +66,7 @@ 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;
u8 afl_compcov_level;
/* Set in the child process in forkserver mode: */
@ -159,9 +159,14 @@ static void afl_setup(void) {
}
/* Maintain for compatibility */
if (getenv("AFL_QEMU_COMPCOV")) {
afl_enable_compcov = 1;
afl_compcov_level = 1;
}
if (getenv("AFL_COMPCOV_LEVEL")) {
afl_compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL"));
}
/* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm

View File

@ -40,7 +40,7 @@
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;
extern u8 afl_compcov_level;
void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc,
TCGv_i64 arg1, TCGv_i64 arg2);
@ -95,11 +95,14 @@ static void afl_compcov_log_64(target_ulong cur_loc, target_ulong arg1,
static void afl_gen_compcov(target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2,
TCGMemOp ot) {
TCGMemOp ot, int is_imm) {
void *func;
if (!afl_enable_compcov || cur_loc > afl_end_code || cur_loc < afl_start_code)
if (!afl_compcov_level || cur_loc > afl_end_code || cur_loc < afl_start_code)
return;
if (!is_imm && afl_compcov_level < 2)
return;
switch (ot) {

View File

@ -15,11 +15,11 @@ index 0dd5fbe4..b95d341e 100644
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);
+ afl_gen_compcov(s1->pc, s1->cc_srcT, s1->T1, ot, d == OR_EAX);
} 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);
+ afl_gen_compcov(s1->pc, s1->T0, s1->T1, ot, d == OR_EAX);
gen_op_st_rm_T0_A0(s1, ot, d);
}
gen_op_update2_cc(s1);
@ -27,7 +27,7 @@ index 0dd5fbe4..b95d341e 100644
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);
+ afl_gen_compcov(s1->pc, s1->T0, s1->T1, ot, d == OR_EAX);
set_cc_op(s1, CC_OP_SUBB + ot);
break;
}