about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2024-05-17 23:55:55 +0200
committerGitHub <noreply@github.com>2024-05-17 23:55:55 +0200
commite7d871c8bf64962a658e447b90a1a3b43aaddc28 (patch)
tree7aec2a095a30ed609ce96f85ec3c4e0a8b8eb74c
parent497f341eac230fab13d6b5c5153c36321371b180 (diff)
parent56d5aa3101945e81519a3fac8783d0d8fad82779 (diff)
downloadafl++-e7d871c8bf64962a658e447b90a1a3b43aaddc28.tar.gz
Merge pull request #2093 from AFLplusplus/dev
push to stable
-rw-r--r--TODO.md1
-rw-r--r--docs/Changelog.md9
-rw-r--r--include/envs.h24
-rw-r--r--instrumentation/SanitizerCoveragePCGUARD.so.cc6
-rw-r--r--instrumentation/afl-llvm-common.cc45
-rw-r--r--instrumentation/afl-llvm-common.h1
-rwxr-xr-xqemu_mode/build_qemu_support.sh4
-rw-r--r--src/afl-cc.c10
-rw-r--r--src/afl-fuzz-run.c3
-rw-r--r--src/afl-fuzz-stats.c27
-rw-r--r--src/afl-fuzz.c9
-rw-r--r--src/afl-showmap.c15
-rwxr-xr-xtest/test-llvm.sh5
13 files changed, 101 insertions, 58 deletions
diff --git a/TODO.md b/TODO.md
index d47372b8..20f3425f 100644
--- a/TODO.md
+++ b/TODO.md
@@ -11,6 +11,7 @@
  - afl-showmap -f support
  - afl-fuzz multicore wrapper script
  - when trimming then perform crash detection
+ - cyclomatic complexity: 2 + calls + edges - blocks
 
 
 ## Should
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 79594e38..6736e42b 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -11,15 +11,22 @@
     - prevent filenames in the queue that have spaces
     - minor fix for FAST schedules
     - more frequent stats update when syncing (todo: check performance impact)
+    - now timing of calibration, trimming and syncing is measured seperately,
+      thanks to @eqv!
+    - -V timing is now accurately the fuzz time (without syncing), before
+      long calibration times and syncing could result in now fuzzing being
+      made when the time was already run out until then, thanks to @eqv!
   * afl-cc:
     - re-enable i386 support that was accidently disabled
-    - fixes for LTO and outdated afl-gcc mode
+    - fixes for LTO and outdated afl-gcc mode for i386
     - fix COMPCOV split compare for old LLVMs
     - disable xml/curl/g_ string transform functions because we do not check
       for null pointers ... TODO
     - ensure shared memory variables are visible in weird build setups
   * afl-cmin
     - work with input files that have a space
+  * afl-showmap
+    - minor fix to collect coverage -C (thanks to @bet4it)
   * enhanced the ASAN configuration
 
 
