about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvanhauser-thc <vh@thc.org>2022-08-14 12:24:42 +0200
committervanhauser-thc <vh@thc.org>2022-08-14 12:30:23 +0200
commit3200e6515b9cc988d0d8dccd27257baccc8df021 (patch)
tree6a3538d9e3d13a78a5227fca69258c46a9fb5c76
parent89d6e306f29d1424012cdbb95d5cb18f6e36932f (diff)
downloadafl++-3200e6515b9cc988d0d8dccd27257baccc8df021.tar.gz
add AFL_NO_STARTUP_CALIBRATION feature
-rw-r--r--docs/Changelog.md9
-rw-r--r--docs/env_variables.md3
-rw-r--r--docs/fuzzing_in_depth.md7
-rw-r--r--include/afl-fuzz.h4
-rw-r--r--include/envs.h1
-rw-r--r--src/afl-fuzz-init.c24
-rw-r--r--src/afl-fuzz-queue.c10
-rw-r--r--src/afl-fuzz-state.c7
-rw-r--r--src/afl-fuzz.c13
9 files changed, 73 insertions, 5 deletions
diff --git a/docs/Changelog.md b/docs/Changelog.md
index ec517104..f5847ade 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -9,7 +9,14 @@ Want to stay in the loop on major new features? Join our mailing list by
 sending a mail to <afl-users+subscribe@googlegroups.com>.
 
 ### Version ++4.03a (dev)
-  - ... your PR? :)
+  - afl-fuzz:
+    - added AFL_NO_STARTUP_CALIBRATION to start fuzzing at once instead
+      of calibrating all initial seeds first. Good for large queues
+      and long execution times, especially in CIs.
+  - qemu_mode:
+    - added AFL_QEMU_TRACK_UNSTABLE to log the addresses of unstable
+      edges (together with AFL_DEBUG=1 afl-fuzz). thanks to
+      worksbutnottested!
 
 
 ### Version ++4.02c (release)
diff --git a/docs/env_variables.md b/docs/env_variables.md
index 00948fc1..bb54357b 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -462,6 +462,9 @@ checks or alter some of the more exotic semantics of the tool:
     some basic stats. This behavior is also automatically triggered when the
     output from afl-fuzz is redirected to a file or to a pipe.
 
+  - Setting `AFL_NO_STARTUP_CALIBRATION` will skip the initial calibration
+    of all starting seeds, and start fuzzing at once.
+
   - In QEMU mode (-Q) and FRIDA mode (-O), `AFL_PATH` will be searched for
     afl-qemu-trace and afl-frida-trace.so.
 
diff --git a/docs/fuzzing_in_depth.md b/docs/fuzzing_in_depth.md
index 37889137..92c9910b 100644
--- a/docs/fuzzing_in_depth.md
+++ b/docs/fuzzing_in_depth.md
@@ -626,6 +626,9 @@ from other fuzzers in the campaign first.
 
 If you have a large corpus, a corpus from a previous run or are fuzzing in a CI,
 then also set `export AFL_CMPLOG_ONLY_NEW=1` and `export AFL_FAST_CAL=1`.
+If the queue in the CI is huge and/or the execution time is slow then you can
+also add `AFL_NO_STARTUP_CALIBRATION=1` to skip the initial queue calibration
+phase and start fuzzing at once.
 
 You can also use different fuzzers. If you are using AFL spinoffs or AFL
 conforming fuzzers, then just use the same -o directory and give it a unique
@@ -902,6 +905,10 @@ complex file formats.
 Some notes on continuous integration (CI) fuzzing - this fuzzing is different to
 normal fuzzing campaigns as these are much shorter runnings.
 
