mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-16 11:58:08 +00:00
compcov levels to enable the instrumentation of only immediates
This commit is contained in:
@ -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.
|
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
|
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.
|
To use this library make sure to preload it with AFL_PRELOAD.
|
||||||
|
|
||||||
export AFL_PRELOAD=/path/to/libcompcov.so
|
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>
|
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
|
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
|
Linux specific. However this is not a strict dependency, other UNIX operating
|
||||||
systems can be supported simply replacing the code related to the
|
systems can be supported simply replacing the code related to the
|
||||||
|
@ -45,6 +45,8 @@ static void *__compcov_code_start,
|
|||||||
|
|
||||||
static u8 *__compcov_afl_map;
|
static u8 *__compcov_afl_map;
|
||||||
|
|
||||||
|
static u32 __compcov_level;
|
||||||
|
|
||||||
static int (*__libc_strcmp)(const char*, const char*);
|
static int (*__libc_strcmp)(const char*, const char*);
|
||||||
static int (*__libc_strncmp)(const char*, const char*, size_t);
|
static int (*__libc_strncmp)(const char*, const char*, size_t);
|
||||||
static int (*__libc_strcasecmp)(const char*, const char*);
|
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;
|
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) {
|
static size_t __strlen2(const char *s1, const char *s2, size_t max_length) {
|
||||||
// from https://github.com/googleprojectzero/CompareCoverage
|
// from https://github.com/googleprojectzero/CompareCoverage
|
||||||
|
|
||||||
@ -71,6 +95,15 @@ static void __compcov_load(void) {
|
|||||||
__libc_strcasecmp = dlsym(RTLD_NEXT, "strcasecmp");
|
__libc_strcasecmp = dlsym(RTLD_NEXT, "strcasecmp");
|
||||||
__libc_strncasecmp = dlsym(RTLD_NEXT, "strncasecmp");
|
__libc_strncasecmp = dlsym(RTLD_NEXT, "strncasecmp");
|
||||||
__libc_memcmp = dlsym(RTLD_NEXT, "memcmp");
|
__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);
|
char *id_str = getenv(SHM_ENV_VAR);
|
||||||
int shm_id;
|
int shm_id;
|
||||||
@ -110,6 +143,12 @@ static void __compcov_load(void) {
|
|||||||
__compcov_code_end = maps_tmp->addr_end;
|
__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);
|
pmparser_free(maps);
|
||||||
@ -149,7 +188,8 @@ int strcmp(const char* str1, const char* str2) {
|
|||||||
|
|
||||||
void* retaddr = __builtin_return_address(0);
|
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);
|
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);
|
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);
|
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1);
|
||||||
n = MIN(n, len);
|
n = MIN(n, len);
|
||||||
@ -198,7 +239,8 @@ int strcasecmp(const char* str1, const char* str2) {
|
|||||||
|
|
||||||
void* retaddr = __builtin_return_address(0);
|
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 */
|
/* Fallback to strcmp, maybe improve in future */
|
||||||
|
|
||||||
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1);
|
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);
|
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 */
|
/* Fallback to strncmp, maybe improve in future */
|
||||||
|
|
||||||
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1);
|
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);
|
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;
|
size_t n = len;
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ abi_ulong afl_entry_point, /* ELF entry point (_start) */
|
|||||||
afl_start_code, /* .text start pointer */
|
afl_start_code, /* .text start pointer */
|
||||||
afl_end_code; /* .text end pointer */
|
afl_end_code; /* .text end pointer */
|
||||||
|
|
||||||
u8 afl_enable_compcov;
|
u8 afl_compcov_level;
|
||||||
|
|
||||||
/* Set in the child process in forkserver mode: */
|
/* 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")) {
|
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
|
/* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
extern unsigned char *afl_area_ptr;
|
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;
|
||||||
extern u8 afl_enable_compcov;
|
extern u8 afl_compcov_level;
|
||||||
|
|
||||||
void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc,
|
void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc,
|
||||||
TCGv_i64 arg1, TCGv_i64 arg2);
|
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,
|
static void afl_gen_compcov(target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2,
|
||||||
TCGMemOp ot) {
|
TCGMemOp ot, int is_imm) {
|
||||||
|
|
||||||
void *func;
|
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;
|
return;
|
||||||
|
|
||||||
switch (ot) {
|
switch (ot) {
|
||||||
|
@ -15,11 +15,11 @@ index 0dd5fbe4..b95d341e 100644
|
|||||||
tcg_gen_atomic_fetch_add_tl(s1->cc_srcT, s1->A0, s1->T0,
|
tcg_gen_atomic_fetch_add_tl(s1->cc_srcT, s1->A0, s1->T0,
|
||||||
s1->mem_index, ot | MO_LE);
|
s1->mem_index, ot | MO_LE);
|
||||||
tcg_gen_sub_tl(s1->T0, s1->cc_srcT, s1->T1);
|
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 {
|
} else {
|
||||||
tcg_gen_mov_tl(s1->cc_srcT, s1->T0);
|
tcg_gen_mov_tl(s1->cc_srcT, s1->T0);
|
||||||
tcg_gen_sub_tl(s1->T0, s1->T0, s1->T1);
|
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_st_rm_T0_A0(s1, ot, d);
|
||||||
}
|
}
|
||||||
gen_op_update2_cc(s1);
|
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(cpu_cc_src, s1->T1);
|
||||||
tcg_gen_mov_tl(s1->cc_srcT, s1->T0);
|
tcg_gen_mov_tl(s1->cc_srcT, s1->T0);
|
||||||
tcg_gen_sub_tl(cpu_cc_dst, s1->T0, s1->T1);
|
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);
|
set_cc_op(s1, CC_OP_SUBB + ot);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user