diff --git a/include/envs.h b/include/envs.h
index 2f5b0d60..5b516905 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -21,18 +21,18 @@ static char *afl_environment_variables[] = {
     "AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", "AFL_CC_COMPILER",
     "AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", "AFL_CMPLOG_ONLY_NEW",
     "AFL_CODE_END", "AFL_CODE_START", "AFL_COMPCOV_BINNAME",
-    "AFL_CMPLOG_MAX_LEN", "AFL_COMPCOV_LEVEL", "AFL_CRASH_EXITCODE",
-    "AFL_CRASHING_SEEDS_AS_NEW_CRASH", "AFL_CUSTOM_MUTATOR_LIBRARY",
-    "AFL_CUSTOM_MUTATOR_ONLY", "AFL_CUSTOM_INFO_PROGRAM",
-    "AFL_CUSTOM_INFO_PROGRAM_ARGV", "AFL_CUSTOM_INFO_PROGRAM_INPUT",
-    "AFL_CUSTOM_INFO_OUT", "AFL_CXX", "AFL_CYCLE_SCHEDULES", "AFL_DEBUG",
-    "AFL_DEBUG_CHILD", "AFL_DEBUG_GDB", "AFL_DEBUG_UNICORN",
-    "AFL_DISABLE_REDUNDANT", "AFL_NO_REDUNDANT", "AFL_DISABLE_TRIM",
-    "AFL_NO_TRIM", "AFL_DISABLE_LLVM_INSTRUMENTATION", "AFL_DONT_OPTIMIZE",
-    "AFL_DRIVER_STDERR_DUPLICATE_FILENAME", "AFL_DUMB_FORKSRV",
-    "AFL_EARLY_FORKSERVER", "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE",
-    "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL",
-    "AFL_FINAL_SYNC", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS",
+    "AFL_DUMP_CYCLOMATIC_COMPLEXITY", "AFL_CMPLOG_MAX_LEN", "AFL_COMPCOV_LEVEL",
+    "AFL_CRASH_EXITCODE", "AFL_CRASHING_SEEDS_AS_NEW_CRASH",
+    "AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_ONLY",
+    "AFL_CUSTOM_INFO_PROGRAM", "AFL_CUSTOM_INFO_PROGRAM_ARGV",
+    "AFL_CUSTOM_INFO_PROGRAM_INPUT", "AFL_CUSTOM_INFO_OUT", "AFL_CXX",
+    "AFL_CYCLE_SCHEDULES", "AFL_DEBUG", "AFL_DEBUG_CHILD", "AFL_DEBUG_GDB",
+    "AFL_DEBUG_UNICORN", "AFL_DISABLE_REDUNDANT", "AFL_NO_REDUNDANT",
+    "AFL_DISABLE_TRIM", "AFL_NO_TRIM", "AFL_DISABLE_LLVM_INSTRUMENTATION",
+    "AFL_DONT_OPTIMIZE", "AFL_DRIVER_STDERR_DUPLICATE_FILENAME",
+    "AFL_DUMB_FORKSRV", "AFL_EARLY_FORKSERVER", "AFL_ENTRYPOINT",
+    "AFL_EXIT_WHEN_DONE", "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES",
+    "AFL_FAST_CAL", "AFL_FINAL_SYNC", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS",
     "AFL_FRIDA_DRIVER_NO_HOOK", "AFL_FRIDA_EXCLUDE_RANGES",
     "AFL_FRIDA_INST_CACHE_SIZE", "AFL_FRIDA_INST_COVERAGE_ABSOLUTE",
     "AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_DEBUG_FILE",
diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc
index f88ce126..01881f28 100644
--- a/instrumentation/SanitizerCoveragePCGUARD.so.cc
+++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc
@@ -195,7 +195,7 @@ class ModuleSanitizerCoverageAFL
 
   SanitizerCoverageOptions Options;
 
-  uint32_t        instr = 0, selects = 0, unhandled = 0;
+  uint32_t        instr = 0, selects = 0, unhandled = 0, dump_cc = 0;
   GlobalVariable *AFLMapPtr = NULL;
   ConstantInt    *One = NULL;
   ConstantInt    *Zero = NULL;
@@ -330,6 +330,8 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
 
   if (getenv("AFL_DEBUG")) { debug = 1; }
 
+  if (getenv("AFL_DUMP_CYCLOMATIC_COMPLEXITY")) { dump_cc = 1; }
+
   if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
 
     SAYF(cCYA "SanitizerCoveragePCGUARD" VERSION cRST "\n");
@@ -638,6 +640,8 @@ void ModuleSanitizerCoverageAFL::instrumentFunction(
   // InjectTraceForCmp(F, CmpTraceTargets);
   // InjectTraceForSwitch(F, SwitchTraceTargets);
 
+  if (dump_cc) { calcCyclomaticComplexity(&F); }
+
 }
 
 GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection(
diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc
index 8e9e7800..ed9268dc 100644
--- a/instrumentation/afl-llvm-common.cc
+++ b/instrumentation/afl-llvm-common.cc
@@ -26,6 +26,51 @@ static std::list<std::string> allowListFunctions;
 static std::list<std::string> denyListFiles;
 static std::list<std::string> denyListFunctions;
 
+unsigned int calcCyclomaticComplexity(llvm::Function *F) {
+
+  unsigned int numBlocks = 0;
+  unsigned int numEdges = 0;
+  unsigned int numCalls = 0;
+
+  // Iterate through each basic block in the function
+  for (BasicBlock &BB : *F) {
+
+    // count all nodes == basic blocks
+    numBlocks++;
+    // Count the number of successors (outgoing edges)
+    for (BasicBlock *Succ : successors(&BB)) {
+
+      // count edges for CC
+      numEdges++;
+      (void)(Succ);
+
+    }
+
+    for (Instruction &I : BB) {
+
+      // every call is also an edge, so we need to count the calls too
+      if (isa<CallInst>(&I) || isa<InvokeInst>(&I)) { numCalls++; }
+
+    }
+
+  }
+
+  // Cyclomatic Complexity V(G) = E - N + 2P
+  // For a single function, P (number of connected components) is 1
+  // Calls are considered to be an edge
+  unsigned int CC = 2 + numCalls + numEdges - numBlocks;
+
+  // if (debug) {
+
+  fprintf(stderr, "CyclomaticComplexity for %s: %u\n",
+          F->getName().str().c_str(), CC);
+
+  //}
+
+  return CC;
+
+}
+
 char *getBBName(const llvm::BasicBlock *BB) {
 
   static char *name;
diff --git a/instrumentation/afl-llvm-common.h b/instrumentation/afl-llvm-common.h
index 23f67179..6b628d64 100644
--- a/instrumentation/afl-llvm-common.h
+++ b/instrumentation/afl-llvm-common.h
@@ -55,6 +55,7 @@ void  initInstrumentList();
 bool  isInInstrumentList(llvm::Function *F, std::string Filename);
 unsigned long long int calculateCollisions(uint32_t edges);
 void                   scanForDangerousFunctions(llvm::Module *M);
+unsigned int           calcCyclomaticComplexity(llvm::Function *F);
 
 #ifndef IS_EXTERN
   #define IS_EXTERN
diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh
index ecc90ef5..19336114 100755
--- a/qemu_mode/build_qemu_support.sh
+++ b/qemu_mode/build_qemu_support.sh
@@ -202,6 +202,8 @@ QEMU_CONF_FLAGS=" \
   --disable-xfsctl \
   --target-list="${CPU_TARGET}-linux-user" \
   --without-default-devices \
+  --extra-cflags=-Wno-int-conversion \
+  --disable-werror \
   "
 
 if [ -n "${CROSS_PREFIX}" ]; then
@@ -243,7 +245,6 @@ if [ "$DEBUG" = "1" ]; then
     --enable-debug-stack-usage \
     --enable-debug-tcg \
     --enable-qom-cast-debug \
-    --enable-werror \
     "
 
 else
@@ -254,7 +255,6 @@ else
     --disable-debug-tcg \
     --disable-qom-cast-debug \
     --disable-stack-protector \
-    --disable-werror \
     --disable-docs \
     "
 
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 7acee8e4..c872b2eb 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -2794,11 +2794,11 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
         "MODES:                                  NCC PERSIST DICT   LAF "
         "CMPLOG SELECT\n"
         "  [LLVM] LLVM:             %s%s\n"
-        "      PCGUARD              %s    yes yes     module yes yes    "
+        "      PCGUARD              %s yes yes     module yes yes    "
         "yes\n"
         "      NATIVE               AVAILABLE    no  yes     no     no  "
         "part.  yes\n"
-        "      CLASSIC              %s    no  yes     module yes yes    "
+        "      CLASSIC              %s no  yes     module yes yes    "
         "yes\n"
         "        - NORMAL\n"
         "        - CALLER\n"
@@ -2815,10 +2815,10 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
         "  [GCC/CLANG] simple gcc/clang: %s%s\n"
         "      CLASSIC              DEFAULT      no  no      no     no  no     "
         "no\n\n",
-        aflcc->have_llvm ? "AVAILABLE" : "unavailable!",
+        aflcc->have_llvm ? "AVAILABLE   " : "unavailable!",
         aflcc->compiler_mode == LLVM ? " [SELECTED]" : "",
-        aflcc->have_llvm ? "AVAILABLE" : "unavailable!",
-        aflcc->have_llvm ? "AVAILABLE" : "unavailable!",
+        aflcc->have_llvm ? "AVAILABLE   " : "unavailable!",
+        aflcc->have_llvm ? "AVAILABLE   " : "unavailable!",
         aflcc->have_lto ? "AVAILABLE" : "unavailable!",
         aflcc->compiler_mode == LTO ? " [SELECTED]" : "",
         aflcc->have_gcc_plugin ? "AVAILABLE" : "unavailable!",
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 2a55da00..b62db1ea 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -606,6 +606,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
   }
 
   q->exec_us = diff_us / afl->stage_max;
+  if (unlikely(!q->exec_us)) { q->exec_us = 1; }
+
   q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits);
   q->handicap = handicap;
   q->cal_failed = 0;
@@ -1193,4 +1195,3 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
   return 0;
 
 }