+If the queue in the CI is huge and/or the execution time is slow then you can
+also add `AFL_NO_STARTUP_CALIBRATION=1` to skip the initial queue calibration
+phase and start fuzzing at once.
+
 1. Always:
     * LTO has a much longer compile time which is diametrical to short fuzzing -
       hence use afl-clang-fast instead.
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 061076ed..822096e8 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -386,7 +386,8 @@ typedef struct afl_env_vars {
       afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast,
       afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new,
       afl_exit_on_seed_issues, afl_try_affinity, afl_ignore_problems,
-      afl_keep_timeouts, afl_pizza_mode, afl_no_crash_readme;
+      afl_keep_timeouts, afl_pizza_mode, afl_no_crash_readme,
+      afl_no_startup_calibration;
 
   u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
       *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload,
@@ -1122,6 +1123,7 @@ void bind_to_free_cpu(afl_state_t *);
 void   setup_post(afl_state_t *);
 void   read_testcases(afl_state_t *, u8 *);
 void   perform_dry_run(afl_state_t *);
+void   no_dry_run(afl_state_t *);
 void   pivot_inputs(afl_state_t *);
 u32    find_start_position(afl_state_t *);
 void   find_timeout(afl_state_t *);
diff --git a/include/envs.h b/include/envs.h
index 02bd2ece..2204a100 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -165,6 +165,7 @@ static char *afl_environment_variables[] = {
     "AFL_NO_FORKSRV",
     "AFL_NO_UI",
     "AFL_NO_PYTHON",
+    "AFL_NO_STARTUP_CALIBRATION",
     "AFL_UNTRACER_FILE",
     "AFL_LLVM_USE_TRACE_PC",
     "AFL_MAP_SIZE",
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 4ffcfd2b..32e2b7b8 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -850,6 +850,30 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
 
 }
 
+/* In case no initial calibration is to be performed (e.g. huge queue and slow
+execution time), then setting AFL_NO_STARTUP_CALIBRATION will help getting
+initial data. For this to succeed, non-calibrated corpus entries have to look
+especially juicy so they are more likely to be selected then a calibrated good
+looking one. */
+
+void no_dry_run(afl_state_t *afl) {
+
+  struct queue_entry *q;
+  u32                 idx;
+
+  for (idx = 0; idx < afl->queued_items; idx++) {
+
+    q = afl->queue_buf[idx];
+    if (unlikely(!q || q->disabled)) { continue; }
+
+    q->exec_us = 1;
+    q->bitmap_size = MAP_SIZE;
+    q->tc_ref = MAP_SIZE;
+
+  }
+
+}
+
 /* Perform dry run of all test cases to confirm that the app is working as
    expected. This is done only for the initial inputs, and only once. */
 
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 02d697ab..d8dbdfbe 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -795,8 +795,14 @@ void cull_queue(afl_state_t *afl) {
 
 u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
 
-  u32 avg_exec_us = afl->total_cal_us / afl->total_cal_cycles;
-  u32 avg_bitmap_size = afl->total_bitmap_size / afl->total_bitmap_entries;
+  u32 cal_cycles = afl->total_cal_cycles;
+  u32 bitmap_entries = afl->total_bitmap_entries;
+
+  if (unlikely(!cal_cycles)) { cal_cycles = 1; }
+  if (unlikely(!bitmap_entries)) { bitmap_entries = 1; }
+
+  u32 avg_exec_us = afl->total_cal_us / cal_cycles;
+  u32 avg_bitmap_size = afl->total_bitmap_size / bitmap_entries;
   u32 perf_score = 100;
 
   /* Adjust score based on execution speed of this path, compared to the
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index ddfd4b31..6770839a 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -265,6 +265,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_cmplog_only_new =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_NO_STARTUP_CALIBRATION",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_no_startup_calibration =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
           } else if (!strncmp(env, "AFL_NO_UI", afl_environment_variable_len)) {
 
             afl->afl_env.afl_no_ui =
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 2e151abb..e3851473 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -273,6 +273,7 @@ static void usage(u8 *argv0, int more_help) {
       "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
       "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
       "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
+      "AFL_NO_STARTUP_CALIBRATION: no initial seed calibration, start fuzzing at once\n"
       "AFL_NO_UI: switch status screen off\n"
 
       DYN_COLOR
@@ -2150,7 +2151,17 @@ int main(int argc, char **argv_orig, char **envp) {
   memset(afl->virgin_tmout, 255, map_size);
   memset(afl->virgin_crash, 255, map_size);
 
-  perform_dry_run(afl);
+  if (likely(!afl->afl_env.afl_no_startup_calibration)) {
+
+    perform_dry_run(afl);
+
+  } else {
+
+    ACTF("skipping initial seed calibration due option override");
+    usleep(1000);
+    no_dry_run(afl);
+
+  }
 
   if (afl->q_testcase_max_cache_entries) {