about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2020-03-20 08:54:09 +0100
committervan Hauser <vh@thc.org>2020-03-20 08:54:09 +0100
commit29853549c3c12b4ebd4c2af4f0d728a13f30a727 (patch)
treed35e7d17a8156e0a206c19c8052c3db2a068b76e
parentd0b5cd64c3edd790c1405f0a2105033cf52f7c14 (diff)
downloadafl++-29853549c3c12b4ebd4c2af4f0d728a13f30a727.tar.gz
add RARE schedule. also fixes doc_path
-rw-r--r--README.md5
-rw-r--r--docs/Changelog.md9
-rw-r--r--docs/power_schedules.md1
-rw-r--r--include/afl-fuzz.h1
-rw-r--r--[-rwxr-xr-x]include/android-ashmem.h0
-rw-r--r--src/afl-fuzz-globals.c5
-rw-r--r--src/afl-fuzz-queue.c49
-rw-r--r--src/afl-fuzz-stats.c25
-rw-r--r--src/afl-fuzz.c13
9 files changed, 73 insertions, 35 deletions
diff --git a/README.md b/README.md
index ca321f31..5125928e 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@
   * [dev](https://github.com/AFLplusplus/AFLplusplus/tree/dev) : development state of afl++ - bleeding edge and you might catch a
     checkout which does not compile or has a bug. *We only accept PRs in dev!!*
   * (any other) : experimental branches to work on specific features or testing
-    new functionality or changes
+    new functionality or changes.
 
   For releases, please see the [Releases](https://github.com/AFLplusplus/AFLplusplus/releases) tab.
 
@@ -365,7 +365,8 @@ The available schedules are:
  - quad
  - lin
  - exploit
- - mmopt
+ - mmopt (experimental)
+ - rare (experimental)
 
 In parallel mode (-M/-S, several instances with shared queue), we suggest to
 run the master using the explore or fast schedule (-p explore) and the slaves
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 1fb78625..3eb5d329 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -24,10 +24,11 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
     - python mutator modules and custom mutator modules now use the same
       interface and hence the API changed
     - AFL_AUTORESUME will resume execution without the need to specify `-i -`
-    - added experimental power schedule -p mmopt that ignores the runtime of
-      queue entries and gives higher weighting to the last 5 queue entries
-      it is currently experimental and subject to change but preliminary
-      results are good
+    - added experimental power schedules (-p):
+      - mmopt: ignores runtime of queue entries, gives higher weighting to
+               the last 5 queue entries
+      - rare: puts focus on queue entries that hits rare branches, also ignores
+              runtime
   - LTO collision free instrumented added in llvm_mode with afl-clang-lto -
     note that this mode is amazing, but quite some targets won't compile
   - llvm_mode InsTrim mode:
diff --git a/docs/power_schedules.md b/docs/power_schedules.md
index cdada0f6..c69c64d2 100644
--- a/docs/power_schedules.md
+++ b/docs/power_schedules.md
@@ -20,6 +20,7 @@ We find that AFL's exploitation-based constant schedule assigns **too much energ
 | `-p lin` | ![LIN](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%5Cfrac%7Bs%28i%29%7D%7Bf%28i%29%7D%2CM%5Cright%29) |
 | `-p exploit` (AFL) | ![LIN](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Calpha%28i%29) |
 | `-p mmopt` | Experimental: `explore` with no weighting to runtime and increased weighting on the last 5 queue entries |
+| `-p rare` | Experimental: `rare` puts focus on queue entries that hit rare edges |
 where *α(i)* is the performance score that AFL uses to compute for the seed input *i*, *β(i)>1* is a constant, *s(i)* is the number of times that seed *i* has been chosen from the queue, *f(i)* is the number of generated inputs that exercise the same path as seed *i*, and *μ* is the average number of generated inputs exercising a path.
   
 More details can be found in the paper that was accepted at the [23rd ACM Conference on Computer and Communications Security (CCS'16)](https://www.sigsac.org/ccs/CCS2016/accepted-papers/).
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 1a798239..1d83f335 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -235,6 +235,7 @@ enum {
   /* 04 */ QUAD,    /* Quadratic schedule               */
   /* 05 */ EXPLOIT, /* AFL's exploitation-based const.  */
   /* 06 */ MMOPT,   /* Modified MOPT schedule           */
+  /* 07 */ RARE,    /* Rare edges                       */
 
   POWER_SCHEDULES_NUM
 
diff --git a/include/android-ashmem.h b/include/android-ashmem.h
index 3a0b9969..3a0b9969 100755..100644
--- a/include/android-ashmem.h
+++ b/include/android-ashmem.h
diff --git a/src/afl-fuzz-globals.c b/src/afl-fuzz-globals.c
index dbd8c835..88633a1b 100644
--- a/src/afl-fuzz-globals.c
+++ b/src/afl-fuzz-globals.c
@@ -30,8 +30,9 @@ s8  interesting_8[] = {INTERESTING_8};
 s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
 s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
 
-char *power_names[POWER_SCHEDULES_NUM] = {"explore", "fast",    "coe",  "lin",
-                                          "quad",    "exploit", "mmopt"};
+char *power_names[POWER_SCHEDULES_NUM] = {
+
+    "explore", "fast", "coe", "lin", "quad", "exploit", "mmopt", "rare"};
 
 u8 *doc_path = NULL;                    /* gath to documentation dir        */
 
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 8a995727..f49e1f1e 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -185,12 +185,16 @@ void destroy_queue(afl_state_t *afl) {
 void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
 
   u32 i;
-  u64 fav_factor = q->exec_us * q->len;
+  u64 fav_factor;
   u64 fuzz_p2 = next_p2(q->n_fuzz);
 
+  if (afl->schedule == MMOPT || afl->schedule == RARE)
+    fav_factor = q->len << 2;
+  else
+    fav_factor = q->exec_us * q->len;
+
   /* For every byte set in afl->fsrv.trace_bits[], see if there is a previous
      winner, and how it compares to us. */
-
   for (i = 0; i < MAP_SIZE; ++i)
 
     if (afl->fsrv.trace_bits[i]) {
@@ -198,20 +202,20 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
       if (afl->top_rated[i]) {
 
         /* Faster-executing or smaller test cases are favored. */
+        u64 top_rated_fav_factor;
         u64 top_rated_fuzz_p2 = next_p2(afl->top_rated[i]->n_fuzz);
-        u64 top_rated_fav_factor =
-            afl->top_rated[i]->exec_us * afl->top_rated[i]->len;
 
-        if (fuzz_p2 > top_rated_fuzz_p2) {
+        if (afl->schedule == MMOPT || afl->schedule == RARE)
+          top_rated_fav_factor = afl->top_rated[i]->len << 2;
+        else
+          top_rated_fav_factor =
+              afl->top_rated[i]->exec_us * afl->top_rated[i]->len;
 
+        if (fuzz_p2 > top_rated_fuzz_p2)
           continue;
-
-        } else if (fuzz_p2 == top_rated_fuzz_p2) {
-
+        else if (fuzz_p2 == top_rated_fuzz_p2)
           if (fav_factor > top_rated_fav_factor) continue;
 
-        }
-
         if (fav_factor > afl->top_rated[i]->exec_us * afl->top_rated[i]->len)
           continue;
 
@@ -328,7 +332,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
   // Longer execution time means longer work on the input, the deeper in
   // coverage, the better the fuzzing, right? -mh
 
-  if (afl->schedule != MMOPT) {
+  if (afl->schedule != MMOPT && afl->schedule != RARE) {
 
     if (q->exec_us * 0.1 > avg_exec_us)
       perf_score = 10;
@@ -448,8 +452,29 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
       break;
 
     case MMOPT:
+      /* -- this was a more complex setup, which is good, but competed with
+         -- rare. the simpler algo however is good when rare is not.
+        // the newer the entry, the higher the pref_score
+        perf_score *= (1 + (double)((double)q->depth /
+        (double)afl->queued_paths));
+        // with special focus on the last 8 entries
+        if (afl->max_depth - q->depth < 8) perf_score *= (1 + ((8 -
+        (afl->max_depth - q->depth)) / 5));
+      */
+      // put focus on the last 5 entries
+      if (afl->max_depth - q->depth < 5) perf_score *= 2;
+
+      break;
+
+    case RARE:
 
-      if (afl->max_depth - q->depth < 5) perf_score *= 1.5;
+      // increase the score for every bitmap byte for which this entry
+      // is the top contender
+      perf_score += (q->tc_ref * 10);
+      // the more often fuzz result paths are equal to this queue entry,
+      // reduce its value
+      perf_score *=
+          (1 - (double)((double)q->n_fuzz / (double)afl->total_execs));
 
       break;
 
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index dcd4f542..6ea6a8e9 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -32,9 +32,10 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
 
   struct rusage rus;
 
-  u8 *  fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
-  s32   fd;
-  FILE *f;
+  unsigned long long int cur_time = get_cur_time();
+  u8 *                   fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
+  s32                    fd;
+  FILE *                 f;
 
   fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
 
@@ -69,6 +70,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
       f,
       "start_time        : %llu\n"
       "last_update       : %llu\n"
+      "run_time          : %llu\n"
       "fuzzer_pid        : %d\n"
       "cycles_done       : %llu\n"
       "execs_done        : %llu\n"
@@ -99,7 +101,8 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
       "\n"
       "target_mode       : %s%s%s%s%s%s%s%s\n"
       "command_line      : %s\n",
-      afl->start_time / 1000, get_cur_time() / 1000, getpid(),
+      afl->start_time / 1000, cur_time / 1000,
+      (cur_time - afl->start_time) / 1000, getpid(),
       afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->total_execs,
       /*eps,*/ afl->total_execs /
           ((double)(get_cur_time() - afl->start_time) / 1000),
@@ -357,9 +360,9 @@ void show_stats(afl_state_t *afl) {
 
   /* Lord, forgive me this. */
 
-  SAYF(SET_G1 bSTG bLT bH bSTOP                         cCYA
+  SAYF(SET_G1 bSTG bLT bH bSTOP cCYA
        " process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA
-       " overall results " bSTG bH2 bH2                 bRT "\n");
+       " overall results " bSTG bH2 bH2 bRT "\n");
 
   if (afl->dumb_mode) {
 
@@ -441,9 +444,9 @@ void show_stats(afl_state_t *afl) {
                 "   uniq hangs : " cRST "%-6s" bSTG         bV "\n",
        time_tmp, tmp);
 
-  SAYF(bVR bH bSTOP                                          cCYA
+  SAYF(bVR bH bSTOP            cCYA
        " cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA
-       " map coverage " bSTG bH bHT bH20 bH2                 bVL "\n");
+       " map coverage " bSTG bH bHT bH20 bH2 bVL "\n");
 
   /* This gets funny because we want to print several variable-length variables
      together, but then cram them into a fixed-width field - so we need to
@@ -472,9 +475,9 @@ void show_stats(afl_state_t *afl) {
 
   SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp);
 
-  SAYF(bVR bH bSTOP                                         cCYA
+  SAYF(bVR bH bSTOP            cCYA
        " stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA
-       " findings in depth " bSTG bH10 bH5 bH2 bH2          bVL "\n");
+       " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n");
 
   sprintf(tmp, "%s (%0.02f%%)", DI(IB(0), afl->queued_favored),
           ((double)afl->queued_favored) * 100 / afl->queued_paths);
@@ -546,7 +549,7 @@ void show_stats(afl_state_t *afl) {
 
   /* Aaaalmost there... hold on! */
 
-  SAYF(bVR bH cCYA                                                     bSTOP
+  SAYF(bVR bH cCYA                      bSTOP
        " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA
        " path geometry " bSTG bH5 bH2 bVL "\n");
 
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 10fee76c..15caa65f 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -96,8 +96,8 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
       "Execution control settings:\n"
       "  -p schedule   - power schedules recompute a seed's performance "
       "score.\n"
-      "                  <explore (default), fast, coe, lin, quad, exploit, "
-      "mmopt>\n"
+      "                  <explore(default), fast, coe, lin, quad, exploit, "
+      "mmopt, rare>\n"
       "                  see docs/power_schedules.md\n"
       "  -f file       - location read by the fuzzed program (stdin)\n"
       "  -t msec       - timeout for each run (auto-scaled, 50-%d ms)\n"
@@ -250,7 +250,7 @@ int main(int argc, char **argv_orig, char **envp) {
   SAYF(cCYA "afl-fuzz" VERSION cRST
             " based on afl by Michal Zalewski and a big online community\n");
 
-  doc_path = access(DOC_PATH, F_OK) ? (u8 *)"docs" : doc_path;
+  doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH;
 
   gettimeofday(&tv, &tz);
   afl->init_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
@@ -304,6 +304,10 @@ int main(int argc, char **argv_orig, char **envp) {
 
           afl->schedule = MMOPT;
 
+        } else if (!stricmp(optarg, "rare")) {
+
+          afl->schedule = RARE;
+
         } else if (!stricmp(optarg, "explore") || !stricmp(optarg, "default") ||
 
                    !stricmp(optarg, "normal") || !stricmp(optarg, "afl")) {
@@ -760,8 +764,9 @@ int main(int argc, char **argv_orig, char **envp) {
     case LIN: OKF("Using linear power schedule (LIN)"); break;
     case QUAD: OKF("Using quadratic power schedule (QUAD)"); break;
     case MMOPT: OKF("Using modified MOpt power schedule (MMOPT)"); break;
+    case RARE: OKF("Using rare edge focus power schedule (RARE)"); break;
     case EXPLORE:
-      OKF("Using exploration-based constant power schedule (EXPLORE)");
+      OKF("Using exploration-based constant power schedule (EXPLORE, default)");
       break;
     default: FATAL("Unknown power schedule"); break;