From c2b04bdf6c596f5d220f27caead20d09452ed42d Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 16 Jul 2020 14:32:41 +0200 Subject: queue buffer and new splice havoc mutation --- src/afl-fuzz-one.c | 111 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 94 insertions(+), 17 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 72383727..399bfcab 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1897,7 +1897,7 @@ havoc_stage: } switch (rand_below( - afl, 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) { + afl, 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) { case 0: @@ -2190,12 +2190,102 @@ havoc_stage: break; + } + + case 15: { + + /* Overwrite bytes with a randomly selected chunk from another + testcase or insert that chunk. */ + + if (afl->queued_paths < 2) break; + + /* Pick a random queue entry and seek to it. */ + + u32 tid; + do + tid = rand_below(afl, afl->queued_paths); + while (tid == afl->current_entry); + + struct queue_entry* target = afl->queue_buf[tid]; + + /* 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; + } /* Values 15 and 16 can be selected only if there are any extras present in the dictionaries. */ - case 15: { + case 16: { /* Overwrite bytes with an extra. */ @@ -2233,7 +2323,7 @@ havoc_stage: } - case 16: { + case 17: { u32 use_extra, extra_len, insert_at = rand_below(afl, temp_len + 1); u8 *ptr; @@ -2357,20 +2447,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. */ -- cgit 1.4.1 From ce9b4698fec5222e0af1b62d68c4105e6364771e Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 21 Jul 2020 20:53:51 +0200 Subject: added andrea's splicing, added cycle_schedules --- GNUmakefile | 2 +- include/afl-fuzz.h | 11 +- include/config.h | 24 ++ include/envs.h | 1 + src/afl-fuzz-one.c | 719 +++++++++++++++++++++++++++++++++++++++++++-------- src/afl-fuzz-queue.c | 112 +++++++- src/afl-fuzz-state.c | 7 + src/afl-fuzz.c | 80 +++++- 8 files changed, 834 insertions(+), 122 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/GNUmakefile b/GNUmakefile index f44ef95e..86d6a947 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -455,7 +455,7 @@ code-format: ./.custom-format.py -i llvm_mode/*.h ./.custom-format.py -i llvm_mode/*.cc ./.custom-format.py -i gcc_plugin/*.c - #./.custom-format.py -i gcc_plugin/*.h + @#./.custom-format.py -i gcc_plugin/*.h ./.custom-format.py -i gcc_plugin/*.cc ./.custom-format.py -i custom_mutators/*/*.c ./.custom-format.py -i custom_mutators/*/*.h diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index adab8155..96d3d9f4 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -139,7 +139,8 @@ struct queue_entry { var_behavior, /* Variable behavior? */ favored, /* Currently favored? */ fs_redundant, /* Marked as redundant in the fs? */ - fully_colorized; /* Do not run redqueen stage again */ + fully_colorized, /* Do not run redqueen stage again */ + is_ascii; /* Is the input just ascii text? */ u32 bitmap_size, /* Number of bits set in bitmap */ fuzz_level; /* Number of fuzzing iterations */ @@ -333,7 +334,7 @@ typedef struct afl_env_vars { afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child_output, afl_autoresume, - afl_cal_fast; + afl_cal_fast, afl_cycle_schedules; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_skip_crashes, *afl_preload; @@ -454,7 +455,9 @@ typedef struct afl_state { fixed_seed, /* do not reseed */ fast_cal, /* Try to calibrate faster? */ disable_trim, /* Never trim in fuzz_one */ - shmem_testcase_mode; /* If sharedmem testcases are used */ + shmem_testcase_mode, /* If sharedmem testcases are used */ + expand_havoc, /* perform expensive havoc after no find */ + cycle_schedules; /* cycle power schedules ? */ u8 *virgin_bits, /* Regions yet untouched by fuzzing */ *virgin_tmout, /* Bits we haven't seen in tmouts */ @@ -548,7 +551,7 @@ typedef struct afl_state { // growing buf struct queue_entry **queue_buf; - size_t queue_size; + size_t queue_size; struct queue_entry **top_rated; /* Top entries for bitmap bytes */ diff --git a/include/config.h b/include/config.h index 4503c3e9..9710cd1f 100644 --- a/include/config.h +++ b/include/config.h @@ -401,5 +401,29 @@ // #define IGNORE_FINDS +/* Text mutations */ + +/* What is the minimum length of a queue input to be evaluated for "is_ascii"? ++ */ + +#define AFL_TXT_MIN_LEN 12 + +/* What is the minimum percentage of ascii characters present to be classifed + as "is_ascii"? */ + +#define AFL_TXT_MIN_PERCENT 95 + +/* How often to perform ASCII mutations 0 = disable, 1-8 are good values */ + +#define AFL_TXT_BIAS 6 + +/* Maximum length of a string to tamper with */ + +#define AFL_TXT_STRING_MAX_LEN 1024 + +/* Maximum mutations on a string */ + +#define AFL_TXT_STRING_MAX_MUTATIONS 8 + #endif /* ! _HAVE_CONFIG_H */ diff --git a/include/envs.h b/include/envs.h index 86222418..cb3c183e 100644 --- a/include/envs.h +++ b/include/envs.h @@ -34,6 +34,7 @@ static char *afl_environment_variables[] = { "AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_ONLY", "AFL_CXX", + "AFL_CYCLE_SCHEDULES", "AFL_DEBUG", "AFL_DEBUG_CHILD_OUTPUT", "AFL_DEBUG_GDB", diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 399bfcab..250409da 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -24,6 +24,11 @@ */ #include "afl-fuzz.h" +#include + +static u8 *strnstr(const u8 *s, const u8 *find, size_t slen); +static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from, + u8 *to); /* MOpt */ @@ -362,6 +367,450 @@ 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 + +/* search a string */ + +static u8 *strnstr(const u8 *s, const u8 *find, size_t slen) { + + char c, sc; + size_t len; + + if ((c = *find++) != '\0') { + + len = strlen(find); + do { + + do { + + if (slen-- < 1 || (sc = *s++) == '\0') return (NULL); + + } while (sc != c); + + if (len > slen) return (NULL); + + } while (strncmp(s, find, len) != 0); + + s--; + + } + + return ((u8 *)s); + +} + +/* replace between deliminators, if rep == NULL, then we will duplicate the + * target */ + +static u32 delim_replace(u8 **out_buf, s32 *temp_len, size_t pos, + const u8 *ldelim, const u8 *rdelim, u8 *rep) { + + u8 *end_buf = *out_buf + *temp_len; + u8 *ldelim_start = strnstr(*out_buf + pos, ldelim, *temp_len - pos); + + if (ldelim_start != NULL) { + + u32 max = (end_buf - ldelim_start - 1 > AFL_TXT_STRING_MAX_LEN + ? AFL_TXT_STRING_MAX_LEN + : end_buf - ldelim_start - 1); + + if (max > 0) { + + u8 *rdelim_end = strnstr(ldelim_start + 1, rdelim, max); + + if (rdelim_end != NULL) { + + u32 rep_len, delim_space_len = rdelim_end - ldelim_start - 1, xtra = 0; + + if (rep != NULL) { + + rep_len = (u32)strlen(rep); + + } else { // NULL? then we copy the value in between the delimiters + + rep_len = delim_space_len; + delim_space_len = 0; + rep = ldelim_start + 1; + xtra = rep_len; + + } + + if (rep_len != delim_space_len) { + + memmove(ldelim_start + rep_len + xtra + 1, rdelim_end, + *temp_len - (rdelim_end - *out_buf)); + + } + + memcpy(ldelim_start + 1, rep, rep_len); + *temp_len = (*temp_len - delim_space_len + rep_len); + + return 1; + + } + + } + + } + + return 0; + +} + +static u32 delim_swap(u8 **out_buf, s32 *temp_len, size_t pos, const u8 *ldelim, + const u8 *mdelim, const u8 *rdelim) { + + u8 *out_buf_end = *out_buf + *temp_len; + u32 max = (*temp_len - pos > AFL_TXT_STRING_MAX_LEN ? AFL_TXT_STRING_MAX_LEN + : *temp_len - pos); + u8 *ldelim_start = strnstr(*out_buf + pos, ldelim, max); + + if (ldelim_start != NULL) { + + max = (out_buf_end - ldelim_start - 1 > AFL_TXT_STRING_MAX_LEN + ? AFL_TXT_STRING_MAX_LEN + : out_buf_end - ldelim_start - 1); + if (max > 1) { + + u8 *mdelim_pos = strnstr(ldelim_start + 1, mdelim, max); + + if (mdelim_pos != NULL) { + + max = (out_buf_end - mdelim_pos - 1 > AFL_TXT_STRING_MAX_LEN + ? AFL_TXT_STRING_MAX_LEN + : out_buf_end - mdelim_pos - 1); + if (max > 0) { + + u8 *rdelim_end = strnstr(mdelim + 1, rdelim, max); + + if (rdelim_end != NULL) { + + u32 first_len = mdelim_pos - ldelim_start - 1; + u32 second_len = rdelim_end - mdelim_pos - 1; + u8 scratch[AFL_TXT_STRING_MAX_LEN]; + + memcpy(scratch, ldelim_start + 1, first_len); + + if (first_len != second_len) { + + memmove(ldelim_start + second_len + 1, mdelim_pos, + out_buf_end - mdelim_pos); + + } + + memcpy(ldelim_start + 1, mdelim_pos + 1, second_len); + + if (first_len != second_len) { + + memmove(mdelim_pos + first_len + 1, rdelim_end, + out_buf_end - rdelim_end); + + } + + memcpy(mdelim_pos + 1, scratch, first_len); + + return 1; + + } + + } + + } + + } + + } + + return 0; + +} + +/* replace a string */ + +static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from, + u8 *to) { + + u8 *start = strnstr(*out_buf + pos, from, *temp_len - pos); + + if (start) { + + u32 from_len = strlen(from); + u32 to_len = strlen(to); + + if (from_len != to_len) { + + memmove(start + to_len, start + from_len, + *temp_len - from_len - (start - *out_buf)); + + } + + memcpy(start, to, to_len); + *temp_len = (*temp_len - from_len + to_len); + + return 1; + + } + + return 0; + +} + +/* Returns 1 if a mutant was generated and placed in out_buf, 0 if none + * generated. */ + +static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { + + s32 temp_len; + u32 pos, yes = 0, + mutations = rand_below(afl, AFL_TXT_STRING_MAX_MUTATIONS) + 1; + u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), + *orig_temp_len + AFL_TXT_STRING_MAX_MUTATIONS); + temp_len = *orig_temp_len; + memcpy(new_buf, *out_buf, temp_len); + + for (u32 i = 0; i < mutations; i++) { + + if (temp_len < AFL_TXT_MIN_LEN) { return 0; } + + pos = rand_below(afl, temp_len - 1); + int choice = rand_below(afl, 72); + switch (choice) { + + case 0: /* Semantic statement deletion */ + yes += string_replace(out_buf, &temp_len, pos, "\n", "#"); + break; + case 1: + yes += string_replace(out_buf, &temp_len, pos, "(", "(!"); + break; + case 2: + yes += string_replace(out_buf, &temp_len, pos, "==", "!="); + break; + case 3: + yes += string_replace(out_buf, &temp_len, pos, "!=", "=="); + break; + case 4: + yes += string_replace(out_buf, &temp_len, pos, "==", "<"); + break; + case 5: + yes += string_replace(out_buf, &temp_len, pos, "<", "=="); + break; + case 6: + yes += string_replace(out_buf, &temp_len, pos, "==", ">"); + break; + case 7: + yes += string_replace(out_buf, &temp_len, pos, ">", "=="); + break; + case 8: + yes += string_replace(out_buf, &temp_len, pos, "=", "<"); + break; + case 9: + yes += string_replace(out_buf, &temp_len, pos, "=", ">"); + break; + case 10: + yes += string_replace(out_buf, &temp_len, pos, "<", ">"); + break; + case 11: + yes += string_replace(out_buf, &temp_len, pos, ">", "<"); + break; + case 12: + yes += string_replace(out_buf, &temp_len, pos, "++", "--"); + break; + case 13: + yes += string_replace(out_buf, &temp_len, pos, "--", "++"); + break; + case 14: + yes += string_replace(out_buf, &temp_len, pos, "+", "-"); + break; + case 15: + yes += string_replace(out_buf, &temp_len, pos, "+", "*"); + break; + case 16: + yes += string_replace(out_buf, &temp_len, pos, "+", "/"); + break; + case 17: + yes += string_replace(out_buf, &temp_len, pos, "+", "%"); + break; + case 18: + yes += string_replace(out_buf, &temp_len, pos, "*", "-"); + break; + case 19: + yes += string_replace(out_buf, &temp_len, pos, "*", "+"); + break; + case 20: + yes += string_replace(out_buf, &temp_len, pos, "*", "/"); + break; + case 21: + yes += string_replace(out_buf, &temp_len, pos, "*", "%"); + break; + case 22: + yes += string_replace(out_buf, &temp_len, pos, "-", "+"); + break; + case 23: + yes += string_replace(out_buf, &temp_len, pos, "-", "*"); + break; + case 24: + yes += string_replace(out_buf, &temp_len, pos, "-", "/"); + break; + case 25: + yes += string_replace(out_buf, &temp_len, pos, "-", "%"); + break; + case 26: + yes += string_replace(out_buf, &temp_len, pos, "/", "-"); + break; + case 27: + yes += string_replace(out_buf, &temp_len, pos, "/", "*"); + break; + case 28: + yes += string_replace(out_buf, &temp_len, pos, "/", "+"); + break; + case 29: + yes += string_replace(out_buf, &temp_len, pos, "/", "%"); + break; + case 30: + yes += string_replace(out_buf, &temp_len, pos, "%", "-"); + break; + case 31: + yes += string_replace(out_buf, &temp_len, pos, "%", "*"); + break; + case 32: + yes += string_replace(out_buf, &temp_len, pos, "%", "/"); + break; + case 33: + yes += string_replace(out_buf, &temp_len, pos, "%", "+"); + break; + case 34: + yes += string_replace(out_buf, &temp_len, pos, " ", "|"); + break; + case 35: + yes += string_replace(out_buf, &temp_len, pos, " ", "$"); + break; + case 36: + yes += string_replace(out_buf, &temp_len, pos, "0", "1"); + break; + case 37: + yes += string_replace(out_buf, &temp_len, pos, "1", "0"); + break; + case 38: + yes += string_replace(out_buf, &temp_len, pos, " ", "`"); + break; + case 39: + yes += string_replace(out_buf, &temp_len, pos, " ", "\""); + break; + case 40: + yes += string_replace(out_buf, &temp_len, pos, ";", " "); + break; + case 41: + yes += string_replace(out_buf, &temp_len, pos, "&&", "||"); + break; + case 42: + yes += string_replace(out_buf, &temp_len, pos, "||", "&&"); + break; + case 43: + yes += string_replace(out_buf, &temp_len, pos, "!", ""); + break; + case 44: + yes += string_replace(out_buf, &temp_len, pos, "==", "="); + break; + case 45: + yes += string_replace(out_buf, &temp_len, pos, "--", ""); + break; + case 46: + yes += string_replace(out_buf, &temp_len, pos, "<<", "<"); + break; + case 47: + yes += string_replace(out_buf, &temp_len, pos, ">>", ">"); + break; + case 48: + yes += string_replace(out_buf, &temp_len, pos, "<", "<<"); + break; + case 49: + yes += string_replace(out_buf, &temp_len, pos, ">", ">>"); + break; + case 50: + yes += string_replace(out_buf, &temp_len, pos, "\"", "'"); + break; + case 51: + yes += string_replace(out_buf, &temp_len, pos, "'", "\""); + break; + case 52: + yes += string_replace(out_buf, &temp_len, pos, "(", "\""); + break; + case 53: /* Remove a semicolon delimited statement after a semicolon */ + yes += delim_replace(out_buf, &temp_len, pos, ";", ";", ";"); + break; + case 54: /* Remove a semicolon delimited statement after a left curly + brace */ + yes += delim_replace(out_buf, &temp_len, pos, "}", ";", "}"); + break; + case 55: /* Remove a curly brace construct */ + yes += delim_replace(out_buf, &temp_len, pos, "{", "}", ""); + break; + case 56: /* Replace a curly brace construct with an empty one */ + yes += delim_replace(out_buf, &temp_len, pos, "{", "}", "{}"); + break; + case 57: + yes += delim_swap(out_buf, &temp_len, pos, ";", ";", ";"); + break; + case 58: + yes += delim_swap(out_buf, &temp_len, pos, "}", ";", ";"); + break; + case 59: /* Swap comma delimited things case 1 */ + yes += delim_swap(out_buf, &temp_len, pos, "(", ",", ")"); + break; + case 60: /* Swap comma delimited things case 2 */ + yes += delim_swap(out_buf, &temp_len, pos, "(", ",", ","); + break; + case 61: /* Swap comma delimited things case 3 */ + yes += delim_swap(out_buf, &temp_len, pos, ",", ",", ","); + break; + case 62: /* Swap comma delimited things case 4 */ + yes += delim_swap(out_buf, &temp_len, pos, ",", ",", ")"); + break; + case 63: /* Just delete a line */ + yes += delim_replace(out_buf, &temp_len, pos, "\n", "\n", ""); + break; + case 64: /* Delete something like "const" case 1 */ + yes += delim_replace(out_buf, &temp_len, pos, " ", " ", ""); + break; + case 65: /* Delete something like "const" case 2 */ + yes += delim_replace(out_buf, &temp_len, pos, "\n", " ", ""); + break; + case 66: /* Delete something like "const" case 3 */ + yes += delim_replace(out_buf, &temp_len, pos, "(", " ", ""); + break; + case 67: /* Swap space delimited things case 1 */ + yes += delim_swap(out_buf, &temp_len, pos, " ", " ", " "); + break; + case 68: /* Swap space delimited things case 2 */ + yes += delim_swap(out_buf, &temp_len, pos, " ", " ", ")"); + break; + case 69: /* Swap space delimited things case 3 */ + yes += delim_swap(out_buf, &temp_len, pos, "(", " ", " "); + break; + case 70: /* Swap space delimited things case 4 */ + yes += delim_swap(out_buf, &temp_len, pos, "(", " ", ")"); + break; + case 71: /* Duplicate a single line of code */ + yes += delim_replace(out_buf, &temp_len, pos, "\n", "\n", NULL); + break; + case 72: /* Duplicate a construct (most often, a non-nested for loop */ + yes += delim_replace(out_buf, &temp_len, pos, "\n", "}", NULL); + break; + + } + + } + + if (yes == 0 || temp_len <= 0) { return 0; } + + swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); + *out_buf = new_buf; + *orig_temp_len = temp_len; + + return 1; + +} + /* 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 +2303,22 @@ 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) + + (afl->queue_cur->is_ascii ? AFL_TXT_BIAS : 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 +2361,9 @@ havoc_stage: } - switch (rand_below( - afl, 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) { + retry_havoc: + + switch ((r = rand_below(afl, r_max))) { case 0: @@ -2191,176 +2657,203 @@ havoc_stage: break; } - - case 15: { - /* Overwrite bytes with a randomly selected chunk from another - testcase or insert that chunk. */ + default: - if (afl->queued_paths < 2) break; + if (likely(r <= 16 && (afl->extras_cnt || afl->a_extras_cnt))) { - /* Pick a random queue entry and seek to it. */ + /* Values 15 and 16 can be selected only if there are any extras + present in the dictionaries. */ - u32 tid; - do - tid = rand_below(afl, afl->queued_paths); - while (tid == afl->current_entry); + if (r == 15) { - struct queue_entry* target = afl->queue_buf[tid]; + /* Overwrite bytes with an extra. */ - /* Make sure that the target has a reasonable length. */ + if (!afl->extras_cnt || + (afl->a_extras_cnt && rand_below(afl, 2))) { - while (target && (target->len < 2 || target == afl->queue_cur)) - target = target->next; + /* No user-specified extras or odds in our favor. Let's use an + auto-detected one. */ - if (!target) break; + u32 use_extra = rand_below(afl, afl->a_extras_cnt); + u32 extra_len = afl->a_extras[use_extra].len; + u32 insert_at; - /* Read the testcase into a new buffer. */ + if (extra_len > temp_len) { break; } - fd = open(target->fname, O_RDONLY); + insert_at = rand_below(afl, temp_len - extra_len + 1); + memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, + extra_len); - if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); } + } else { - u32 new_len = target->len; - u8 * new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len); + /* No auto extras or odds in our favor. Use the dictionary. */ - ck_read(fd, new_buf, new_len, target->fname); + u32 use_extra = rand_below(afl, afl->extras_cnt); + u32 extra_len = afl->extras[use_extra].len; + u32 insert_at; - close(fd); + if (extra_len > temp_len) { break; } - 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; - } + insert_at = rand_below(afl, temp_len - extra_len + 1); + memcpy(out_buf + insert_at, afl->extras[use_extra].data, + extra_len); - if (overwrite) { + } - u32 copy_from, copy_to, copy_len; + break; - copy_len = choose_block_len(afl, new_len - 1); - if (copy_len > temp_len) copy_len = temp_len; + } else { // case 16 - copy_from = rand_below(afl, new_len - copy_len + 1); - copy_to = rand_below(afl, temp_len - copy_len + 1); + u32 use_extra, extra_len, + insert_at = rand_below(afl, temp_len + 1); + u8 *ptr; - memmove(out_buf + copy_to, new_buf + copy_from, copy_len); + /* Insert an extra. Do the same dice-rolling stuff as for the + previous case. */ - } 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); + if (!afl->extras_cnt || + (afl->a_extras_cnt && rand_below(afl, 2))) { - u8 * temp_buf = - ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len); + use_extra = rand_below(afl, afl->a_extras_cnt); + extra_len = afl->a_extras[use_extra].len; + ptr = afl->a_extras[use_extra].data; - /* Head */ + } else { - memcpy(temp_buf, out_buf, clone_to); + use_extra = rand_below(afl, afl->extras_cnt); + extra_len = afl->extras[use_extra].len; + ptr = afl->extras[use_extra].data; - /* Inserted part */ + } - memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); + if (temp_len + extra_len >= MAX_FILE) { break; } - /* Tail */ - memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, - temp_len - clone_to); + out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len); - swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); - out_buf = temp_buf; - temp_len += clone_len; - - } + /* Tail */ + memmove(out_buf + insert_at + extra_len, out_buf + insert_at, + temp_len - insert_at); - break; + /* Inserted part */ + memcpy(out_buf + insert_at, ptr, extra_len); - } + temp_len += extra_len; - /* Values 15 and 16 can be selected only if there are any extras - present in the dictionaries. */ + break; - case 16: { + } - /* Overwrite bytes with an extra. */ + } else - if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) { + switch (r) { - /* No user-specified extras or odds in our favor. Let's use an - auto-detected one. */ + case 15: // fall through + case 17: { - u32 use_extra = rand_below(afl, afl->a_extras_cnt); - u32 extra_len = afl->a_extras[use_extra].len; - u32 insert_at; + /* Overwrite bytes with a randomly selected chunk from another + testcase or insert that chunk. */ - if (extra_len > temp_len) { break; } + if (afl->queued_paths < 2) break; - insert_at = rand_below(afl, temp_len - extra_len + 1); - memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, - extra_len); + /* Pick a random queue entry and seek to it. */ - } else { + u32 tid; + do + tid = rand_below(afl, afl->queued_paths); + while (tid == afl->current_entry); - /* No auto extras or odds in our favor. Use the dictionary. */ + struct queue_entry *target = afl->queue_buf[tid]; - u32 use_extra = rand_below(afl, afl->extras_cnt); - u32 extra_len = afl->extras[use_extra].len; - u32 insert_at; + /* Make sure that the target has a reasonable length. */ - if (extra_len > temp_len) { break; } + while (target && (target->len < 2 || target == afl->queue_cur)) + target = target->next; - insert_at = rand_below(afl, temp_len - extra_len + 1); - memcpy(out_buf + insert_at, afl->extras[use_extra].data, extra_len); + if (!target) break; - } + /* Read the testcase into a new buffer. */ - break; + fd = open(target->fname, O_RDONLY); - } + if (unlikely(fd < 0)) { + + PFATAL("Unable to open '%s'", target->fname); - case 17: { + } - u32 use_extra, extra_len, insert_at = rand_below(afl, temp_len + 1); - u8 *ptr; + u32 new_len = target->len; + u8 *new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len); - /* Insert an extra. Do the same dice-rolling stuff as for the - previous case. */ + ck_read(fd, new_buf, new_len, target->fname); - if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) { + close(fd); - use_extra = rand_below(afl, afl->a_extras_cnt); - extra_len = afl->a_extras[use_extra].len; - ptr = afl->a_extras[use_extra].data; + u8 overwrite = 0; + if (temp_len >= 2 && rand_below(afl, 2)) + overwrite = 1; + else if (temp_len + HAVOC_BLK_XL >= MAX_FILE) { - } else { + if (temp_len >= 2) + overwrite = 1; + else + break; - use_extra = rand_below(afl, afl->extras_cnt); - extra_len = afl->extras[use_extra].len; - ptr = afl->extras[use_extra].data; + } - } + if (overwrite) { - if (temp_len + extra_len >= MAX_FILE) { break; } + u32 copy_from, copy_to, copy_len; - out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len); + copy_len = choose_block_len(afl, new_len - 1); + if (copy_len > temp_len) copy_len = temp_len; - /* Tail */ - memmove(out_buf + insert_at + extra_len, out_buf + insert_at, - temp_len - insert_at); + copy_from = rand_below(afl, new_len - copy_len + 1); + copy_to = rand_below(afl, temp_len - copy_len + 1); - /* Inserted part */ - memcpy(out_buf + insert_at, ptr, extra_len); + memmove(out_buf + copy_to, new_buf + copy_from, copy_len); - temp_len += extra_len; + } else { - break; + 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; + + } + + default: + + // perform ascii mutations + if (text_mutation(afl, &out_buf, &temp_len) == 0) + goto retry_havoc; + + } // end default: switch(r) } @@ -4827,7 +5320,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 a96995e5..56073b0a 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -24,6 +24,7 @@ #include "afl-fuzz.h" #include +#include #define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size @@ -102,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) { @@ -139,9 +242,10 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { afl->q_prev100 = q; } - - 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; + + 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(); @@ -164,6 +268,8 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { } + q->is_ascii = check_if_text(q); + } /* Destroy the entire queue. */ diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index e56d122a..f68a79e8 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -293,6 +293,13 @@ 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_CAL_FAST", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index df2896d2..88f8e902 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1252,11 +1252,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 { @@ -1270,6 +1301,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 && -- cgit 1.4.1 From b015e4f07aabb39e1683406704f2aae1f7dcde4a Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 22 Jul 2020 16:15:16 +0200 Subject: epand havoc now env --- include/envs.h | 1 + src/afl-fuzz-one.c | 211 ++++++++++++++++++++++++++++++++++------------------- src/afl-fuzz.c | 1 + 3 files changed, 138 insertions(+), 75 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/include/envs.h b/include/envs.h index cb3c183e..c1c7d387 100644 --- a/include/envs.h +++ b/include/envs.h @@ -130,6 +130,7 @@ static char *afl_environment_variables[] = { "AFL_USE_CFISAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", + "AFL_EXPAND_HAVOC_NOW", NULL }; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 250409da..a0ecb7a9 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -564,238 +564,299 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { u32 pos, yes = 0, mutations = rand_below(afl, AFL_TXT_STRING_MAX_MUTATIONS) + 1; u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), - *orig_temp_len + AFL_TXT_STRING_MAX_MUTATIONS); + *orig_temp_len + AFL_TXT_STRING_MAX_MUTATIONS +1); temp_len = *orig_temp_len; memcpy(new_buf, *out_buf, temp_len); + new_buf[temp_len] = 0; for (u32 i = 0; i < mutations; i++) { if (temp_len < AFL_TXT_MIN_LEN) { return 0; } pos = rand_below(afl, temp_len - 1); - int choice = rand_below(afl, 72); + int choice = rand_below(afl, 80); switch (choice) { case 0: /* Semantic statement deletion */ - yes += string_replace(out_buf, &temp_len, pos, "\n", "#"); + yes += string_replace(&new_buf, &temp_len, pos, "\n", "#"); break; case 1: - yes += string_replace(out_buf, &temp_len, pos, "(", "(!"); + yes += string_replace(&new_buf, &temp_len, pos, "(", "(!"); break; case 2: - yes += string_replace(out_buf, &temp_len, pos, "==", "!="); + yes += string_replace(&new_buf, &temp_len, pos, "==", "!="); break; case 3: - yes += string_replace(out_buf, &temp_len, pos, "!=", "=="); + yes += string_replace(&new_buf, &temp_len, pos, "!=", "=="); break; case 4: - yes += string_replace(out_buf, &temp_len, pos, "==", "<"); + yes += string_replace(&new_buf, &temp_len, pos, "==", "<"); break; case 5: - yes += string_replace(out_buf, &temp_len, pos, "<", "=="); + yes += string_replace(&new_buf, &temp_len, pos, "<", "=="); break; case 6: - yes += string_replace(out_buf, &temp_len, pos, "==", ">"); + yes += string_replace(&new_buf, &temp_len, pos, "==", ">"); break; case 7: - yes += string_replace(out_buf, &temp_len, pos, ">", "=="); + yes += string_replace(&new_buf, &temp_len, pos, ">", "=="); break; case 8: - yes += string_replace(out_buf, &temp_len, pos, "=", "<"); + yes += string_replace(&new_buf, &temp_len, pos, "=", "<"); break; case 9: - yes += string_replace(out_buf, &temp_len, pos, "=", ">"); + yes += string_replace(&new_buf, &temp_len, pos, "=", ">"); break; case 10: - yes += string_replace(out_buf, &temp_len, pos, "<", ">"); + yes += string_replace(&new_buf, &temp_len, pos, "<", ">"); break; case 11: - yes += string_replace(out_buf, &temp_len, pos, ">", "<"); + yes += string_replace(&new_buf, &temp_len, pos, ">", "<"); break; case 12: - yes += string_replace(out_buf, &temp_len, pos, "++", "--"); + yes += string_replace(&new_buf, &temp_len, pos, "++", "--"); break; case 13: - yes += string_replace(out_buf, &temp_len, pos, "--", "++"); + yes += string_replace(&new_buf, &temp_len, pos, "--", "++"); break; case 14: - yes += string_replace(out_buf, &temp_len, pos, "+", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "+", "-"); break; case 15: - yes += string_replace(out_buf, &temp_len, pos, "+", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "+", "*"); break; case 16: - yes += string_replace(out_buf, &temp_len, pos, "+", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "+", "/"); break; case 17: - yes += string_replace(out_buf, &temp_len, pos, "+", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "+", "%"); break; case 18: - yes += string_replace(out_buf, &temp_len, pos, "*", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "*", "-"); break; case 19: - yes += string_replace(out_buf, &temp_len, pos, "*", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "*", "+"); break; case 20: - yes += string_replace(out_buf, &temp_len, pos, "*", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "*", "/"); break; case 21: - yes += string_replace(out_buf, &temp_len, pos, "*", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "*", "%"); break; case 22: - yes += string_replace(out_buf, &temp_len, pos, "-", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "-", "+"); break; case 23: - yes += string_replace(out_buf, &temp_len, pos, "-", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "-", "*"); break; case 24: - yes += string_replace(out_buf, &temp_len, pos, "-", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "-", "/"); break; case 25: - yes += string_replace(out_buf, &temp_len, pos, "-", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "-", "%"); break; case 26: - yes += string_replace(out_buf, &temp_len, pos, "/", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "/", "-"); break; case 27: - yes += string_replace(out_buf, &temp_len, pos, "/", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "/", "*"); break; case 28: - yes += string_replace(out_buf, &temp_len, pos, "/", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "/", "+"); break; case 29: - yes += string_replace(out_buf, &temp_len, pos, "/", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "/", "%"); break; case 30: - yes += string_replace(out_buf, &temp_len, pos, "%", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "%", "-"); break; case 31: - yes += string_replace(out_buf, &temp_len, pos, "%", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "%", "*"); break; case 32: - yes += string_replace(out_buf, &temp_len, pos, "%", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "%", "/"); break; case 33: - yes += string_replace(out_buf, &temp_len, pos, "%", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "%", "+"); break; case 34: - yes += string_replace(out_buf, &temp_len, pos, " ", "|"); + yes += string_replace(&new_buf, &temp_len, pos, " ", "|"); break; case 35: - yes += string_replace(out_buf, &temp_len, pos, " ", "$"); + yes += string_replace(&new_buf, &temp_len, pos, " ", "$"); break; case 36: - yes += string_replace(out_buf, &temp_len, pos, "0", "1"); + yes += string_replace(&new_buf, &temp_len, pos, "0", "1"); break; case 37: - yes += string_replace(out_buf, &temp_len, pos, "1", "0"); + yes += string_replace(&new_buf, &temp_len, pos, "1", "0"); break; case 38: - yes += string_replace(out_buf, &temp_len, pos, " ", "`"); + yes += string_replace(&new_buf, &temp_len, pos, " ", "`"); break; case 39: - yes += string_replace(out_buf, &temp_len, pos, " ", "\""); + yes += string_replace(&new_buf, &temp_len, pos, " ", "\""); break; case 40: - yes += string_replace(out_buf, &temp_len, pos, ";", " "); + yes += string_replace(&new_buf, &temp_len, pos, ";", " "); break; case 41: - yes += string_replace(out_buf, &temp_len, pos, "&&", "||"); + yes += string_replace(&new_buf, &temp_len, pos, "&&", "||"); break; case 42: - yes += string_replace(out_buf, &temp_len, pos, "||", "&&"); + yes += string_replace(&new_buf, &temp_len, pos, "||", "&&"); break; case 43: - yes += string_replace(out_buf, &temp_len, pos, "!", ""); + yes += string_replace(&new_buf, &temp_len, pos, "!", ""); break; case 44: - yes += string_replace(out_buf, &temp_len, pos, "==", "="); + yes += string_replace(&new_buf, &temp_len, pos, "==", "="); break; case 45: - yes += string_replace(out_buf, &temp_len, pos, "--", ""); + yes += string_replace(&new_buf, &temp_len, pos, "--", ""); break; case 46: - yes += string_replace(out_buf, &temp_len, pos, "<<", "<"); + yes += string_replace(&new_buf, &temp_len, pos, "<<", "<"); break; case 47: - yes += string_replace(out_buf, &temp_len, pos, ">>", ">"); + yes += string_replace(&new_buf, &temp_len, pos, ">>", ">"); break; case 48: - yes += string_replace(out_buf, &temp_len, pos, "<", "<<"); + yes += string_replace(&new_buf, &temp_len, pos, "<", "<<"); break; case 49: - yes += string_replace(out_buf, &temp_len, pos, ">", ">>"); + yes += string_replace(&new_buf, &temp_len, pos, ">", ">>"); break; case 50: - yes += string_replace(out_buf, &temp_len, pos, "\"", "'"); + yes += string_replace(&new_buf, &temp_len, pos, "\"", "'"); break; case 51: - yes += string_replace(out_buf, &temp_len, pos, "'", "\""); + yes += string_replace(&new_buf, &temp_len, pos, "'", "\""); break; case 52: - yes += string_replace(out_buf, &temp_len, pos, "(", "\""); + yes += string_replace(&new_buf, &temp_len, pos, "(", "\""); break; case 53: /* Remove a semicolon delimited statement after a semicolon */ - yes += delim_replace(out_buf, &temp_len, pos, ";", ";", ";"); + yes += delim_replace(&new_buf, &temp_len, pos, ";", ";", ";"); break; case 54: /* Remove a semicolon delimited statement after a left curly brace */ - yes += delim_replace(out_buf, &temp_len, pos, "}", ";", "}"); + yes += delim_replace(&new_buf, &temp_len, pos, "}", ";", "}"); break; case 55: /* Remove a curly brace construct */ - yes += delim_replace(out_buf, &temp_len, pos, "{", "}", ""); + yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", ""); break; case 56: /* Replace a curly brace construct with an empty one */ - yes += delim_replace(out_buf, &temp_len, pos, "{", "}", "{}"); + yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", "{}"); break; case 57: - yes += delim_swap(out_buf, &temp_len, pos, ";", ";", ";"); + yes += delim_swap(&new_buf, &temp_len, pos, ";", ";", ";"); break; case 58: - yes += delim_swap(out_buf, &temp_len, pos, "}", ";", ";"); + yes += delim_swap(&new_buf, &temp_len, pos, "}", ";", ";"); break; case 59: /* Swap comma delimited things case 1 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", ",", ")"); + yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ")"); break; case 60: /* Swap comma delimited things case 2 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", ",", ","); + yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ","); break; case 61: /* Swap comma delimited things case 3 */ - yes += delim_swap(out_buf, &temp_len, pos, ",", ",", ","); + yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ","); break; case 62: /* Swap comma delimited things case 4 */ - yes += delim_swap(out_buf, &temp_len, pos, ",", ",", ")"); + yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ")"); break; case 63: /* Just delete a line */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", "\n", ""); + yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", ""); break; case 64: /* Delete something like "const" case 1 */ - yes += delim_replace(out_buf, &temp_len, pos, " ", " ", ""); + yes += delim_replace(&new_buf, &temp_len, pos, " ", " ", ""); break; case 65: /* Delete something like "const" case 2 */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", " ", ""); + yes += delim_replace(&new_buf, &temp_len, pos, "\n", " ", ""); break; case 66: /* Delete something like "const" case 3 */ - yes += delim_replace(out_buf, &temp_len, pos, "(", " ", ""); + yes += delim_replace(&new_buf, &temp_len, pos, "(", " ", ""); break; case 67: /* Swap space delimited things case 1 */ - yes += delim_swap(out_buf, &temp_len, pos, " ", " ", " "); + yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", " "); break; case 68: /* Swap space delimited things case 2 */ - yes += delim_swap(out_buf, &temp_len, pos, " ", " ", ")"); + yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", ")"); break; case 69: /* Swap space delimited things case 3 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", " ", " "); + yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", " "); break; case 70: /* Swap space delimited things case 4 */ - yes += delim_swap(out_buf, &temp_len, pos, "(", " ", ")"); + yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", ")"); break; case 71: /* Duplicate a single line of code */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", "\n", NULL); + yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", NULL); break; case 72: /* Duplicate a construct (most often, a non-nested for loop */ - yes += delim_replace(out_buf, &temp_len, pos, "\n", "}", NULL); + yes += delim_replace(&new_buf, &temp_len, pos, "\n", "}", NULL); break; + default: { + + for (u32 j = pos; j < temp_len; ++j) { + if (isdigit(new_buf[j])) { + + u8* endptr; + unsigned long long num = strtoull(new_buf +j, (char**)&endptr, 0); + + switch (rand_below(afl, 8)) { + case 0: + num = rand_below(afl, INT_MAX); + break; + case 1: + num = rand_next(afl); + break; + case 2: + num += 1 + rand_below(afl, 255); + break; + case 3: + num -= 1 + rand_below(afl, 255); + break; + case 4: + num *= 1 + rand_below(afl, 255); + break; + case 5: + num /= 1 + rand_below(afl, 255); + break; + case 6: + num /= 1 + rand_below(afl, 255); + break; + case 7: + num = ~num; + break; + } + + const char* fmt = "%llu"; + if (rand_below(afl, 5) == 0) // add - sign with 1/5 probability + fmt = "-%llu"; + + size_t num_len = snprintf(NULL, 0, fmt, num); + size_t old_len = endptr - (new_buf +j); + if (num_len < old_len) { + memmove(new_buf +j +num_len, endptr, temp_len - (endptr - new_buf)); + snprintf(new_buf +j, num_len, fmt, num); + temp_len -= old_len - num_len; + } else if (num_len == old_len) { + snprintf(new_buf +j, num_len, fmt, num); + } else { + new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + (num_len - old_len)); + memmove(new_buf +j +num_len, endptr, temp_len - (endptr - new_buf)); + snprintf(new_buf +j, num_len, fmt, num); + temp_len += num_len - old_len; + } + + yes += 1; + + } + } + + } } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 88f8e902..8220b41b 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -900,6 +900,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) { -- cgit 1.4.1 From a46a733dbee6defce6770d79e8e001430e76fe18 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 22 Jul 2020 17:04:57 +0200 Subject: fix bugs --- src/afl-fuzz-one.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index a0ecb7a9..69671f71 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -802,6 +802,8 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { for (u32 j = pos; j < temp_len; ++j) { if (isdigit(new_buf[j])) { + new_buf[temp_len] = 0; // should be safe thanks to the initial grow + u8* endptr; unsigned long long num = strtoull(new_buf +j, (char**)&endptr, 0); @@ -839,19 +841,20 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { size_t num_len = snprintf(NULL, 0, fmt, num); size_t old_len = endptr - (new_buf +j); if (num_len < old_len) { - memmove(new_buf +j +num_len, endptr, temp_len - (endptr - new_buf)); + memmove(new_buf +j +num_len, new_buf +j +old_len, temp_len - (j + old_len)); snprintf(new_buf +j, num_len, fmt, num); temp_len -= old_len - num_len; } else if (num_len == old_len) { snprintf(new_buf +j, num_len, fmt, num); } else { - new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + (num_len - old_len)); - memmove(new_buf +j +num_len, endptr, temp_len - (endptr - new_buf)); + new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + (num_len - old_len) + AFL_TXT_STRING_MAX_MUTATIONS +1); + memmove(new_buf +j +num_len, new_buf +j +old_len, temp_len - (j + old_len)); snprintf(new_buf +j, num_len, fmt, num); temp_len += num_len - old_len; } yes += 1; + break; } } @@ -859,7 +862,7 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { } } - + } if (yes == 0 || temp_len <= 0) { return 0; } @@ -867,7 +870,7 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); *out_buf = new_buf; *orig_temp_len = temp_len; - + return 1; } -- cgit 1.4.1 From 1ddb70e0d9ec0c71a09c5c62f435a2b63ddfee53 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 23 Jul 2020 05:08:20 +0200 Subject: fix compilation --- src/afl-fuzz-one.c | 1 + src/afl-fuzz-redqueen.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 69671f71..7f96c2c6 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -25,6 +25,7 @@ #include "afl-fuzz.h" #include +#include static u8 *strnstr(const u8 *s, const u8 *find, size_t slen); static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from, diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 55b88bf8..de3adb2d 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -24,6 +24,7 @@ */ +#include #include "afl-fuzz.h" #include "cmplog.h" -- cgit 1.4.1 From 30c09915432af7a9e98f9b4d8b09566731e0cca9 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 24 Jul 2020 13:26:07 +0200 Subject: better text mutation --- include/afl-fuzz.h | 2 +- include/config.h | 7 +- src/afl-fuzz-one.c | 341 +++++++++++++++++++++++++----------------------- src/afl-fuzz-redqueen.c | 142 ++++++++++---------- src/afl-fuzz-state.c | 7 + src/afl-fuzz.c | 2 +- 6 files changed, 261 insertions(+), 240 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 96d3d9f4..0e2b7458 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -334,7 +334,7 @@ typedef struct afl_env_vars { afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child_output, afl_autoresume, - afl_cal_fast, afl_cycle_schedules; + afl_cal_fast, afl_cycle_schedules, afl_expand_havoc; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_skip_crashes, *afl_preload; diff --git a/include/config.h b/include/config.h index 9710cd1f..344a368f 100644 --- a/include/config.h +++ b/include/config.h @@ -403,15 +403,14 @@ /* Text mutations */ -/* What is the minimum length of a queue input to be evaluated for "is_ascii"? -+ */ +/* Minimum length of a queue input to be evaluated for "is_ascii"? */ #define AFL_TXT_MIN_LEN 12 /* What is the minimum percentage of ascii characters present to be classifed as "is_ascii"? */ -#define AFL_TXT_MIN_PERCENT 95 +#define AFL_TXT_MIN_PERCENT 94 /* How often to perform ASCII mutations 0 = disable, 1-8 are good values */ @@ -423,7 +422,7 @@ /* Maximum mutations on a string */ -#define AFL_TXT_STRING_MAX_MUTATIONS 8 +#define AFL_TXT_STRING_MAX_MUTATIONS 6 #endif /* ! _HAVE_CONFIG_H */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 7f96c2c6..dc19150d 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -559,13 +559,25 @@ static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from, /* Returns 1 if a mutant was generated and placed in out_buf, 0 if none * generated. */ +static const uint8_t text_mutation_special_chars[] = { + + '\t', '\n', '\r', ' ', '!', '"', '$', '%', '&', '\'', '(', ')', '*', + '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', + '\\', ']', '^', '_', '`', '{', '|', '}', '~', ' ' // space is here twice + +}; + static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { + if (*orig_temp_len < AFL_TXT_MIN_LEN) { return 0; } + s32 temp_len; u32 pos, yes = 0, - mutations = rand_below(afl, AFL_TXT_STRING_MAX_MUTATIONS) + 1; - u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), - *orig_temp_len + AFL_TXT_STRING_MAX_MUTATIONS +1); + mutations = rand_below(afl, AFL_TXT_STRING_MAX_MUTATIONS) + 16; + u8 *new_buf = + ck_maybe_grow(BUF_PARAMS(out_scratch), + *orig_temp_len + AFL_TXT_STRING_MAX_MUTATIONS + 16); + u8 fromc[2] = {0, 0}, toc[2] = {0, 0}; temp_len = *orig_temp_len; memcpy(new_buf, *out_buf, temp_len); new_buf[temp_len] = 0; @@ -575,9 +587,12 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { if (temp_len < AFL_TXT_MIN_LEN) { return 0; } pos = rand_below(afl, temp_len - 1); - int choice = rand_below(afl, 80); + int choice = rand_below(afl, 100); + switch (choice) { + /* 50% -> fixed replacements */ + case 0: /* Semantic statement deletion */ yes += string_replace(&new_buf, &temp_len, pos, "\n", "#"); break; @@ -624,246 +639,240 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { yes += string_replace(&new_buf, &temp_len, pos, "+", "-"); break; case 15: - yes += string_replace(&new_buf, &temp_len, pos, "+", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "-", "+"); break; case 16: - yes += string_replace(&new_buf, &temp_len, pos, "+", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "0", "1"); break; case 17: - yes += string_replace(&new_buf, &temp_len, pos, "+", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "1", "0"); break; case 18: - yes += string_replace(&new_buf, &temp_len, pos, "*", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "&&", "||"); break; case 19: - yes += string_replace(&new_buf, &temp_len, pos, "*", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "||", "&&"); break; case 20: - yes += string_replace(&new_buf, &temp_len, pos, "*", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "!", ""); break; case 21: - yes += string_replace(&new_buf, &temp_len, pos, "*", "%"); + yes += string_replace(&new_buf, &temp_len, pos, "==", "="); break; case 22: - yes += string_replace(&new_buf, &temp_len, pos, "-", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "=", "=="); break; case 23: - yes += string_replace(&new_buf, &temp_len, pos, "-", "*"); + yes += string_replace(&new_buf, &temp_len, pos, "--", ""); break; case 24: - yes += string_replace(&new_buf, &temp_len, pos, "-", "/"); + yes += string_replace(&new_buf, &temp_len, pos, "<<", "<"); break; case 25: - yes += string_replace(&new_buf, &temp_len, pos, "-", "%"); + yes += string_replace(&new_buf, &temp_len, pos, ">>", ">"); break; case 26: - yes += string_replace(&new_buf, &temp_len, pos, "/", "-"); + yes += string_replace(&new_buf, &temp_len, pos, "<", "<<"); break; case 27: - yes += string_replace(&new_buf, &temp_len, pos, "/", "*"); + yes += string_replace(&new_buf, &temp_len, pos, ">", ">>"); break; case 28: - yes += string_replace(&new_buf, &temp_len, pos, "/", "+"); + yes += string_replace(&new_buf, &temp_len, pos, "'", "\""); break; case 29: - yes += string_replace(&new_buf, &temp_len, pos, "/", "%"); - break; - case 30: - yes += string_replace(&new_buf, &temp_len, pos, "%", "-"); - break; - case 31: - yes += string_replace(&new_buf, &temp_len, pos, "%", "*"); - break; - case 32: - yes += string_replace(&new_buf, &temp_len, pos, "%", "/"); - break; - case 33: - yes += string_replace(&new_buf, &temp_len, pos, "%", "+"); - break; - case 34: - yes += string_replace(&new_buf, &temp_len, pos, " ", "|"); - break; - case 35: - yes += string_replace(&new_buf, &temp_len, pos, " ", "$"); - break; - case 36: - yes += string_replace(&new_buf, &temp_len, pos, "0", "1"); - break; - case 37: - yes += string_replace(&new_buf, &temp_len, pos, "1", "0"); - break; - case 38: - yes += string_replace(&new_buf, &temp_len, pos, " ", "`"); - break; - case 39: - yes += string_replace(&new_buf, &temp_len, pos, " ", "\""); - break; - case 40: - yes += string_replace(&new_buf, &temp_len, pos, ";", " "); - break; - case 41: - yes += string_replace(&new_buf, &temp_len, pos, "&&", "||"); - break; - case 42: - yes += string_replace(&new_buf, &temp_len, pos, "||", "&&"); - break; - case 43: - yes += string_replace(&new_buf, &temp_len, pos, "!", ""); - break; - case 44: - yes += string_replace(&new_buf, &temp_len, pos, "==", "="); - break; - case 45: - yes += string_replace(&new_buf, &temp_len, pos, "--", ""); - break; - case 46: - yes += string_replace(&new_buf, &temp_len, pos, "<<", "<"); - break; - case 47: - yes += string_replace(&new_buf, &temp_len, pos, ">>", ">"); - break; - case 48: - yes += string_replace(&new_buf, &temp_len, pos, "<", "<<"); - break; - case 49: - yes += string_replace(&new_buf, &temp_len, pos, ">", ">>"); - break; - case 50: yes += string_replace(&new_buf, &temp_len, pos, "\"", "'"); break; - case 51: - yes += string_replace(&new_buf, &temp_len, pos, "'", "\""); - break; - case 52: - yes += string_replace(&new_buf, &temp_len, pos, "(", "\""); - break; - case 53: /* Remove a semicolon delimited statement after a semicolon */ + case 30: /* Remove a semicolon delimited statement after a semicolon */ yes += delim_replace(&new_buf, &temp_len, pos, ";", ";", ";"); break; - case 54: /* Remove a semicolon delimited statement after a left curly + case 31: /* Remove a semicolon delimited statement after a left curly brace */ yes += delim_replace(&new_buf, &temp_len, pos, "}", ";", "}"); break; - case 55: /* Remove a curly brace construct */ + case 32: /* Remove a curly brace construct */ yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", ""); break; - case 56: /* Replace a curly brace construct with an empty one */ + case 33: /* Replace a curly brace construct with an empty one */ yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", "{}"); break; - case 57: + case 34: yes += delim_swap(&new_buf, &temp_len, pos, ";", ";", ";"); break; - case 58: + case 35: yes += delim_swap(&new_buf, &temp_len, pos, "}", ";", ";"); break; - case 59: /* Swap comma delimited things case 1 */ + case 36: /* Swap comma delimited things case 1 */ yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ")"); break; - case 60: /* Swap comma delimited things case 2 */ + case 37: /* Swap comma delimited things case 2 */ yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ","); break; - case 61: /* Swap comma delimited things case 3 */ + case 38: /* Swap comma delimited things case 3 */ yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ","); break; - case 62: /* Swap comma delimited things case 4 */ + case 39: /* Swap comma delimited things case 4 */ yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ")"); break; - case 63: /* Just delete a line */ + case 40: /* Just delete a line */ yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", ""); break; - case 64: /* Delete something like "const" case 1 */ + case 41: /* Delete something like "const" case 1 */ yes += delim_replace(&new_buf, &temp_len, pos, " ", " ", ""); break; - case 65: /* Delete something like "const" case 2 */ + case 42: /* Delete something like "const" case 2 */ yes += delim_replace(&new_buf, &temp_len, pos, "\n", " ", ""); break; - case 66: /* Delete something like "const" case 3 */ + case 43: /* Delete something like "const" case 3 */ yes += delim_replace(&new_buf, &temp_len, pos, "(", " ", ""); break; - case 67: /* Swap space delimited things case 1 */ + case 44: /* Swap space delimited things case 1 */ yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", " "); break; - case 68: /* Swap space delimited things case 2 */ + case 45: /* Swap space delimited things case 2 */ yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", ")"); break; - case 69: /* Swap space delimited things case 3 */ + case 46: /* Swap space delimited things case 3 */ yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", " "); break; - case 70: /* Swap space delimited things case 4 */ + case 47: /* Swap space delimited things case 4 */ yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", ")"); break; - case 71: /* Duplicate a single line of code */ + case 48: /* Duplicate a single line of code */ yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", NULL); break; - case 72: /* Duplicate a construct (most often, a non-nested for loop */ + case 49: /* Duplicate a construct (most often, a non-nested for loop */ yes += delim_replace(&new_buf, &temp_len, pos, "\n", "}", NULL); break; default: { - - for (u32 j = pos; j < temp_len; ++j) { - if (isdigit(new_buf[j])) { - - new_buf[temp_len] = 0; // should be safe thanks to the initial grow - - u8* endptr; - unsigned long long num = strtoull(new_buf +j, (char**)&endptr, 0); - - switch (rand_below(afl, 8)) { - case 0: - num = rand_below(afl, INT_MAX); - break; - case 1: - num = rand_next(afl); - break; - case 2: - num += 1 + rand_below(afl, 255); - break; - case 3: - num -= 1 + rand_below(afl, 255); - break; - case 4: - num *= 1 + rand_below(afl, 255); - break; - case 5: - num /= 1 + rand_below(afl, 255); - break; - case 6: - num /= 1 + rand_below(afl, 255); - break; - case 7: - num = ~num; - break; - } - - const char* fmt = "%llu"; - if (rand_below(afl, 5) == 0) // add - sign with 1/5 probability - fmt = "-%llu"; - - size_t num_len = snprintf(NULL, 0, fmt, num); - size_t old_len = endptr - (new_buf +j); - if (num_len < old_len) { - memmove(new_buf +j +num_len, new_buf +j +old_len, temp_len - (j + old_len)); - snprintf(new_buf +j, num_len, fmt, num); - temp_len -= old_len - num_len; - } else if (num_len == old_len) { - snprintf(new_buf +j, num_len, fmt, num); - } else { - new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + (num_len - old_len) + AFL_TXT_STRING_MAX_MUTATIONS +1); - memmove(new_buf +j +num_len, new_buf +j +old_len, temp_len - (j + old_len)); - snprintf(new_buf +j, num_len, fmt, num); - temp_len += num_len - old_len; + + /* 10% is transforming ascii numbers */ + + if (choice < 60) { + + for (u32 j = pos; j < temp_len; ++j) { + + if (isdigit(new_buf[j])) { + + new_buf[temp_len] = + 0; // should be safe thanks to the initial grow + + u8 * endptr; + unsigned long long num = + strtoull(new_buf + j, (char **)&endptr, 0); + + switch (rand_below(afl, 8)) { + + case 0: + num = rand_below(afl, INT_MAX); + break; + case 1: + num = rand_next(afl); + break; + case 2: + num += 1 + rand_below(afl, 255); + break; + case 3: + num -= 1 + rand_below(afl, 255); + break; + case 4: + num *= 1 + rand_below(afl, 255); + break; + case 5: + num /= 1 + rand_below(afl, 255); + break; + case 6: + num /= 1 + rand_below(afl, 255); + break; + case 7: + num = ~num; + break; + + } + + const char *fmt = "%llu"; + if (rand_below(afl, 5) == 0) // add - sign with 1/5 probability + fmt = "-%llu"; + + size_t num_len = snprintf(NULL, 0, fmt, num); + size_t old_len = endptr - (new_buf + j); + if (num_len < old_len) { + + memmove(new_buf + j + num_len, new_buf + j + old_len, + temp_len - (j + old_len)); + snprintf(new_buf + j, num_len, fmt, num); + temp_len -= old_len - num_len; + + } else if (num_len == old_len) { + + snprintf(new_buf + j, num_len, fmt, num); + + } else { + + new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), + temp_len + (num_len - old_len) + + AFL_TXT_STRING_MAX_MUTATIONS + 1); + memmove(new_buf + j + num_len, new_buf + j + old_len, + temp_len - (j + old_len)); + snprintf(new_buf + j, num_len, fmt, num); + temp_len += num_len - old_len; + + } + + yes += 1; + break; + } - yes += 1; - break; - } + + } else if (choice < 90) { + + /* 30% is special character transform */ + + fromc[0] = text_mutation_special_chars[rand_below( + afl, sizeof(text_mutation_special_chars))]; + + do { + + toc[0] = text_mutation_special_chars[rand_below( + afl, sizeof(text_mutation_special_chars))]; + + } while (toc[0] == fromc[0]); + + yes += string_replace(&new_buf, &temp_len, pos, fromc, toc); + break; + + } else { + + /* 10% is random text character transform */ + + u32 iter, cnt, loc, prev_loc = temp_len; + if (temp_len > 32) { + + cnt = 1 + rand_below(afl, 5); + + } else { + + cnt = rand_below(afl, 2); + + } + + for (iter = 0; iter <= cnt; iter++) { + + while ((loc = rand_below(afl, temp_len)) == prev_loc) + ; + new_buf[loc] = 32 + rand_below(afl, 'z' - ' ' + 1); + prev_loc = loc; + + } + } - + } } - + } if (yes == 0 || temp_len <= 0) { return 0; } @@ -871,7 +880,7 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); *out_buf = new_buf; *orig_temp_len = temp_len; - + return 1; } diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index de3adb2d..57e60c3d 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -264,49 +264,53 @@ 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; + + 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; +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 @@ -328,49 +332,51 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u32 its_len = len - idx; // *status = 0; - u8 *endptr; - u8 use_num = 0, use_unum = 0; + u8 * endptr; + u8 use_num = 0, use_unum = 0; unsigned long long unum; - long long num; + long long num; if (afl->queue_cur->is_ascii) { - + endptr = buf_8; - num = strntoll(buf_8, len - idx, (char**)&endptr, 0); + 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; + + 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); + + 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); - + + 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); + + 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); - + + 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) { @@ -382,7 +388,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, *buf_64 = pattern; } - + // reverse encoding if (do_reverse && *status != 1) { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index f68a79e8..66280ed1 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -300,6 +300,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { 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)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 553300e9..c014035e 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1275,7 +1275,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->expand_havoc = 2; break; case 2: - //afl->cycle_schedules = 1; + // afl->cycle_schedules = 1; afl->expand_havoc = 3; break; case 3: -- cgit 1.4.1 From ecb0601bc1e90b3379030644556a0d8d51182c0d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 24 Jul 2020 13:42:39 +0200 Subject: massage chances --- src/afl-fuzz-one.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index dc19150d..98d9875e 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -746,9 +746,9 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { break; default: { - /* 10% is transforming ascii numbers */ + /* 5% is transforming ascii numbers */ - if (choice < 60) { + if (choice < 55) { for (u32 j = pos; j < temp_len; ++j) { @@ -826,7 +826,7 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { } - } else if (choice < 90) { + } else if (choice < 85) { /* 30% is special character transform */ @@ -845,7 +845,7 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { } else { - /* 10% is random text character transform */ + /* 15% is random text character transform */ u32 iter, cnt, loc, prev_loc = temp_len; if (temp_len > 32) { -- cgit 1.4.1 From ff107714f1af1bd908a35ce54701da1eca8ce25d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 26 Jul 2020 15:00:44 +0200 Subject: remove test input mutation in havoc --- src/afl-fuzz-one.c | 153 ++++++++++++++++++++++++++++------------------------- 1 file changed, 80 insertions(+), 73 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 98d9875e..f8680100 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -27,9 +27,9 @@ #include #include -static u8 *strnstr(const u8 *s, const u8 *find, size_t slen); +/* static u8 *strnstr(const u8 *s, const u8 *find, size_t slen); static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from, - u8 *to); + u8 *to); */ /* MOpt */ @@ -370,6 +370,7 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) { #define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size +#if 0 /* search a string */ static u8 *strnstr(const u8 *s, const u8 *find, size_t slen) { @@ -591,7 +592,7 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { switch (choice) { - /* 50% -> fixed replacements */ + /* 50% -> fixed replacements */ case 0: /* Semantic statement deletion */ yes += string_replace(&new_buf, &temp_len, pos, "\n", "#"); @@ -885,6 +886,8 @@ static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { } +#endif /* if 0 */ + /* 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. */ @@ -2384,8 +2387,8 @@ havoc_stage: /* 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) + - (afl->queue_cur->is_ascii ? AFL_TXT_BIAS : 0); + r_max = 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0); + /* + (afl->queue_cur->is_ascii ? AFL_TXT_BIAS : 0); */ } else { @@ -2435,7 +2438,7 @@ havoc_stage: } - retry_havoc: + // retry_havoc: switch ((r = rand_below(afl, r_max))) { @@ -2818,116 +2821,120 @@ havoc_stage: } - } else + } else { - switch (r) { + /* + switch (r) { - case 15: // fall through - case 17: { + case 15: // fall through + case 16: + case 17: {*/ - /* Overwrite bytes with a randomly selected chunk from another - testcase or insert that chunk. */ + /* Overwrite bytes with a randomly selected chunk from another + testcase or insert that chunk. */ - if (afl->queued_paths < 2) break; + if (afl->queued_paths < 4) break; - /* Pick a random queue entry and seek to it. */ + /* Pick a random queue entry and seek to it. */ - u32 tid; - do - tid = rand_below(afl, afl->queued_paths); - while (tid == afl->current_entry); + u32 tid; + do + tid = rand_below(afl, afl->queued_paths); + while (tid == afl->current_entry); - struct queue_entry *target = afl->queue_buf[tid]; + struct queue_entry *target = afl->queue_buf[tid]; - /* Make sure that the target has a reasonable length. */ + /* Make sure that the target has a reasonable length. */ - while (target && (target->len < 2 || target == afl->queue_cur)) - target = target->next; + while (target && (target->len < 2 || target == afl->queue_cur)) + target = target->next; - if (!target) break; + if (!target) break; - /* Read the testcase into a new buffer. */ + /* Read the testcase into a new buffer. */ - fd = open(target->fname, O_RDONLY); + fd = open(target->fname, O_RDONLY); - if (unlikely(fd < 0)) { + if (unlikely(fd < 0)) { - PFATAL("Unable to open '%s'", target->fname); + PFATAL("Unable to open '%s'", target->fname); - } + } - u32 new_len = target->len; - u8 *new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len); + 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); + ck_read(fd, new_buf, new_len, target->fname); - close(fd); + close(fd); - u8 overwrite = 0; - if (temp_len >= 2 && rand_below(afl, 2)) - overwrite = 1; - else if (temp_len + HAVOC_BLK_XL >= MAX_FILE) { + 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 (temp_len >= 2) + overwrite = 1; + else + break; - } + } - if (overwrite) { + if (overwrite) { - u32 copy_from, copy_to, copy_len; + 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_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); + 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); + memmove(out_buf + copy_to, new_buf + copy_from, copy_len); - } else { + } else { - u32 clone_from, clone_to, clone_len; + 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_len = choose_block_len(afl, new_len); + clone_from = rand_below(afl, new_len - clone_len + 1); - clone_to = rand_below(afl, temp_len); + clone_to = rand_below(afl, temp_len); - u8 *temp_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), - temp_len + clone_len); + u8 *temp_buf = + ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len); - /* Head */ + /* Head */ - memcpy(temp_buf, out_buf, clone_to); + memcpy(temp_buf, out_buf, clone_to); - /* Inserted part */ + /* Inserted part */ - memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); + 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); + /* 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; + swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); + out_buf = temp_buf; + temp_len += clone_len; - } + } - break; + break; - } + } + + /* default: - default: + // perform ascii mutations + if (text_mutation(afl, &out_buf, &temp_len) == 0) + goto retry_havoc; - // perform ascii mutations - if (text_mutation(afl, &out_buf, &temp_len) == 0) - goto retry_havoc; + } // end default: switch(r) - } // end default: switch(r) + */ } -- cgit 1.4.1 From 6cfa27d78ab9fb178a1678bdcc36cb62a555f7a4 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 29 Jul 2020 11:47:32 +0200 Subject: remove dead code, code-format --- docs/Changelog.md | 4 +- src/afl-fuzz-one.c | 532 +-------------------------------------------------- src/afl-fuzz-stats.c | 134 ++++++------- 3 files changed, 71 insertions(+), 599 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/docs/Changelog.md b/docs/Changelog.md index cadfcb04..d3d5063b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -14,6 +14,8 @@ sending a mail to . - added -F option to allow -M main fuzzers to sync to foreign fuzzers, e.g. honggfuzz or libfuzzer - eliminated CPU affinity race condition for -S/-M runs + - expanded havoc mode added, on no cycle finds add extra splicing and + MOpt into the mix - llvm_mode: - now supports llvm 12! - fixes for laf-intel float splitting (thanks to mark-griffin for @@ -21,7 +23,7 @@ sending a mail to . - LTO: autodictionary mode is a default - LTO: instrim instrumentation disabled, only classic support used as it is always better - - added honggfuzz mangle as a custom mutator in custom_mutators/honggfuzz :) + - added honggfuzz mangle as a custom mutator in custom_mutators/honggfuzz - added afl-frida gum solution to examples/afl_frida (mostly imported from https://github.com/meme/hotwax/) - small fixes to afl-plot, afl-whatsup and man page creation diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index f8680100..a42bb0fc 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -27,10 +27,6 @@ #include #include -/* static u8 *strnstr(const u8 *s, const u8 *find, size_t slen); -static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from, - u8 *to); */ - /* MOpt */ static int select_algorithm(afl_state_t *afl) { @@ -370,524 +366,6 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) { #define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size -#if 0 -/* search a string */ - -static u8 *strnstr(const u8 *s, const u8 *find, size_t slen) { - - char c, sc; - size_t len; - - if ((c = *find++) != '\0') { - - len = strlen(find); - do { - - do { - - if (slen-- < 1 || (sc = *s++) == '\0') return (NULL); - - } while (sc != c); - - if (len > slen) return (NULL); - - } while (strncmp(s, find, len) != 0); - - s--; - - } - - return ((u8 *)s); - -} - -/* replace between deliminators, if rep == NULL, then we will duplicate the - * target */ - -static u32 delim_replace(u8 **out_buf, s32 *temp_len, size_t pos, - const u8 *ldelim, const u8 *rdelim, u8 *rep) { - - u8 *end_buf = *out_buf + *temp_len; - u8 *ldelim_start = strnstr(*out_buf + pos, ldelim, *temp_len - pos); - - if (ldelim_start != NULL) { - - u32 max = (end_buf - ldelim_start - 1 > AFL_TXT_STRING_MAX_LEN - ? AFL_TXT_STRING_MAX_LEN - : end_buf - ldelim_start - 1); - - if (max > 0) { - - u8 *rdelim_end = strnstr(ldelim_start + 1, rdelim, max); - - if (rdelim_end != NULL) { - - u32 rep_len, delim_space_len = rdelim_end - ldelim_start - 1, xtra = 0; - - if (rep != NULL) { - - rep_len = (u32)strlen(rep); - - } else { // NULL? then we copy the value in between the delimiters - - rep_len = delim_space_len; - delim_space_len = 0; - rep = ldelim_start + 1; - xtra = rep_len; - - } - - if (rep_len != delim_space_len) { - - memmove(ldelim_start + rep_len + xtra + 1, rdelim_end, - *temp_len - (rdelim_end - *out_buf)); - - } - - memcpy(ldelim_start + 1, rep, rep_len); - *temp_len = (*temp_len - delim_space_len + rep_len); - - return 1; - - } - - } - - } - - return 0; - -} - -static u32 delim_swap(u8 **out_buf, s32 *temp_len, size_t pos, const u8 *ldelim, - const u8 *mdelim, const u8 *rdelim) { - - u8 *out_buf_end = *out_buf + *temp_len; - u32 max = (*temp_len - pos > AFL_TXT_STRING_MAX_LEN ? AFL_TXT_STRING_MAX_LEN - : *temp_len - pos); - u8 *ldelim_start = strnstr(*out_buf + pos, ldelim, max); - - if (ldelim_start != NULL) { - - max = (out_buf_end - ldelim_start - 1 > AFL_TXT_STRING_MAX_LEN - ? AFL_TXT_STRING_MAX_LEN - : out_buf_end - ldelim_start - 1); - if (max > 1) { - - u8 *mdelim_pos = strnstr(ldelim_start + 1, mdelim, max); - - if (mdelim_pos != NULL) { - - max = (out_buf_end - mdelim_pos - 1 > AFL_TXT_STRING_MAX_LEN - ? AFL_TXT_STRING_MAX_LEN - : out_buf_end - mdelim_pos - 1); - if (max > 0) { - - u8 *rdelim_end = strnstr(mdelim + 1, rdelim, max); - - if (rdelim_end != NULL) { - - u32 first_len = mdelim_pos - ldelim_start - 1; - u32 second_len = rdelim_end - mdelim_pos - 1; - u8 scratch[AFL_TXT_STRING_MAX_LEN]; - - memcpy(scratch, ldelim_start + 1, first_len); - - if (first_len != second_len) { - - memmove(ldelim_start + second_len + 1, mdelim_pos, - out_buf_end - mdelim_pos); - - } - - memcpy(ldelim_start + 1, mdelim_pos + 1, second_len); - - if (first_len != second_len) { - - memmove(mdelim_pos + first_len + 1, rdelim_end, - out_buf_end - rdelim_end); - - } - - memcpy(mdelim_pos + 1, scratch, first_len); - - return 1; - - } - - } - - } - - } - - } - - return 0; - -} - -/* replace a string */ - -static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from, - u8 *to) { - - u8 *start = strnstr(*out_buf + pos, from, *temp_len - pos); - - if (start) { - - u32 from_len = strlen(from); - u32 to_len = strlen(to); - - if (from_len != to_len) { - - memmove(start + to_len, start + from_len, - *temp_len - from_len - (start - *out_buf)); - - } - - memcpy(start, to, to_len); - *temp_len = (*temp_len - from_len + to_len); - - return 1; - - } - - return 0; - -} - -/* Returns 1 if a mutant was generated and placed in out_buf, 0 if none - * generated. */ - -static const uint8_t text_mutation_special_chars[] = { - - '\t', '\n', '\r', ' ', '!', '"', '$', '%', '&', '\'', '(', ')', '*', - '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', - '\\', ']', '^', '_', '`', '{', '|', '}', '~', ' ' // space is here twice - -}; - -static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) { - - if (*orig_temp_len < AFL_TXT_MIN_LEN) { return 0; } - - s32 temp_len; - u32 pos, yes = 0, - mutations = rand_below(afl, AFL_TXT_STRING_MAX_MUTATIONS) + 16; - u8 *new_buf = - ck_maybe_grow(BUF_PARAMS(out_scratch), - *orig_temp_len + AFL_TXT_STRING_MAX_MUTATIONS + 16); - u8 fromc[2] = {0, 0}, toc[2] = {0, 0}; - temp_len = *orig_temp_len; - memcpy(new_buf, *out_buf, temp_len); - new_buf[temp_len] = 0; - - for (u32 i = 0; i < mutations; i++) { - - if (temp_len < AFL_TXT_MIN_LEN) { return 0; } - - pos = rand_below(afl, temp_len - 1); - int choice = rand_below(afl, 100); - - switch (choice) { - - /* 50% -> fixed replacements */ - - case 0: /* Semantic statement deletion */ - yes += string_replace(&new_buf, &temp_len, pos, "\n", "#"); - break; - case 1: - yes += string_replace(&new_buf, &temp_len, pos, "(", "(!"); - break; - case 2: - yes += string_replace(&new_buf, &temp_len, pos, "==", "!="); - break; - case 3: - yes += string_replace(&new_buf, &temp_len, pos, "!=", "=="); - break; - case 4: - yes += string_replace(&new_buf, &temp_len, pos, "==", "<"); - break; - case 5: - yes += string_replace(&new_buf, &temp_len, pos, "<", "=="); - break; - case 6: - yes += string_replace(&new_buf, &temp_len, pos, "==", ">"); - break; - case 7: - yes += string_replace(&new_buf, &temp_len, pos, ">", "=="); - break; - case 8: - yes += string_replace(&new_buf, &temp_len, pos, "=", "<"); - break; - case 9: - yes += string_replace(&new_buf, &temp_len, pos, "=", ">"); - break; - case 10: - yes += string_replace(&new_buf, &temp_len, pos, "<", ">"); - break; - case 11: - yes += string_replace(&new_buf, &temp_len, pos, ">", "<"); - break; - case 12: - yes += string_replace(&new_buf, &temp_len, pos, "++", "--"); - break; - case 13: - yes += string_replace(&new_buf, &temp_len, pos, "--", "++"); - break; - case 14: - yes += string_replace(&new_buf, &temp_len, pos, "+", "-"); - break; - case 15: - yes += string_replace(&new_buf, &temp_len, pos, "-", "+"); - break; - case 16: - yes += string_replace(&new_buf, &temp_len, pos, "0", "1"); - break; - case 17: - yes += string_replace(&new_buf, &temp_len, pos, "1", "0"); - break; - case 18: - yes += string_replace(&new_buf, &temp_len, pos, "&&", "||"); - break; - case 19: - yes += string_replace(&new_buf, &temp_len, pos, "||", "&&"); - break; - case 20: - yes += string_replace(&new_buf, &temp_len, pos, "!", ""); - break; - case 21: - yes += string_replace(&new_buf, &temp_len, pos, "==", "="); - break; - case 22: - yes += string_replace(&new_buf, &temp_len, pos, "=", "=="); - break; - case 23: - yes += string_replace(&new_buf, &temp_len, pos, "--", ""); - break; - case 24: - yes += string_replace(&new_buf, &temp_len, pos, "<<", "<"); - break; - case 25: - yes += string_replace(&new_buf, &temp_len, pos, ">>", ">"); - break; - case 26: - yes += string_replace(&new_buf, &temp_len, pos, "<", "<<"); - break; - case 27: - yes += string_replace(&new_buf, &temp_len, pos, ">", ">>"); - break; - case 28: - yes += string_replace(&new_buf, &temp_len, pos, "'", "\""); - break; - case 29: - yes += string_replace(&new_buf, &temp_len, pos, "\"", "'"); - break; - case 30: /* Remove a semicolon delimited statement after a semicolon */ - yes += delim_replace(&new_buf, &temp_len, pos, ";", ";", ";"); - break; - case 31: /* Remove a semicolon delimited statement after a left curly - brace */ - yes += delim_replace(&new_buf, &temp_len, pos, "}", ";", "}"); - break; - case 32: /* Remove a curly brace construct */ - yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", ""); - break; - case 33: /* Replace a curly brace construct with an empty one */ - yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", "{}"); - break; - case 34: - yes += delim_swap(&new_buf, &temp_len, pos, ";", ";", ";"); - break; - case 35: - yes += delim_swap(&new_buf, &temp_len, pos, "}", ";", ";"); - break; - case 36: /* Swap comma delimited things case 1 */ - yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ")"); - break; - case 37: /* Swap comma delimited things case 2 */ - yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ","); - break; - case 38: /* Swap comma delimited things case 3 */ - yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ","); - break; - case 39: /* Swap comma delimited things case 4 */ - yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ")"); - break; - case 40: /* Just delete a line */ - yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", ""); - break; - case 41: /* Delete something like "const" case 1 */ - yes += delim_replace(&new_buf, &temp_len, pos, " ", " ", ""); - break; - case 42: /* Delete something like "const" case 2 */ - yes += delim_replace(&new_buf, &temp_len, pos, "\n", " ", ""); - break; - case 43: /* Delete something like "const" case 3 */ - yes += delim_replace(&new_buf, &temp_len, pos, "(", " ", ""); - break; - case 44: /* Swap space delimited things case 1 */ - yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", " "); - break; - case 45: /* Swap space delimited things case 2 */ - yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", ")"); - break; - case 46: /* Swap space delimited things case 3 */ - yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", " "); - break; - case 47: /* Swap space delimited things case 4 */ - yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", ")"); - break; - case 48: /* Duplicate a single line of code */ - yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", NULL); - break; - case 49: /* Duplicate a construct (most often, a non-nested for loop */ - yes += delim_replace(&new_buf, &temp_len, pos, "\n", "}", NULL); - break; - default: { - - /* 5% is transforming ascii numbers */ - - if (choice < 55) { - - for (u32 j = pos; j < temp_len; ++j) { - - if (isdigit(new_buf[j])) { - - new_buf[temp_len] = - 0; // should be safe thanks to the initial grow - - u8 * endptr; - unsigned long long num = - strtoull(new_buf + j, (char **)&endptr, 0); - - switch (rand_below(afl, 8)) { - - case 0: - num = rand_below(afl, INT_MAX); - break; - case 1: - num = rand_next(afl); - break; - case 2: - num += 1 + rand_below(afl, 255); - break; - case 3: - num -= 1 + rand_below(afl, 255); - break; - case 4: - num *= 1 + rand_below(afl, 255); - break; - case 5: - num /= 1 + rand_below(afl, 255); - break; - case 6: - num /= 1 + rand_below(afl, 255); - break; - case 7: - num = ~num; - break; - - } - - const char *fmt = "%llu"; - if (rand_below(afl, 5) == 0) // add - sign with 1/5 probability - fmt = "-%llu"; - - size_t num_len = snprintf(NULL, 0, fmt, num); - size_t old_len = endptr - (new_buf + j); - if (num_len < old_len) { - - memmove(new_buf + j + num_len, new_buf + j + old_len, - temp_len - (j + old_len)); - snprintf(new_buf + j, num_len, fmt, num); - temp_len -= old_len - num_len; - - } else if (num_len == old_len) { - - snprintf(new_buf + j, num_len, fmt, num); - - } else { - - new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), - temp_len + (num_len - old_len) + - AFL_TXT_STRING_MAX_MUTATIONS + 1); - memmove(new_buf + j + num_len, new_buf + j + old_len, - temp_len - (j + old_len)); - snprintf(new_buf + j, num_len, fmt, num); - temp_len += num_len - old_len; - - } - - yes += 1; - break; - - } - - } - - } else if (choice < 85) { - - /* 30% is special character transform */ - - fromc[0] = text_mutation_special_chars[rand_below( - afl, sizeof(text_mutation_special_chars))]; - - do { - - toc[0] = text_mutation_special_chars[rand_below( - afl, sizeof(text_mutation_special_chars))]; - - } while (toc[0] == fromc[0]); - - yes += string_replace(&new_buf, &temp_len, pos, fromc, toc); - break; - - } else { - - /* 15% is random text character transform */ - - u32 iter, cnt, loc, prev_loc = temp_len; - if (temp_len > 32) { - - cnt = 1 + rand_below(afl, 5); - - } else { - - cnt = rand_below(afl, 2); - - } - - for (iter = 0; iter <= cnt; iter++) { - - while ((loc = rand_below(afl, temp_len)) == prev_loc) - ; - new_buf[loc] = 32 + rand_below(afl, 'z' - ' ' + 1); - prev_loc = loc; - - } - - } - - } - - } - - } - - if (yes == 0 || temp_len <= 0) { return 0; } - - swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); - *out_buf = new_buf; - *orig_temp_len = temp_len; - - return 1; - -} - -#endif /* if 0 */ - /* 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. */ @@ -2926,15 +2404,7 @@ havoc_stage: } - /* default: - - // perform ascii mutations - if (text_mutation(afl, &out_buf, &temp_len) == 0) - goto retry_havoc; - - } // end default: switch(r) - - */ + // end of default: } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 9b16c226..7b30b5ea 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -82,60 +82,59 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; } #endif - fprintf( - f, - "start_time : %llu\n" - "last_update : %llu\n" - "run_time : %llu\n" - "fuzzer_pid : %u\n" - "cycles_done : %llu\n" - "cycles_wo_finds : %llu\n" - "execs_done : %llu\n" - "execs_per_sec : %0.02f\n" - "execs_ps_last_min : %0.02f\n" - "paths_total : %u\n" - "paths_favored : %u\n" - "paths_found : %u\n" - "paths_imported : %u\n" - "max_depth : %u\n" - "cur_path : %u\n" /* Must match find_start_position() */ - "pending_favs : %u\n" - "pending_total : %u\n" - "variable_paths : %u\n" - "stability : %0.02f%%\n" - "bitmap_cvg : %0.02f%%\n" - "unique_crashes : %llu\n" - "unique_hangs : %llu\n" - "last_path : %llu\n" - "last_crash : %llu\n" - "last_hang : %llu\n" - "execs_since_crash : %llu\n" - "exec_timeout : %u\n" - "slowest_exec_ms : %u\n" - "peak_rss_mb : %lu\n" - "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" - "target_mode : %s%s%s%s%s%s%s%s%s\n" - "command_line : %s\n", - afl->start_time / 1000, cur_time / 1000, - (cur_time - afl->start_time) / 1000, (u32)getpid(), - afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds, - afl->fsrv.total_execs, - afl->fsrv.total_execs / - ((double)(get_cur_time() - afl->start_time) / 1000), - afl->last_avg_execs_saved, - afl->queued_paths, afl->queued_favored, afl->queued_discovered, - afl->queued_imported, afl->max_depth, afl->current_entry, - afl->pending_favored, afl->pending_not_fuzzed, afl->queued_variable, - stability, bitmap_cvg, afl->unique_crashes, afl->unique_hangs, - afl->last_path_time / 1000, afl->last_crash_time / 1000, - afl->last_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs, - afl->fsrv.exec_tmout, afl->slowest_exec_ms, + fprintf(f, + "start_time : %llu\n" + "last_update : %llu\n" + "run_time : %llu\n" + "fuzzer_pid : %u\n" + "cycles_done : %llu\n" + "cycles_wo_finds : %llu\n" + "execs_done : %llu\n" + "execs_per_sec : %0.02f\n" + "execs_ps_last_min : %0.02f\n" + "paths_total : %u\n" + "paths_favored : %u\n" + "paths_found : %u\n" + "paths_imported : %u\n" + "max_depth : %u\n" + "cur_path : %u\n" /* Must match find_start_position() */ + "pending_favs : %u\n" + "pending_total : %u\n" + "variable_paths : %u\n" + "stability : %0.02f%%\n" + "bitmap_cvg : %0.02f%%\n" + "unique_crashes : %llu\n" + "unique_hangs : %llu\n" + "last_path : %llu\n" + "last_crash : %llu\n" + "last_hang : %llu\n" + "execs_since_crash : %llu\n" + "exec_timeout : %u\n" + "slowest_exec_ms : %u\n" + "peak_rss_mb : %lu\n" + "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" + "target_mode : %s%s%s%s%s%s%s%s%s\n" + "command_line : %s\n", + afl->start_time / 1000, cur_time / 1000, + (cur_time - afl->start_time) / 1000, (u32)getpid(), + afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds, + afl->fsrv.total_execs, + afl->fsrv.total_execs / + ((double)(get_cur_time() - afl->start_time) / 1000), + afl->last_avg_execs_saved, afl->queued_paths, afl->queued_favored, + afl->queued_discovered, afl->queued_imported, afl->max_depth, + afl->current_entry, afl->pending_favored, afl->pending_not_fuzzed, + afl->queued_variable, stability, bitmap_cvg, afl->unique_crashes, + afl->unique_hangs, afl->last_path_time / 1000, + afl->last_crash_time / 1000, afl->last_hang_time / 1000, + afl->fsrv.total_execs - afl->last_crash_execs, afl->fsrv.exec_tmout, + afl->slowest_exec_ms, #ifndef __HAIKU__ #ifdef __APPLE__ (unsigned long int)(rus.ru_maxrss >> 20), @@ -150,19 +149,20 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, #else -1, #endif - 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 " : "", - afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "", - afl->persistent_mode ? "persistent " : "", - afl->shmem_testcase_mode ? "shmem_testcase " : "", - afl->deferred_mode ? "deferred " : "", - (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->non_instrumented_mode || - afl->no_forkserver || afl->crash_mode || afl->persistent_mode || - afl->deferred_mode) - ? "" - : "default", - afl->orig_cmdline); + 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 " : "", + afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "", + afl->persistent_mode ? "persistent " : "", + afl->shmem_testcase_mode ? "shmem_testcase " : "", + afl->deferred_mode ? "deferred " : "", + (afl->unicorn_mode || afl->fsrv.qemu_mode || + afl->non_instrumented_mode || afl->no_forkserver || + afl->crash_mode || afl->persistent_mode || afl->deferred_mode) + ? "" + : "default", + afl->orig_cmdline); /* ignore errors */ if (afl->debug) { -- cgit 1.4.1 From f32811922ec8f363bdf46a019d984058dbeb06bf Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 29 Jul 2020 11:56:38 +0200 Subject: minor opt --- src/afl-fuzz-one.c | 3 --- src/afl-fuzz-queue.c | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/afl-fuzz-one.c') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index a42bb0fc..1f0bf30e 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1866,7 +1866,6 @@ havoc_stage: cycle without finds happened */ r_max = 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0); - /* + (afl->queue_cur->is_ascii ? AFL_TXT_BIAS : 0); */ } else { @@ -1916,8 +1915,6 @@ havoc_stage: } - // retry_havoc: - switch ((r = rand_below(afl, r_max))) { case 0: diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 56073b0a..38e95ac8 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -268,7 +268,8 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { } - q->is_ascii = check_if_text(q); + /* only redqueen currently uses is_ascii */ + if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q); } -- cgit 1.4.1