diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/afl-cc.c | 17 | ||||
-rw-r--r-- | src/afl-common.c | 137 | ||||
-rw-r--r-- | src/afl-fuzz-init.c | 48 | ||||
-rw-r--r-- | src/afl-fuzz-redqueen.c | 114 | ||||
-rw-r--r-- | src/afl-fuzz-run.c | 2 | ||||
-rw-r--r-- | src/afl-fuzz-state.c | 2 | ||||
-rw-r--r-- | src/afl-fuzz-stats.c | 36 | ||||
-rw-r--r-- | src/afl-fuzz.c | 113 |
8 files changed, 355 insertions, 114 deletions
diff --git a/src/afl-cc.c b/src/afl-cc.c index d41f79a2..c3910e6d 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1421,6 +1421,14 @@ int main(int argc, char **argv, char **envp) { } + if (instrument_opt_mode && instrument_mode == INSTRUMENT_DEFAULT && + (compiler_mode == LLVM || compiler_mode == UNSET)) { + + instrument_mode = INSTRUMENT_CLASSIC; + compiler_mode = LLVM; + + } + if (!compiler_mode) { // lto is not a default because outside of afl-cc RANLIB and AR have to @@ -1699,7 +1707,10 @@ int main(int argc, char **argv, char **envp) { "Do not be overwhelmed :) afl-cc uses good defaults if no options are " "selected.\n" "Read the documentation for FEATURES though, all are good but few are " - "defaults.\n\n"); + "defaults.\n" + "Recommended is afl-clang-lto with AFL_LLVM_CMPLOG or afl-clang-fast " + "with\n" + "AFL_LLVM_CMPLOG and AFL_LLVM_DICT2FILE.\n\n"); exit(1); @@ -1791,8 +1802,8 @@ int main(int argc, char **argv, char **envp) { if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC && instrument_mode != INSTRUMENT_CFG) FATAL( - "CTX and NGRAM instrumentation options can only be used with CFG " - "(recommended) and CLASSIC instrumentation modes!"); + "CTX and NGRAM instrumentation options can only be used with LLVM and " + "CFG or CLASSIC instrumentation modes!"); if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO")) FATAL( diff --git a/src/afl-common.c b/src/afl-common.c index 589aac71..078ffb9d 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -518,6 +518,141 @@ int parse_afl_kill_signal_env(u8 *afl_kill_signal_env, int default_signal) { } +static inline unsigned int helper_min3(unsigned int a, unsigned int b, + unsigned int c) { + + return a < b ? (a < c ? a : c) : (b < c ? b : c); + +} + +// from +// https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C +static int string_distance_levenshtein(char *s1, char *s2) { + + unsigned int s1len, s2len, x, y, lastdiag, olddiag; + s1len = strlen(s1); + s2len = strlen(s2); + unsigned int column[s1len + 1]; + column[s1len] = 1; + + for (y = 1; y <= s1len; y++) + column[y] = y; + for (x = 1; x <= s2len; x++) { + + column[0] = x; + for (y = 1, lastdiag = x - 1; y <= s1len; y++) { + + olddiag = column[y]; + column[y] = helper_min3(column[y] + 1, column[y - 1] + 1, + lastdiag + (s1[y - 1] == s2[x - 1] ? 0 : 1)); + lastdiag = olddiag; + + } + + } + + return column[s1len]; + +} + +#define ENV_SIMILARITY_TRESHOLD 3 + +void print_suggested_envs(char *mispelled_env) { + + size_t env_name_len = + strcspn(mispelled_env, "=") - 4; // remove the AFL_prefix + char *env_name = ck_alloc(env_name_len + 1); + memcpy(env_name, mispelled_env + 4, env_name_len); + + char *seen = ck_alloc(sizeof(afl_environment_variables) / sizeof(char *)); + int found = 0; + + int j; + for (j = 0; afl_environment_variables[j] != NULL; ++j) { + + char *afl_env = afl_environment_variables[j] + 4; + int distance = string_distance_levenshtein(afl_env, env_name); + if (distance < ENV_SIMILARITY_TRESHOLD && seen[j] == 0) { + + SAYF("Did you mean %s?\n", afl_environment_variables[j]); + seen[j] = 1; + found = 1; + + } + + } + + if (found) goto cleanup; + + for (j = 0; afl_environment_variables[j] != NULL; ++j) { + + char * afl_env = afl_environment_variables[j] + 4; + size_t afl_env_len = strlen(afl_env); + char * reduced = ck_alloc(afl_env_len + 1); + + size_t start = 0; + while (start < afl_env_len) { + + size_t end = start + strcspn(afl_env + start, "_") + 1; + memcpy(reduced, afl_env, start); + if (end < afl_env_len) + memcpy(reduced + start, afl_env + end, afl_env_len - end); + reduced[afl_env_len - end + start] = 0; + + int distance = string_distance_levenshtein(reduced, env_name); + if (distance < ENV_SIMILARITY_TRESHOLD && seen[j] == 0) { + + SAYF("Did you mean %s?\n", afl_environment_variables[j]); + seen[j] = 1; + found = 1; + + } + + start = end; + + }; + + ck_free(reduced); + + } + + if (found) goto cleanup; + + char * reduced = ck_alloc(env_name_len + 1); + size_t start = 0; + while (start < env_name_len) { + + size_t end = start + strcspn(env_name + start, "_") + 1; + memcpy(reduced, env_name, start); + if (end < env_name_len) + memcpy(reduced + start, env_name + end, env_name_len - end); + reduced[env_name_len - end + start] = 0; + + for (j = 0; afl_environment_variables[j] != NULL; ++j) { + + int distance = string_distance_levenshtein( + afl_environment_variables[j] + 4, reduced); + if (distance < ENV_SIMILARITY_TRESHOLD && seen[j] == 0) { + + SAYF("Did you mean %s?\n", afl_environment_variables[j]); + seen[j] = 1; + + } + + } + + start = end; + + }; + + ck_free(reduced); + +cleanup: + ck_free(env_name); + ck_free(seen); + +} + void check_environment_vars(char **envp) { if (be_quiet) { return; } @@ -587,6 +722,8 @@ void check_environment_vars(char **envp) { WARNF("Mistyped AFL environment variable: %s", env); issue_detected = 1; + print_suggested_envs(env); + } } diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 702e732d..3dbc4c65 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -882,32 +882,23 @@ void perform_dry_run(afl_state_t *afl) { if (afl->timeout_given) { - /* The -t nn+ syntax in the command line sets afl->timeout_given to - '2' and instructs afl-fuzz to tolerate but skip queue entries that - time out. */ + /* if we have a timeout but a timeout value was given then always + skip. The '+' meaning has been changed! */ + WARNF("Test case results in a timeout (skipping)"); + ++cal_failures; + q->cal_failed = CAL_CHANCES; + q->disabled = 1; + q->perf_score = 0; - if (afl->timeout_given > 1) { + if (!q->was_fuzzed) { - WARNF("Test case results in a timeout (skipping)"); - q->cal_failed = CAL_CHANCES; - ++cal_failures; - break; + q->was_fuzzed = 1; + --afl->pending_not_fuzzed; + --afl->active_paths; } - SAYF("\n" cLRD "[-] " cRST - "The program took more than %u ms to process one of the initial " - "test cases.\n" - " Usually, the right thing to do is to relax the -t option - " - "or to delete it\n" - " altogether and allow the fuzzer to auto-calibrate. That " - "said, if you know\n" - " what you are doing and want to simply skip the unruly test " - "cases, append\n" - " '+' at the end of the value passed to -t ('-t %u+').\n", - afl->fsrv.exec_tmout, afl->fsrv.exec_tmout); - - FATAL("Test case '%s' results in a timeout", fn); + break; } else { @@ -1060,13 +1051,22 @@ void perform_dry_run(afl_state_t *afl) { p->perf_score = 0; u32 i = 0; - while (unlikely(afl->queue_buf[i]->disabled)) { + while (unlikely(i < afl->queued_paths && afl->queue_buf[i] && + afl->queue_buf[i]->disabled)) { ++i; } - afl->queue = afl->queue_buf[i]; + if (i < afl->queued_paths && afl->queue_buf[i]) { + + afl->queue = afl->queue_buf[i]; + + } else { + + afl->queue = afl->queue_buf[0]; + + } afl->max_depth = 0; for (i = 0; i < afl->queued_paths; i++) { @@ -2017,7 +2017,7 @@ void setup_dirs_fds(afl_state_t *afl) { fprintf(afl->fsrv.plot_file, "# unix_time, cycles_done, cur_path, paths_total, " "pending_total, pending_favs, map_size, unique_crashes, " - "unique_hangs, max_depth, execs_per_sec\n"); + "unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n"); fflush(afl->fsrv.plot_file); /* ignore errors */ diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 3ac7ba11..1ab5f996 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -30,7 +30,6 @@ //#define _DEBUG //#define CMPLOG_INTROSPECTION -#define CMPLOG_COMBINE // CMP attribute enum enum { @@ -205,14 +204,31 @@ static void type_replace(afl_state_t *afl, u8 *buf, u32 len) { case '\t': c = ' '; break; - /* - case '\r': - case '\n': - // nothing ... - break; - */ + case '\r': + c = '\n'; + break; + case '\n': + c = '\r'; + break; + case 0: + c = 1; + break; + case 1: + c = 0; + break; + case 0xff: + c = 0; + break; default: - c = (buf[i] ^ 0xff); + if (buf[i] < 32) { + + c = (buf[i] ^ 0x1f); + + } else { + + c = (buf[i] ^ 0x7f); // we keep the highest bit + + } } @@ -506,7 +522,7 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) { } -#ifdef CMPLOG_SOLVE_TRANSFORM +//#ifdef CMPLOG_SOLVE_TRANSFORM static int strntoll(const char *str, size_t sz, char **end, int base, long long *out) { @@ -591,7 +607,7 @@ static int is_hex(const char *str) { } - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 +#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 // tests 4 bytes at location static int is_base64(const char *str) { @@ -704,10 +720,10 @@ static void to_base64(u8 *src, u8 *dst, u32 dst_len) { } - #endif - #endif +//#endif + static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 pattern, u64 repl, u64 o_pattern, u64 changed_val, u8 attr, u32 idx, u32 taint_len, @@ -731,9 +747,9 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // o_pattern, pattern, repl, changed_val, idx, taint_len, // h->shape + 1, attr); -#ifdef CMPLOG_SOLVE_TRANSFORM + //#ifdef CMPLOG_SOLVE_TRANSFORM // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3 - if (lvl & LVL3) { + if (afl->cmplog_enable_transform && (lvl & LVL3)) { u8 * endptr; u8 use_num = 0, use_unum = 0; @@ -754,11 +770,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - #ifdef _DEBUG +#ifdef _DEBUG if (idx == 0) fprintf(stderr, "ASCII is=%u use_num=%u use_unum=%u idx=%u %llx==%llx\n", afl->queue_cur->is_ascii, use_num, use_unum, idx, num, pattern); - #endif +#endif // num is likely not pattern as atoi("AAA") will be zero... if (use_num && ((u64)num == pattern || !num)) { @@ -1043,7 +1059,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } -#endif + //#endif // we only allow this for ascii2integer (above) so leave if this is the case if (unlikely(pattern == o_pattern)) { return 0; } @@ -1198,8 +1214,12 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // 16 = modified float, 32 = modified integer (modified = wont match // in original buffer) -#ifdef CMPLOG_SOLVE_ARITHMETIC - if (lvl < LVL3 || attr == IS_TRANSFORM) { return 0; } + //#ifdef CMPLOG_SOLVE_ARITHMETIC + if (!afl->cmplog_enable_arith || lvl < LVL3 || attr == IS_TRANSFORM) { + + return 0; + + } if (!(attr & (IS_GREATER | IS_LESSER)) || SHAPE_BYTES(h->shape) < 4) { @@ -1304,11 +1324,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, double *f = (double *)&repl; float g = (float)*f; repl_new = 0; - #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) memcpy((char *)&repl_new, (char *)&g, 4); - #else +#else memcpy(((char *)&repl_new) + 4, (char *)&g, 4); - #endif +#endif changed_val = repl_new; h->shape = 3; // modify shape @@ -1363,7 +1383,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } -#endif /* CMPLOG_SOLVE_ARITHMETIC */ + //#endif /* CMPLOG_SOLVE_ARITHMETIC return 0; @@ -1522,7 +1542,7 @@ static void try_to_add_to_dictN(afl_state_t *afl, u128 v, u8 size) { for (k = 0; k < size; ++k) { #else - u32 off = 16 - size; + u32 off = 16 - size; for (k = 16 - size; k < 16; ++k) { #endif @@ -1840,9 +1860,9 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, #ifndef CMPLOG_COMBINE (void)(cbuf); #endif -#ifndef CMPLOG_SOLVE_TRANSFORM - (void)(changed_val); -#endif + //#ifndef CMPLOG_SOLVE_TRANSFORM + // (void)(changed_val); + //#endif u8 save[40]; u32 saved_idx = idx, pre, from = 0, to = 0, i, j; @@ -1922,16 +1942,16 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } -#ifdef CMPLOG_SOLVE_TRANSFORM + //#ifdef CMPLOG_SOLVE_TRANSFORM if (*status == 1) return 0; - if (lvl & LVL3) { + if (afl->cmplog_enable_transform && (lvl & LVL3)) { u32 toupper = 0, tolower = 0, xor = 0, arith = 0, tohex = 0, fromhex = 0; - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 +#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 u32 tob64 = 0, fromb64 = 0; - #endif +#endif u32 from_0 = 0, from_x = 0, from_X = 0, from_slash = 0, from_up = 0; u32 to_0 = 0, to_x = 0, to_slash = 0, to_up = 0; u8 xor_val[32], arith_val[32], tmp[48]; @@ -2027,7 +2047,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 +#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 if (i % 3 == 2 && i < 24) { if (is_base64(repl + ((i / 3) << 2))) tob64 += 3; @@ -2040,7 +2060,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } - #endif +#endif if ((o_pattern[i] ^ orig_buf[idx + i]) == xor_val[i] && xor_val[i]) { @@ -2068,20 +2088,20 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } - #ifdef _DEBUG +#ifdef _DEBUG fprintf(stderr, "RTN idx=%u loop=%u xor=%u arith=%u tolower=%u toupper=%u " "tohex=%u fromhex=%u to_0=%u to_slash=%u to_x=%u " "from_0=%u from_slash=%u from_x=%u\n", idx, i, xor, arith, tolower, toupper, tohex, fromhex, to_0, to_slash, to_x, from_0, from_slash, from_x); - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 + #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 fprintf(stderr, "RTN idx=%u loop=%u tob64=%u from64=%u\n", tob64, fromb64); - #endif #endif +#endif - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 +#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 // input is base64 and converted to binary? convert repl to base64! if ((i % 4) == 3 && i < 24 && fromb64 > i) { @@ -2104,7 +2124,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } - #endif +#endif // input is converted to hex? convert repl to binary! if (i < 16 && tohex > i) { @@ -2233,16 +2253,16 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } - #ifdef CMPLOG_COMBINE +#ifdef CMPLOG_COMBINE if (*status == 1) { memcpy(cbuf + idx, &buf[idx], i + 1); } - #endif +#endif if ((i >= 7 && (i >= xor&&i >= arith &&i >= tolower &&i >= toupper &&i > tohex &&i > (fromhex + from_0 + from_x + from_slash + 1) - #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 +#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64 && i > tob64 + 3 && i > fromb64 + 4 - #endif +#endif )) || repl[i] != changed_val[i] || *status == 1) { @@ -2256,7 +2276,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, } -#endif + //#endif return 0; @@ -2589,9 +2609,9 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) { } else if ((lvl & LVL1) -#ifdef CMPLOG_SOLVE_TRANSFORM - || (lvl & LVL3) -#endif + //#ifdef CMPLOG_SOLVE_TRANSFORM + || ((lvl & LVL3) && afl->cmplog_enable_transform) + //#endif ) { if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) { @@ -2672,7 +2692,7 @@ exit_its: #else u32 *v = (u32 *)afl->virgin_bits; u32 *s = (u32 *)virgin_save; - u32 i; + u32 i; for (i = 0; i < (afl->shm.map_size >> 2); i++) { v[i] &= s[i]; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 97cb7415..0b84a542 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -707,6 +707,8 @@ void sync_fuzzers(afl_state_t *afl) { if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0); + afl->last_sync_time = get_cur_time(); + } /* Trim all new test cases to save cycles when doing deterministic checks. The diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 5040e3ef..3d36e712 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -486,6 +486,8 @@ void read_afl_environment(afl_state_t *afl, char **envp) { WARNF("Mistyped AFL environment variable: %s", env); issue_detected = 1; + print_suggested_envs(env); + } } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 66efeb20..bd856088 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -185,15 +185,14 @@ void load_stats_file(afl_state_t *afl) { /* Update stats file for unattended monitoring. */ -void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, - double eps) { +void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, + double stability, double eps) { #ifndef __HAIKU__ struct rusage rus; #endif u64 cur_time = get_cur_time(); - u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits); u8 fn[PATH_MAX]; FILE *f; @@ -353,9 +352,11 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, /* Update the plot file if there is a reason to. */ -void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) { +void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, + double eps) { - if (unlikely(afl->plot_prev_qp == afl->queued_paths && + if (unlikely(afl->stop_soon) || + unlikely(afl->plot_prev_qp == afl->queued_paths && afl->plot_prev_pf == afl->pending_favored && afl->plot_prev_pnf == afl->pending_not_fuzzed && afl->plot_prev_ce == afl->current_entry && @@ -384,16 +385,16 @@ void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) { /* Fields in the file: unix_time, afl->cycles_done, cur_path, paths_total, paths_not_fuzzed, - favored_not_fuzzed, afl->unique_crashes, afl->unique_hangs, afl->max_depth, - execs_per_sec */ + favored_not_fuzzed, unique_crashes, unique_hangs, max_depth, + execs_per_sec, edges_found */ - fprintf( - afl->fsrv.plot_file, - "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu\n", - get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry, - afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored, - bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps, - afl->plot_prev_ed); /* ignore errors */ + fprintf(afl->fsrv.plot_file, + "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, " + "%u\n", + get_cur_time() / 1000, afl->queue_cycle - 1, afl->current_entry, + afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored, + bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, + eps, afl->plot_prev_ed, t_bytes); /* ignore errors */ fflush(afl->fsrv.plot_file); @@ -532,7 +533,8 @@ void show_stats(afl_state_t *afl) { if (cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000) { afl->stats_last_stats_ms = cur_ms; - write_stats_file(afl, t_byte_ratio, stab_ratio, afl->stats_avg_exec); + write_stats_file(afl, t_bytes, t_byte_ratio, stab_ratio, + afl->stats_avg_exec); save_auto(afl); write_bitmap(afl); @@ -555,7 +557,7 @@ void show_stats(afl_state_t *afl) { if (cur_ms - afl->stats_last_plot_ms > PLOT_UPDATE_SEC * 1000) { afl->stats_last_plot_ms = cur_ms; - maybe_update_plot_file(afl, t_byte_ratio, afl->stats_avg_exec); + maybe_update_plot_file(afl, t_bytes, t_byte_ratio, afl->stats_avg_exec); } @@ -1217,7 +1219,7 @@ void show_init_stats(afl_state_t *afl) { stringify_int(IB(0), min_us), stringify_int(IB(1), max_us), stringify_int(IB(2), avg_us)); - if (!afl->timeout_given) { + if (afl->timeout_given != 1) { /* Figure out the appropriate timeout. The basic idea is: 5x average or 1x max, rounded up to EXEC_TM_ROUND ms and capped at 1 second. diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 8eb3625b..a02eadb2 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -103,7 +103,10 @@ static void usage(u8 *argv0, int more_help) { " quad -- see docs/power_schedules.md\n" " -f file - location read by the fuzzed program (default: stdin " "or @@)\n" - " -t msec - timeout for each run (auto-scaled, 50-%u ms)\n" + " -t msec - timeout for each run (auto-scaled, default %u ms). " + "Add a '+'\n" + " to auto-calculate the timeout, the value being the " + "maximum.\n" " -m megs - memory limit for child process (%u MB, 0 = no limit " "[default])\n" " -Q - use binary-only instrumentation (QEMU mode)\n" @@ -122,10 +125,10 @@ static void usage(u8 *argv0, int more_help) { " -c program - enable CmpLog by specifying a binary compiled for " "it.\n" " if using QEMU, just use -c 0.\n" - " -l cmplog_level - set the complexity/intensivity of CmpLog.\n" - " Values: 1 (basic), 2 (larger files) and 3 " - "(transform)\n\n" - + " -l cmplog_opts - CmpLog configuration values (e.g. \"2AT\"):\n" + " 1=small files (default), 2=larger files, 3=all " + "files,\n" + " A=arithmetic solving, T=transformational solving.\n\n" "Fuzzing behavior settings:\n" " -Z - sequential queue selection instead of weighted " "random\n" @@ -137,8 +140,8 @@ static void usage(u8 *argv0, int more_help) { "Testing settings:\n" " -s seed - use a fixed seed for the RNG\n" - " -V seconds - fuzz for a specific time then terminate\n" - " -E execs - fuzz for a approx. no of total executions then " + " -V seconds - fuzz for a specified time then terminate\n" + " -E execs - fuzz for an approx. no. of total executions then " "terminate\n" " Note: not precise and can have several more " "executions.\n\n" @@ -812,13 +815,36 @@ int main(int argc, char **argv_orig, char **envp) { case 'l': { - if (optarg) { afl->cmplog_lvl = atoi(optarg); } - if (afl->cmplog_lvl < 1 || afl->cmplog_lvl > CMPLOG_LVL_MAX) { + if (!optarg) { FATAL("missing parameter for 'l'"); } + char *c = optarg; + while (*c) { - FATAL( - "Bad complog level value, accepted values are 1 (default), 2 and " - "%u.", - CMPLOG_LVL_MAX); + switch (*c) { + + case '0': + case '1': + afl->cmplog_lvl = 1; + break; + case '2': + afl->cmplog_lvl = 2; + break; + case '3': + afl->cmplog_lvl = 3; + break; + case 'a': + case 'A': + afl->cmplog_enable_arith = 1; + break; + case 't': + case 'T': + afl->cmplog_enable_transform = 1; + break; + default: + FATAL("Unknown option value '%c' in -l %s", *c, optarg); + + } + + ++c; } @@ -1428,7 +1454,7 @@ int main(int argc, char **argv_orig, char **envp) { } - if (!afl->timeout_given) { find_timeout(afl); } + if (!afl->timeout_given) { find_timeout(afl); } // only for resumes! if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL && !afl->in_place_resume) { @@ -1682,20 +1708,49 @@ int main(int argc, char **argv_orig, char **envp) { cull_queue(afl); - if (!afl->pending_not_fuzzed) { + // ensure we have at least one seed that is not disabled. + u32 entry, valid_seeds = 0; + for (entry = 0; entry < afl->queued_paths; ++entry) + if (!afl->queue_buf[entry]->disabled) { ++valid_seeds; } + + if (!afl->pending_not_fuzzed || !valid_seeds) { FATAL("We need at least one valid input seed that does not crash!"); } + if (afl->timeout_given == 2) { // -t ...+ option + + if (valid_seeds == 1) { + + WARNF( + "Only one valid seed is present, auto-calculating the timeout is " + "disabled!"); + afl->timeout_given = 1; + + } else { + + u64 max_ms = 0; + + for (entry = 0; entry < afl->queued_paths; ++entry) + if (!afl->queue_buf[entry]->disabled) + if (afl->queue_buf[entry]->exec_us > max_ms) + max_ms = afl->queue_buf[entry]->exec_us; + + afl->fsrv.exec_tmout = max_ms; + + } + + } + show_init_stats(afl); if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); afl->start_time = get_cur_time(); if (afl->in_place_resume || afl->afl_env.afl_autoresume) load_stats_file(afl); - write_stats_file(afl, 0, 0, 0); - maybe_update_plot_file(afl, 0, 0); + write_stats_file(afl, 0, 0, 0, 0); + maybe_update_plot_file(afl, 0, 0, 0); save_auto(afl); if (afl->stop_soon) { goto stop_fuzzing; } @@ -1745,12 +1800,15 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->old_seed_selection)) { afl->current_entry = 0; - while (unlikely(afl->queue_buf[afl->current_entry]->disabled)) { + while (unlikely(afl->current_entry < afl->queued_paths && + afl->queue_buf[afl->current_entry]->disabled)) { ++afl->current_entry; } + if (afl->current_entry >= afl->queued_paths) { afl->current_entry = 0; } + afl->queue_cur = afl->queue_buf[afl->current_entry]; if (unlikely(seek_to)) { @@ -1953,15 +2011,24 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->is_main_node)) { - if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) { + if (unlikely(get_cur_time() > + (SYNC_TIME >> 1) + afl->last_sync_time)) { + + if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) { - sync_fuzzers(afl); + sync_fuzzers(afl); + + } } } else { - if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); } + if (unlikely(get_cur_time() > SYNC_TIME + afl->last_sync_time)) { + + if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); } + + } } @@ -1976,12 +2043,12 @@ int main(int argc, char **argv_orig, char **envp) { } write_bitmap(afl); - maybe_update_plot_file(afl, 0, 0); + maybe_update_plot_file(afl, 0, 0, 0); save_auto(afl); stop_fuzzing: - write_stats_file(afl, 0, 0, 0); + write_stats_file(afl, 0, 0, 0, 0); afl->force_ui_update = 1; // ensure the screen is reprinted show_stats(afl); // print the screen one last time |