about summary refs log tree commit diff
path: root/qemu_mode/libcompcov
diff options
context:
space:
mode:
Diffstat (limited to 'qemu_mode/libcompcov')
-rw-r--r--qemu_mode/libcompcov/README.compcov8
-rw-r--r--qemu_mode/libcompcov/libcompcov.so.c54
2 files changed, 55 insertions, 7 deletions
diff --git a/qemu_mode/libcompcov/README.compcov b/qemu_mode/libcompcov/README.compcov
index 2a4a0ee5..9be13d88 100644
--- a/qemu_mode/libcompcov/README.compcov
+++ b/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
diff --git a/qemu_mode/libcompcov/libcompcov.so.c b/qemu_mode/libcompcov/libcompcov.so.c
index 582230db..92e4dbaa 100644
--- a/qemu_mode/libcompcov/libcompcov.so.c
+++ b/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
   
@@ -71,6 +95,15 @@ static void __compcov_load(void) {
   __libc_strcasecmp = dlsym(RTLD_NEXT, "strcasecmp");
   __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;