compcov levels to enable the instrumentation of only immediates
MODIFY
qemu_mode/libcompcov/README.compcov
qemu_mode/libcompcov/README.compcov
@@ -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

MODIFY
qemu_mode/libcompcov/libcompcov.so.c
qemu_mode/libcompcov/libcompcov.so.c
@@ -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;

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

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

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

compcov levels to enable the instrumentation of only immediates