-
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 755e1c50..ffe56cde 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -321,8 +321,9 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
 #ifndef __HAIKU__
   if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; }
 #endif
-  u64 runtime = afl->prev_run_time + cur_time - afl->start_time;
-  if (!runtime) { runtime = 1; }
+  u64 runtime_ms = afl->prev_run_time + cur_time - afl->start_time;
+  u64 overhead_ms = (afl->calibration_time_us + afl->sync_time_us + afl->trim_time_us) / 1000;
+  if (!runtime_ms) { runtime_ms = 1; }
 
   fprintf(
       f,
@@ -375,20 +376,17 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
       "target_mode       : %s%s%s%s%s%s%s%s%s%s\n"
       "command_line      : %s\n",
       (afl->start_time /*- afl->prev_run_time*/) / 1000, cur_time / 1000,
-      runtime / 1000, (u32)getpid(),
+      runtime_ms / 1000, (u32)getpid(),
       afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
       afl->longest_find_time > cur_time - afl->last_find_time
           ? afl->longest_find_time / 1000
           : ((afl->start_time == 0 || afl->last_find_time == 0)
                  ? 0
                  : (cur_time - afl->last_find_time) / 1000),
-      (runtime -
-       ((afl->calibration_time_us + afl->sync_time_us + afl->trim_time_us) /
-        1000)) /
-          1000,
+      (runtime_ms - MIN(runtime_ms, overhead_ms)) / 1000,
       afl->calibration_time_us / 1000000, afl->sync_time_us / 1000000,
       afl->trim_time_us / 1000000, afl->fsrv.total_execs,
-      afl->fsrv.total_execs / ((double)(runtime) / 1000),
+      afl->fsrv.total_execs / ((double)(runtime_ms) / 1000),
       afl->last_avg_execs_saved, afl->queued_items, afl->queued_favored,
       afl->queued_discovered, afl->queued_imported, afl->queued_variable,
       afl->max_depth, afl->current_entry, afl->pending_favored,
@@ -632,9 +630,9 @@ void show_stats_normal(afl_state_t *afl) {
 
   cur_ms = get_cur_time();
 
-  if (afl->most_time_key) {
+  if (afl->most_time_key && afl->queue_cycle) {
 
-    if (afl->most_time * 1000 < cur_ms - afl->start_time) {
+    if (afl->most_time * 1000 + afl->sync_time_us / 1000 < cur_ms - afl->start_time) {
 
       afl->most_time_key = 2;
       afl->stop_soon = 2;
@@ -643,7 +641,7 @@ void show_stats_normal(afl_state_t *afl) {
 
   }
 
-  if (afl->most_execs_key == 1) {
+  if (afl->most_execs_key == 1 && afl->queue_cycle) {
 
     if (afl->most_execs <= afl->fsrv.total_execs) {
 
@@ -1462,9 +1460,9 @@ void show_stats_pizza(afl_state_t *afl) {
 
   cur_ms = get_cur_time();
 
-  if (afl->most_time_key) {
+  if (afl->most_time_key && afl->queue_cycle) {
 
-    if (afl->most_time * 1000 < cur_ms - afl->start_time) {
+    if (afl->most_time * 1000 + afl->sync_time_us / 1000 < cur_ms - afl->start_time) {
 
       afl->most_time_key = 2;
       afl->stop_soon = 2;
@@ -1473,7 +1471,7 @@ void show_stats_pizza(afl_state_t *afl) {
 
   }
 
-  if (afl->most_execs_key == 1) {
+  if (afl->most_execs_key == 1 && afl->queue_cycle) {
 
     if (afl->most_execs <= afl->fsrv.total_execs) {
 
@@ -2505,4 +2503,3 @@ void update_sync_time(afl_state_t *afl, u64 *time) {
   *time = cur;
 
 }
-
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 1f0037ba..70ab983c 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -1806,7 +1806,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   afl->fsrv.use_fauxsrv = afl->non_instrumented_mode == 1 || afl->no_forkserver;
   afl->fsrv.max_length = afl->max_length;
-   
+
   #ifdef __linux__
   if (!afl->fsrv.nyx_mode) {
 
@@ -2594,13 +2594,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
         sync_fuzzers(afl);
 
-        if (!afl->queue_cycle && afl->afl_env.afl_import_first) {
-
-          // real start time, we reset, so this works correctly with -V
-          afl->start_time = get_cur_time();
-
-        }
-
       }
 
       ++afl->queue_cycle;
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 07a4844a..7e875040 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -178,7 +178,8 @@ fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
 void classify_counts(afl_forkserver_t *fsrv) {
 
   u8       *mem = fsrv->trace_bits;
-  const u8 *map = binary_mode ? count_class_binary : count_class_human;
+  const u8 *map = (binary_mode || collect_coverage) ? count_class_binary
+                                                    : count_class_human;
 
   u32 i = map_size;
 
@@ -240,14 +241,7 @@ static void analyze_results(afl_forkserver_t *fsrv) {
   u32 i;
   for (i = 0; i < map_size; i++) {
 
-    if (fsrv->trace_bits[i]) {
-
-      total += fsrv->trace_bits[i];
-      if (fsrv->trace_bits[i] > highest) highest = fsrv->trace_bits[i];
-      // if (!coverage_map[i]) { coverage_map[i] = 1; }
-      coverage_map[i] |= fsrv->trace_bits[i];
-
-    }
+    if (fsrv->trace_bits[i]) { coverage_map[i] |= fsrv->trace_bits[i]; }
 
   }
 
@@ -1339,6 +1333,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  if (collect_coverage) { binary_mode = false; }  // ensure this
+
   if (optind == argc || !out_file) { usage(argv[0]); }
 
   if (in_dir && in_filelist) { FATAL("you can only specify either -i or -I"); }
@@ -1677,7 +1673,6 @@ int main(int argc, char **argv_orig, char **envp) {
       if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL)
         FATAL("coult not grab memory");
       edges_only = false;
-      raw_instr_output = true;
 
     }
 
diff --git a/test/test-llvm.sh b/test/test-llvm.sh
index 13e1bad1..4dd35e6e 100755
--- a/test/test-llvm.sh
+++ b/test/test-llvm.sh
@@ -264,13 +264,12 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
   }
   rm -f test-compcov test.out instrumentlist.txt
   AFL_LLVM_CMPLOG=1 ../afl-clang-fast -o test-cmplog test-cmplog.c > /dev/null 2>&1
-  ../afl-clang-fast -O0 -o test-c test-cmplog.c > /dev/null 2>&1
   test -e test-cmplog && {
     $ECHO "$GREY[*] running afl-fuzz for llvm_mode cmplog, this will take approx 10 seconds"
     {
       mkdir -p in
       echo 00000000000000000000000000000000 > in/in
-      AFL_BENCH_UNTIL_CRASH=1 ../afl-fuzz -Z -l 3 -m none -V30 -i in -o out -c ./test-cmplog -- ./test-c >>errors 2>&1
+      AFL_BENCH_UNTIL_CRASH=1 ../afl-fuzz -Z -l 3 -m none -V30 -i in -o out -c 0 -- ./test-cmplog >>errors 2>&1
     } >>errors 2>&1
     test -n "$( ls out/default/crashes/id:000000* out/default/hangs/id:000000* 2>/dev/null )" && {
       $ECHO "$GREEN[+] afl-fuzz is working correctly with llvm_mode cmplog"
@@ -285,7 +284,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
     $ECHO "$YELLOW[-] we cannot test llvm_mode cmplog because it is not present"
     INCOMPLETE=1
   }
-  rm -rf errors test-cmplog test-c in core.*
+  rm -rf errors test-cmplog in core.*
   ../afl-clang-fast -o test-persistent ../utils/persistent_mode/persistent_demo.c > /dev/null 2>&1
   test -e test-persistent && {
     echo foo | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && {