about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/afl-fuzz-one.c250
-rw-r--r--src/afl-fuzz-queue.c112
-rw-r--r--src/afl-fuzz-redqueen.c102
-rw-r--r--src/afl-fuzz-state.c15
-rw-r--r--src/afl-fuzz-stats.c3
-rw-r--r--src/afl-fuzz.c81
6 files changed, 494 insertions, 69 deletions
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 72383727..1f0bf30e 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -24,6 +24,8 @@
  */
 
 #include "afl-fuzz.h"
+#include <string.h>
+#include <limits.h>
 
 /* MOpt */
 
@@ -362,6 +364,8 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) {
 
 #endif                                                     /* !IGNORE_FINDS */
 
+#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
+
 /* Take the current entry from the queue, fuzz it for a while. This
    function is a tad too long... returns 0 if fuzzed successfully, 1 if
    skipped or bailed out. */
@@ -1854,6 +1858,21 @@ havoc_stage:
   /* We essentially just do several thousand runs (depending on perf_score)
      where we take the input file and make random stacked tweaks. */
 
+  u32 r_max, r;
+
+  if (unlikely(afl->expand_havoc)) {
+
+    /* add expensive havoc cases here, they are activated after a full
+       cycle without finds happened */
+
+    r_max = 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0);
+
+  } else {
+
+    r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0);
+
+  }
+
   for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
 
     u32 use_stacking = 1 << (1 + rand_below(afl, HAVOC_STACK_POW2));
@@ -1896,8 +1915,7 @@ havoc_stage:
 
       }
 
-      switch (rand_below(
-          afl, 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) {
+      switch ((r = rand_below(afl, r_max))) {
 
         case 0:
 
@@ -2192,85 +2210,198 @@ havoc_stage:
 
         }
 
-          /* Values 15 and 16 can be selected only if there are any extras
-             present in the dictionaries. */
+        default:
 
-        case 15: {
+          if (likely(r <= 16 && (afl->extras_cnt || afl->a_extras_cnt))) {
 
-          /* Overwrite bytes with an extra. */
+            /* Values 15 and 16 can be selected only if there are any extras
+               present in the dictionaries. */
 
-          if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) {
+            if (r == 15) {
 
-            /* No user-specified extras or odds in our favor. Let's use an
-               auto-detected one. */
+              /* Overwrite bytes with an extra. */
 
-            u32 use_extra = rand_below(afl, afl->a_extras_cnt);
-            u32 extra_len = afl->a_extras[use_extra].len;
-            u32 insert_at;
+              if (!afl->extras_cnt ||
+                  (afl->a_extras_cnt && rand_below(afl, 2))) {
 
-            if (extra_len > temp_len) { break; }
+                /* No user-specified extras or odds in our favor. Let's use an
+                   auto-detected one. */
 
-            insert_at = rand_below(afl, temp_len - extra_len + 1);
-            memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
-                   extra_len);
+                u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+                u32 extra_len = afl->a_extras[use_extra].len;
+                u32 insert_at;
 
-          } else {
+                if (extra_len > temp_len) { break; }
 
-            /* No auto extras or odds in our favor. Use the dictionary. */
+                insert_at = rand_below(afl, temp_len - extra_len + 1);
+                memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
+                       extra_len);
 
-            u32 use_extra = rand_below(afl, afl->extras_cnt);
-            u32 extra_len = afl->extras[use_extra].len;
-            u32 insert_at;
+              } else {
 
-            if (extra_len > temp_len) { break; }
+                /* No auto extras or odds in our favor. Use the dictionary. */
 
-            insert_at = rand_below(afl, temp_len - extra_len + 1);
-            memcpy(out_buf + insert_at, afl->extras[use_extra].data, extra_len);
+                u32 use_extra = rand_below(afl, afl->extras_cnt);
+                u32 extra_len = afl->extras[use_extra].len;
+                u32 insert_at;
 
-          }
+                if (extra_len > temp_len) { break; }
 
-          break;
+                insert_at = rand_below(afl, temp_len - extra_len + 1);
+                memcpy(out_buf + insert_at, afl->extras[use_extra].data,
+                       extra_len);
 
-        }
+              }
 
-        case 16: {
+              break;
 
-          u32 use_extra, extra_len, insert_at = rand_below(afl, temp_len + 1);
-          u8 *ptr;
+            } else {  // case 16
+
+              u32 use_extra, extra_len,
+                  insert_at = rand_below(afl, temp_len + 1);
+              u8 *ptr;
+
+              /* Insert an extra. Do the same dice-rolling stuff as for the
+                 previous case. */
+
+              if (!afl->extras_cnt ||
+                  (afl->a_extras_cnt && rand_below(afl, 2))) {
+
+                use_extra = rand_below(afl, afl->a_extras_cnt);
+                extra_len = afl->a_extras[use_extra].len;
+                ptr = afl->a_extras[use_extra].data;
+
+              } else {
+
+                use_extra = rand_below(afl, afl->extras_cnt);
+                extra_len = afl->extras[use_extra].len;
+                ptr = afl->extras[use_extra].data;
+
+              }
+
+              if (temp_len + extra_len >= MAX_FILE) { break; }
+
+              out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len);
+
+              /* Tail */
+              memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
+                      temp_len - insert_at);
+
+              /* Inserted part */
+              memcpy(out_buf + insert_at, ptr, extra_len);
 
-          /* Insert an extra. Do the same dice-rolling stuff as for the
-             previous case. */
+              temp_len += extra_len;
 
-          if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) {
+              break;
 
-            use_extra = rand_below(afl, afl->a_extras_cnt);
-            extra_len = afl->a_extras[use_extra].len;
-            ptr = afl->a_extras[use_extra].data;
+            }
 
           } else {
 
-            use_extra = rand_below(afl, afl->extras_cnt);
-            extra_len = afl->extras[use_extra].len;
-            ptr = afl->extras[use_extra].data;
+            /*
+                        switch (r) {
 
-          }
+                          case 15:  // fall through
+                          case 16:
+                          case 17: {*/
 
-          if (temp_len + extra_len >= MAX_FILE) { break; }
+            /* Overwrite bytes with a randomly selected chunk from another
+               testcase or insert that chunk. */
 
-          out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len);
+            if (afl->queued_paths < 4) break;
 
-          /* Tail */
-          memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
-                  temp_len - insert_at);
+            /* Pick a random queue entry and seek to it. */
 
-          /* Inserted part */
-          memcpy(out_buf + insert_at, ptr, extra_len);
+            u32 tid;
+            do
+              tid = rand_below(afl, afl->queued_paths);
+            while (tid == afl->current_entry);
 
-          temp_len += extra_len;
+            struct queue_entry *target = afl->queue_buf[tid];
 
-          break;
+            /* Make sure that the target has a reasonable length. */
 
-        }
+            while (target && (target->len < 2 || target == afl->queue_cur))
+              target = target->next;
+
+            if (!target) break;
+
+            /* Read the testcase into a new buffer. */
+
+            fd = open(target->fname, O_RDONLY);
+
+            if (unlikely(fd < 0)) {
+
+              PFATAL("Unable to open '%s'", target->fname);
+
+            }
+
+            u32 new_len = target->len;
+            u8 *new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len);
+
+            ck_read(fd, new_buf, new_len, target->fname);
+
+            close(fd);
+
+            u8 overwrite = 0;
+            if (temp_len >= 2 && rand_below(afl, 2))
+              overwrite = 1;
+            else if (temp_len + HAVOC_BLK_XL >= MAX_FILE) {
+
+              if (temp_len >= 2)
+                overwrite = 1;
+              else
+                break;
+
+            }
+
+            if (overwrite) {
+
+              u32 copy_from, copy_to, copy_len;
+
+              copy_len = choose_block_len(afl, new_len - 1);
+              if (copy_len > temp_len) copy_len = temp_len;
+
+              copy_from = rand_below(afl, new_len - copy_len + 1);
+              copy_to = rand_below(afl, temp_len - copy_len + 1);
+
+              memmove(out_buf + copy_to, new_buf + copy_from, copy_len);
+
+            } else {
+
+              u32 clone_from, clone_to, clone_len;
+
+              clone_len = choose_block_len(afl, new_len);
+              clone_from = rand_below(afl, new_len - clone_len + 1);
+
+              clone_to = rand_below(afl, temp_len);
+
+              u8 *temp_buf =
+                  ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len);
+
+              /* Head */
+
+              memcpy(temp_buf, out_buf, clone_to);
+
+              /* Inserted part */
+
+              memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len);
+
+              /* Tail */
+              memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
+                     temp_len - clone_to);
+
+              swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
+              out_buf = temp_buf;
+              temp_len += clone_len;
+
+            }
+
+            break;
+
+          }
+
+          // end of default:
 
       }
 
@@ -2357,20 +2488,7 @@ retry_splicing:
     } while (tid == afl->current_entry);
 
     afl->splicing_with = tid;
-    target = afl->queue;
-
-    while (tid >= 100) {
-
-      target = target->next_100;
-      tid -= 100;
-
-    }
-
-    while (tid--) {
-
-      target = target->next;
-
-    }
+    target = afl->queue_buf[tid];
 
     /* Make sure that the target has a reasonable length. */
 
@@ -4750,7 +4868,7 @@ u8 fuzz_one(afl_state_t *afl) {
 
   return (key_val_lv_1 | key_val_lv_2);
 
-#undef BUF_PARAMS
-
 }
 
+#undef BUF_PARAMS
+
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 7afdd9f1..38e95ac8 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -24,6 +24,9 @@
 
 #include "afl-fuzz.h"
 #include <limits.h>
+#include <ctype.h>
+
+#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
 
 /* Mark deterministic checks as done for a particular queue entry. We use the
    .state file to avoid repeating deterministic fuzzing when resuming aborted
@@ -100,6 +103,108 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
 
 }
 
+/* check if ascii or UTF-8 */
+
+static u8 check_if_text(struct queue_entry *q) {
+
+  if (q->len < AFL_TXT_MIN_LEN) return 0;
+
+  u8  buf[MAX_FILE];
+  s32 fd, len = q->len, offset = 0, ascii = 0, utf8 = 0, comp;
+
+  if ((fd = open(q->fname, O_RDONLY)) < 0) return 0;
+  if ((comp = read(fd, buf, len)) != len) return 0;
+  close(fd);
+
+  while (offset < len) {
+
+    // ASCII: <= 0x7F to allow ASCII control characters
+    if ((buf[offset + 0] == 0x09 || buf[offset + 0] == 0x0A ||
+         buf[offset + 0] == 0x0D ||
+         (0x20 <= buf[offset + 0] && buf[offset + 0] <= 0x7E))) {
+
+      offset++;
+      utf8++;
+      ascii++;
+      continue;
+
+    }
+
+    if (isascii((int)buf[offset]) || isprint((int)buf[offset])) {
+
+      ascii++;
+      // we continue though as it can also be a valid utf8
+
+    }
+
+    // non-overlong 2-byte
+    if (((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) &&
+         (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) {
+
+      offset += 2;
+      utf8++;
+      comp--;
+      continue;
+
+    }
+
+    // excluding overlongs
+    if ((buf[offset + 0] == 0xE0 &&
+         (0xA0 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+         (0x80 <= buf[offset + 2] &&
+          buf[offset + 2] <= 0xBF)) ||  // straight 3-byte
+        (((0xE1 <= buf[offset + 0] && buf[offset + 0] <= 0xEC) ||
+          buf[offset + 0] == 0xEE || buf[offset + 0] == 0xEF) &&
+         (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+         (0x80 <= buf[offset + 2] &&
+          buf[offset + 2] <= 0xBF)) ||  // excluding surrogates
+        (buf[offset + 0] == 0xED &&
+         (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x9F) &&
+         (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF))) {
+
+      offset += 3;
+      utf8++;
+      comp -= 2;
+      continue;
+
+    }
+
+    // planes 1-3
+    if ((buf[offset + 0] == 0xF0 &&
+         (0x90 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+         (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+         (0x80 <= buf[offset + 3] &&
+          buf[offset + 3] <= 0xBF)) ||  // planes 4-15
+        ((0xF1 <= buf[offset + 0] && buf[offset + 0] <= 0xF3) &&
+         (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+         (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+         (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)) ||  // plane 16
+        (buf[offset + 0] == 0xF4 &&
+         (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x8F) &&
+         (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+         (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF))) {
+
+      offset += 4;
+      utf8++;
+      comp -= 3;
+      continue;
+
+    }
+
+    offset++;
+
+  }
+
+  u32 percent_utf8 = (utf8 * 100) / comp;
+  u32 percent_ascii = (ascii * 100) / len;
+
+  if (percent_utf8 >= percent_ascii && percent_utf8 >= AFL_TXT_MIN_PERCENT)
+    return 2;
+  if (percent_ascii >= AFL_TXT_MIN_PERCENT) return 1;
+  return 0;
+
+}
+
 /* Append new test case to the queue. */
 
 void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
@@ -138,6 +243,10 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
 
   }
 
+  struct queue_entry **queue_buf = ck_maybe_grow(
+      BUF_PARAMS(queue), afl->queued_paths * sizeof(struct queue_entry *));
+  queue_buf[afl->queued_paths - 1] = q;
+
   afl->last_path_time = get_cur_time();
 
   if (afl->custom_mutators_count) {
@@ -159,6 +268,9 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
 
   }
 
+  /* only redqueen currently uses is_ascii */
+  if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q);
+
 }
 
 /* Destroy the entire queue. */
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index c53e0e06..57e60c3d 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -24,6 +24,7 @@
 
  */
 
+#include <limits.h>
 #include "afl-fuzz.h"
 #include "cmplog.h"
 
@@ -262,6 +263,58 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
 
 }
 
+static long long strntoll(const char *str, size_t sz, char **end, int base) {
+
+  char        buf[64];
+  long long   ret;
+  const char *beg = str;
+
+  for (; beg && sz && *beg == ' '; beg++, sz--)
+    ;
+
+  if (!sz || sz >= sizeof(buf)) {
+
+    if (end) *end = (char *)str;
+    return 0;
+
+  }
+
+  memcpy(buf, beg, sz);
+  buf[sz] = '\0';
+  ret = strtoll(buf, end, base);
+  if (ret == LLONG_MIN || ret == LLONG_MAX) return ret;
+  if (end) *end = (char *)beg + (*end - buf);
+  return ret;
+
+}
+
+static unsigned long long strntoull(const char *str, size_t sz, char **end,
+                                    int base) {
+
+  char               buf[64];
+  unsigned long long ret;
+  const char *       beg = str;
+
+  for (; beg && sz && *beg == ' '; beg++, sz--)
+    ;
+
+  if (!sz || sz >= sizeof(buf)) {
+
+    if (end) *end = (char *)str;
+    return 0;
+
+  }
+
+  memcpy(buf, beg, sz);
+  buf[sz] = '\0';
+  ret = strtoull(buf, end, base);
+  if (end) *end = (char *)beg + (*end - buf);
+  return ret;
+
+}
+
+#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
+
 static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
                               u64 pattern, u64 repl, u64 o_pattern, u32 idx,
                               u8 *orig_buf, u8 *buf, u32 len, u8 do_reverse,
@@ -279,7 +332,54 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
   u32 its_len = len - idx;
   // *status = 0;
 
-  if (SHAPE_BYTES(h->shape) >= 8) {
+  u8 *               endptr;
+  u8                 use_num = 0, use_unum = 0;
+  unsigned long long unum;
+  long long          num;
+  if (afl->queue_cur->is_ascii) {
+
+    endptr = buf_8;
+    num = strntoll(buf_8, len - idx, (char **)&endptr, 0);
+    if (endptr == buf_8) {
+
+      unum = strntoull(buf_8, len - idx, (char **)&endptr, 0);
+      if (endptr == buf_8) use_unum = 1;
+
+    } else
+
+      use_num = 1;
+
+  }
+
+  if (use_num && num == pattern) {
+
+    size_t old_len = endptr - buf_8;
+    size_t num_len = snprintf(NULL, 0, "%lld", num);
+
+    u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), len + num_len);
+    memcpy(new_buf, buf, idx);
+
+    snprintf(new_buf + idx, num_len, "%lld", num);
+    memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len);
+
+    if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; }
+
+  } else if (use_unum && unum == pattern) {
+
+    size_t old_len = endptr - buf_8;
+    size_t num_len = snprintf(NULL, 0, "%llu", unum);
+
+    u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), len + num_len);
+    memcpy(new_buf, buf, idx);
+
+    snprintf(new_buf + idx, num_len, "%llu", unum);
+    memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len);
+
+    if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; }
+
+  }
+
+  if (SHAPE_BYTES(h->shape) >= 8 && *status != 1) {
 
     if (its_len >= 8 && *buf_64 == pattern && *o_buf_64 == o_pattern) {
 
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index e0e43f54..66280ed1 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -293,6 +293,20 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_autoresume =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_CYCLE_SCHEDULES",
+
+                              afl_environment_variable_len)) {
+
+            afl->cycle_schedules = afl->afl_env.afl_cycle_schedules =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+          } else if (!strncmp(env, "AFL_EXPAND_HAVOC_NOW",
+
+                              afl_environment_variable_len)) {
+
+            afl->expand_havoc = afl->afl_env.afl_expand_havoc =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
           } else if (!strncmp(env, "AFL_CAL_FAST",
 
                               afl_environment_variable_len)) {
@@ -405,6 +419,7 @@ void afl_state_deinit(afl_state_t *afl) {
   if (afl->pass_stats) { ck_free(afl->pass_stats); }
   if (afl->orig_cmp_map) { ck_free(afl->orig_cmp_map); }
 
+  if (afl->queue_buf) { free(afl->queue_buf); }
   if (afl->out_buf) { free(afl->out_buf); }
   if (afl->out_scratch_buf) { free(afl->out_scratch_buf); }
   if (afl->eff_buf) { free(afl->eff_buf); }
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 2546a57a..7b30b5ea 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -115,6 +115,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
           "cpu_affinity      : %d\n"
           "edges_found       : %u\n"
           "var_byte_count    : %u\n"
+          "havoc_expansion   : %u\n"
           "afl_banner        : %s\n"
           "afl_version       : " VERSION
           "\n"
@@ -148,7 +149,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
 #else
           -1,
 #endif
-          t_bytes, afl->var_byte_count, afl->use_banner,
+          t_bytes, afl->var_byte_count, afl->expand_havoc, afl->use_banner,
           afl->unicorn_mode ? "unicorn" : "",
           afl->fsrv.qemu_mode ? "qemu " : "",
           afl->non_instrumented_mode ? " non_instrumented " : "",
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index eb4b6a87..5bedf6e1 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -916,6 +916,7 @@ int main(int argc, char **argv_orig, char **envp) {
   if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; }
   if (get_afl_env("AFL_SHUFFLE_QUEUE")) { afl->shuffle_queue = 1; }
   if (get_afl_env("AFL_FAST_CAL")) { afl->fast_cal = 1; }
+  if (get_afl_env("AFL_EXPAND_HAVOC_NOW")) { afl->expand_havoc = 1; }
 
   if (afl->afl_env.afl_autoresume) {
 
@@ -1271,11 +1272,42 @@ int main(int argc, char **argv_orig, char **envp) {
       /* If we had a full queue cycle with no new finds, try
          recombination strategies next. */
 
-      if (afl->queued_paths == prev_queued) {
+      if (afl->queued_paths == prev_queued &&
+          (get_cur_time() - afl->start_time) >= 3600) {
 
         if (afl->use_splicing) {
 
           ++afl->cycles_wo_finds;
+          switch (afl->expand_havoc) {
+
+            case 0:
+              afl->expand_havoc = 1;
+              break;
+            case 1:
+              if (afl->limit_time_sig == 0) {
+
+                afl->limit_time_sig = -1;
+                afl->limit_time_puppet = 0;
+
+              }
+
+              afl->expand_havoc = 2;
+              break;
+            case 2:
+              // afl->cycle_schedules = 1;
+              afl->expand_havoc = 3;
+              break;
+            case 3:
+              // nothing else currently
+              break;
+
+          }
+
+          if (afl->expand_havoc) {
+
+          } else
+
+            afl->expand_havoc = 1;
 
         } else {
 
@@ -1289,6 +1321,53 @@ int main(int argc, char **argv_orig, char **envp) {
 
       }
 
+      if (afl->cycle_schedules) {
+
+        /* we cannot mix non-AFLfast schedules with others */
+
+        switch (afl->schedule) {
+
+          case EXPLORE:
+            afl->schedule = EXPLOIT;
+            break;
+          case EXPLOIT:
+            afl->schedule = MMOPT;
+            break;
+          case MMOPT:
+            afl->schedule = SEEK;
+            break;
+          case SEEK:
+            afl->schedule = EXPLORE;
+            break;
+          case FAST:
+            afl->schedule = COE;
+            break;
+          case COE:
+            afl->schedule = LIN;
+            break;
+          case LIN:
+            afl->schedule = QUAD;
+            break;
+          case QUAD:
+            afl->schedule = RARE;
+            break;
+          case RARE:
+            afl->schedule = FAST;
+            break;
+
+        }
+
+        struct queue_entry *q = afl->queue;
+        // we must recalculate the scores of all queue entries
+        while (q) {
+
+          update_bitmap_score(afl, q);
+          q = q->next;
+
+        }
+
+      }
+
       prev_queued = afl->queued_paths;
 
       if (afl->sync_id && afl->queue_cycle == 1 &&