commit afl for openSUSE:Factory
Hello community, here is the log from the commit of package afl for openSUSE:Factory checked in at 2016-07-28 23:46:39 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/afl (Old) and /work/SRC/openSUSE:Factory/.afl.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "afl" Changes: -------- --- /work/SRC/openSUSE:Factory/afl/afl.changes 2016-07-01 09:59:30.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.afl.new/afl.changes 2016-07-28 23:46:41.000000000 +0200 @@ -1,0 +2,15 @@ +Sat Jul 23 19:10:30 UTC 2016 - astieger@suse.com + +- afl 2.21b: + * Minor UI fixes +- includes changes from 2.20b: + * Revamp handling of variable paths + * Stablility improvements + * Include current input bitmap density in UI + * Add experimental support for parallelizing -M. +- includes changes from 2.19b: + * Ensure auto CPU binding happens at non-overlapping times +- includes changes from 2.18b + * Performance improvements + +------------------------------------------------------------------- Old: ---- afl-2.17b.tgz New: ---- afl-2.21b.tgz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ afl.spec ++++++ --- /var/tmp/diff_new_pack.oASzMh/_old 2016-07-28 23:46:42.000000000 +0200 +++ /var/tmp/diff_new_pack.oASzMh/_new 2016-07-28 23:46:42.000000000 +0200 @@ -17,7 +17,7 @@ Name: afl -Version: 2.17b +Version: 2.21b Release: 0 Summary: American fuzzy lop is a security-oriented fuzzer License: Apache-2.0 ++++++ afl-2.17b.tgz -> afl-2.21b.tgz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/afl-as.h new/afl-2.21b/afl-as.h --- old/afl-2.17b/afl-as.h 2016-06-21 06:44:52.000000000 +0200 +++ new/afl-2.21b/afl-as.h 2016-07-04 22:08:29.000000000 +0200 @@ -98,7 +98,7 @@ of every .c file. This should have no impact in any practical sense. Another side effect of this design is that getenv() will be called once per - every .o file when running in non-instrumented mode; an since getenv() tends + every .o file when running in non-instrumented mode; and since getenv() tends to be optimized in funny ways, we need to be very careful to save every oddball register it may touch. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/afl-fuzz.c new/afl-2.21b/afl-fuzz.c --- old/afl-2.17b/afl-fuzz.c 2016-06-28 07:22:19.000000000 +0200 +++ new/afl-2.21b/afl-fuzz.c 2016-07-23 01:21:04.000000000 +0200 @@ -112,12 +112,12 @@ in_place_resume, /* Attempt in-place resume? */ auto_changed, /* Auto-generated tokens changed? */ no_cpu_meter_red, /* Feng shui on the status screen */ - no_var_check, /* Don't detect variable behavior */ shuffle_queue, /* Shuffle input queue? */ bitmap_changed = 1, /* Time to update bitmap? */ qemu_mode, /* Running in QEMU mode? */ skip_requested, /* Skip request, via SIGUSR1 */ - run_over10m; /* Run time over 10 minutes? */ + run_over10m, /* Run time over 10 minutes? */ + persistent_mode; /* Running in persistent mode? */ static s32 out_fd, /* Persistent fd for out_file */ dev_urandom_fd = -1, /* Persistent fd for /dev/urandom */ @@ -135,6 +135,8 @@ virgin_hang[MAP_SIZE], /* Bits we haven't seen in hangs */ virgin_crash[MAP_SIZE]; /* Bits we haven't seen in crashes */ +static u8 var_bytes[MAP_SIZE]; /* Bytes that appear to be variable */ + static s32 shm_id; /* ID of the SHM region */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ @@ -154,6 +156,7 @@ cur_depth, /* Current path depth */ max_depth, /* Max path depth */ useless_at_start, /* Number of useless starting paths */ + var_byte_count, /* Bitmap bytes with var behavior */ current_entry, /* Current queue entry ID */ havoc_div = 1; /* Cycle count divisor for havoc */ @@ -166,6 +169,7 @@ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ last_hang_time, /* Time for most recent hang (ms) */ + last_crash_execs, /* Exec counter at last crash */ queue_cycle, /* Queue round counter */ cycles_wo_finds, /* Cycles without any new paths */ trim_execs, /* Execs done to trim input files */ @@ -183,6 +187,8 @@ static s32 stage_cur, stage_max; /* Stage progression */ static s32 splicing_with = -1; /* Splicing with which test case? */ +static u32 master_id, master_max; /* Master instance job splitting */ + static u32 syncing_case; /* Syncing with case #... */ static s32 stage_cur_byte, /* Byte offset of current stage op */ @@ -343,7 +349,7 @@ static inline u32 UR(u32 limit) { - if (!rand_cnt--) { + if (unlikely(!rand_cnt--)) { u32 seed[2]; @@ -863,9 +869,6 @@ This function is called after every exec() on a fairly large buffer, so it needs to be fast. We do this in 32-bit and 64-bit flavors. */ -#define FFL(_b) (0xffULL << ((_b) << 3)) -#define FF(_b) (0xff << ((_b) << 3)) - static inline u8 has_new_bits(u8* virgin_map) { #ifdef __x86_64__ @@ -888,53 +891,39 @@ while (i--) { -#ifdef __x86_64__ - - u64 cur = *current; - u64 vir = *virgin; - -#else - - u32 cur = *current; - u32 vir = *virgin; - -#endif /* ^__x86_64__ */ + /* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap + that have not been already cleared from the virgin map - since this will + almost always be the case. */ - /* Optimize for *current == ~*virgin, since this will almost always be the - case. */ + if (unlikely(*current) && unlikely(*current & *virgin)) { - if (cur & vir) { + if (likely(ret < 2)) { - if (ret < 2) { + u8* cur = (u8*)current; + u8* vir = (u8*)virgin; - /* This trace did not have any new bytes yet; see if there's any - current[] byte that is non-zero when virgin[] is 0xff. */ + /* Looks like we have not found any new bytes yet; see if any non-zero + bytes in current[] are pristine in virgin[]. */ #ifdef __x86_64__ - if (((cur & FFL(0)) && (vir & FFL(0)) == FFL(0)) || - ((cur & FFL(1)) && (vir & FFL(1)) == FFL(1)) || - ((cur & FFL(2)) && (vir & FFL(2)) == FFL(2)) || - ((cur & FFL(3)) && (vir & FFL(3)) == FFL(3)) || - ((cur & FFL(4)) && (vir & FFL(4)) == FFL(4)) || - ((cur & FFL(5)) && (vir & FFL(5)) == FFL(5)) || - ((cur & FFL(6)) && (vir & FFL(6)) == FFL(6)) || - ((cur & FFL(7)) && (vir & FFL(7)) == FFL(7))) ret = 2; + if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) || + (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) || + (cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) || + (cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff)) ret = 2; else ret = 1; #else - if (((cur & FF(0)) && (vir & FF(0)) == FF(0)) || - ((cur & FF(1)) && (vir & FF(1)) == FF(1)) || - ((cur & FF(2)) && (vir & FF(2)) == FF(2)) || - ((cur & FF(3)) && (vir & FF(3)) == FF(3))) ret = 2; + if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) || + (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff)) ret = 2; else ret = 1; #endif /* ^__x86_64__ */ } - *virgin = vir & ~cur; + *virgin &= ~*current; } @@ -982,6 +971,8 @@ } +#define FF(_b) (0xff << ((_b) << 3)) + /* Count the number of bytes set in the bitmap. Called fairly sporadically, mostly to update the status screen or calibrate and examine confirmed new paths. */ @@ -1060,7 +1051,7 @@ /* Optimize for sparse bitmaps. */ - if (*mem) { + if (unlikely(*mem)) { u8* mem8 = (u8*)mem; @@ -1091,7 +1082,7 @@ /* Optimize for sparse bitmaps. */ - if (*mem) { + if (unlikely(*mem)) { u8* mem8 = (u8*)mem; @@ -1114,7 +1105,7 @@ preprocessing step for any newly acquired traces. Called on every exec, must be fast. */ -static const u8 count_class_lookup[256] = { +static const u8 count_class_lookup8[256] = { [0] = 0, [1] = 1, @@ -1128,6 +1119,22 @@ }; +static u16 count_class_lookup16[65536]; + + +static void init_count_class16(void) { + + u32 b1, b2; + + for (b1 = 0; b1 < 256; b1++) + for (b2 = 0; b2 < 256; b2++) + count_class_lookup16[(b1 << 8) + b2] = + (count_class_lookup8[b1] << 8) | + count_class_lookup8[b2]; + +} + + #ifdef __x86_64__ static inline void classify_counts(u64* mem) { @@ -1138,18 +1145,14 @@ /* Optimize for sparse bitmaps. */ - if (*mem) { + if (unlikely(*mem)) { - u8* mem8 = (u8*)mem; + u16* mem16 = (u16*)mem; - mem8[0] = count_class_lookup[mem8[0]]; - mem8[1] = count_class_lookup[mem8[1]]; - mem8[2] = count_class_lookup[mem8[2]]; - mem8[3] = count_class_lookup[mem8[3]]; - mem8[4] = count_class_lookup[mem8[4]]; - mem8[5] = count_class_lookup[mem8[5]]; - mem8[6] = count_class_lookup[mem8[6]]; - mem8[7] = count_class_lookup[mem8[7]]; + mem16[0] = count_class_lookup16[mem16[0]]; + mem16[1] = count_class_lookup16[mem16[1]]; + mem16[2] = count_class_lookup16[mem16[2]]; + mem16[3] = count_class_lookup16[mem16[3]]; } @@ -1169,14 +1172,12 @@ /* Optimize for sparse bitmaps. */ - if (*mem) { + if (unlikely(*mem)) { - u8* mem8 = (u8*)mem; + u16* mem16 = (u16*)mem; - mem8[0] = count_class_lookup[mem8[0]]; - mem8[1] = count_class_lookup[mem8[1]]; - mem8[2] = count_class_lookup[mem8[2]]; - mem8[3] = count_class_lookup[mem8[3]]; + mem16[0] = count_class_lookup16[mem16[0]]; + mem16[1] = count_class_lookup16[mem16[1]]; } @@ -2520,7 +2521,11 @@ static u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem, u32 handicap, u8 from_queue) { - u8 fault = 0, new_bits = 0, var_detected = 0, first_run = (q->exec_cksum == 0); + static u8 first_trace[MAP_SIZE]; + + u8 fault = 0, new_bits = 0, var_detected = 0, + first_run = (q->exec_cksum == 0); + u64 start_us, stop_us; s32 old_sc = stage_cur, old_sm = stage_max, old_tmout = exec_tmout; @@ -2537,7 +2542,7 @@ q->cal_failed++; stage_name = "calibration"; - stage_max = no_var_check ? CAL_CYCLES_NO_VAR : CAL_CYCLES; + stage_max = CAL_CYCLES; /* Make sure the forkserver is up before we do anything, and let's not count its spin-up time toward binary calibration. */ @@ -2545,6 +2550,8 @@ if (dumb_mode != 1 && !no_forkserver && !forksrv_pid) init_forkserver(argv); + if (q->exec_cksum) memcpy(first_trace, trace_bits, MAP_SIZE); + start_us = get_cur_time_us(); for (stage_cur = 0; stage_cur < stage_max; stage_cur++) { @@ -2574,12 +2581,24 @@ u8 hnb = has_new_bits(virgin_bits); if (hnb > new_bits) new_bits = hnb; - if (!no_var_check && q->exec_cksum) { + if (q->exec_cksum) { + + u32 i; + + for (i = 0; i < MAP_SIZE; i++) + if (!var_bytes[i] && first_trace[i] != trace_bits[i]) { + var_bytes[i] = 1; + stage_max = CAL_CYCLES_LONG; + } var_detected = 1; - stage_max = CAL_CYCLES_LONG; - } else q->exec_cksum = cksum; + } else { + + q->exec_cksum = cksum; + memcpy(first_trace, trace_bits, MAP_SIZE); + + } } @@ -2618,9 +2637,15 @@ /* Mark variable paths. */ - if (var_detected && !q->var_behavior) { - mark_as_variable(q); - queued_variable++; + if (var_detected) { + + var_byte_count = count_bytes(var_bytes); + + if (!q->var_behavior) { + mark_as_variable(q); + queued_variable++; + } + } stage_name = old_sn; @@ -3209,6 +3234,7 @@ unique_crashes++; last_crash_time = get_cur_time(); + last_crash_execs = total_execs; break; @@ -3306,9 +3332,9 @@ /* Update stats file for unattended monitoring. */ -static void write_stats_file(double bitmap_cvg, double eps) { +static void write_stats_file(double bitmap_cvg, double stability, double eps) { - static double last_bcvg, last_eps; + static double last_bcvg, last_stab, last_eps; u8* fn = alloc_printf("%s/fuzzer_stats", out_dir); s32 fd; @@ -3327,46 +3353,51 @@ /* Keep last values in case we're called from another context where exec/sec stats and such are not readily available. */ - if (!bitmap_cvg && !eps) { + if (!bitmap_cvg && !stability && !eps) { bitmap_cvg = last_bcvg; + stability = last_stab; eps = last_eps; } else { last_bcvg = bitmap_cvg; + last_stab = stability; last_eps = eps; } - fprintf(f, "start_time : %llu\n" - "last_update : %llu\n" - "fuzzer_pid : %u\n" - "cycles_done : %llu\n" - "execs_done : %llu\n" - "execs_per_sec : %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" - "pending_favs : %u\n" - "pending_total : %u\n" - "variable_paths : %u\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" - "exec_timeout : %u\n" - "afl_banner : %s\n" - "afl_version : " VERSION "\n" - "command_line : %s\n", + fprintf(f, "start_time : %llu\n" + "last_update : %llu\n" + "fuzzer_pid : %u\n" + "cycles_done : %llu\n" + "execs_done : %llu\n" + "execs_per_sec : %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" + "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" + "afl_banner : %s\n" + "afl_version : " VERSION "\n" + "command_line : %s\n", start_time / 1000, get_cur_time() / 1000, getpid(), queue_cycle ? (queue_cycle - 1) : 0, total_execs, eps, queued_paths, queued_favored, queued_discovered, queued_imported, max_depth, current_entry, pending_favored, pending_not_fuzzed, - queued_variable, bitmap_cvg, unique_crashes, unique_hangs, - last_path_time / 1000, last_crash_time / 1000, - last_hang_time / 1000, exec_tmout, use_banner, orig_cmdline); + queued_variable, stability, bitmap_cvg, unique_crashes, + unique_hangs, last_path_time / 1000, last_crash_time / 1000, + last_hang_time / 1000, total_execs - last_crash_execs, + exec_tmout, use_banner, orig_cmdline); /* ignore errors */ fclose(f); @@ -3789,7 +3820,7 @@ static u64 last_stats_ms, last_plot_ms, last_ms, last_execs; static double avg_exec; - double t_byte_ratio; + double t_byte_ratio, stab_ratio; u64 cur_ms; u32 t_bytes, t_bits; @@ -3842,12 +3873,17 @@ t_bytes = count_non_255_bytes(virgin_bits); t_byte_ratio = ((double)t_bytes * 100) / MAP_SIZE; + if (t_bytes) + stab_ratio = 100 - ((double)var_byte_count) * 100 / t_bytes; + else + stab_ratio = 100; + /* Roughly every minute, update fuzzer stats and save auto tokens. */ if (cur_ms - last_stats_ms > STATS_UPDATE_SEC * 1000) { last_stats_ms = cur_ms; - write_stats_file(t_byte_ratio, avg_exec); + write_stats_file(t_byte_ratio, stab_ratio, avg_exec); save_auto(); write_bitmap(); @@ -4009,8 +4045,8 @@ SAYF(bV bSTOP " now processing : " cRST "%-17s " bSTG bV bSTOP, tmp); - - sprintf(tmp, "%s (%0.02f%%)", DI(t_bytes), t_byte_ratio); + sprintf(tmp, "%0.02f%% / %0.02f%%", ((double)queue_cur->bitmap_size) * + 100 / MAP_SIZE, t_byte_ratio); SAYF(" map density : %s%-21s " bSTG bV "\n", t_byte_ratio > 70 ? cLRD : ((t_bytes < 200 && !dumb_mode) ? cPIN : cRST), tmp); @@ -4154,9 +4190,13 @@ DI(stage_finds[STAGE_HAVOC]), DI(stage_cycles[STAGE_HAVOC]), DI(stage_finds[STAGE_SPLICE]), DI(stage_cycles[STAGE_SPLICE])); - SAYF(bV bSTOP " havoc : " cRST "%-37s " bSTG bV bSTOP - " variable : %s%-10s " bSTG bV "\n", tmp, queued_variable ? cLRD : cRST, - no_var_check ? (u8*)"n/a" : DI(queued_variable)); + SAYF(bV bSTOP " havoc : " cRST "%-37s " bSTG bV bSTOP, tmp); + + if (t_bytes) sprintf(tmp, "%0.02f%%", stab_ratio); + else strcpy(tmp, "n/a"); + + SAYF(" stability : %s%-10s " bSTG bV "\n", stab_ratio < 90 ? cLRD : + ((queued_variable && !persistent_mode) ? cMGN : cRST), tmp); if (!bytes_trim_out) { @@ -4967,6 +5007,12 @@ if (skip_deterministic || queue_cur->was_fuzzed || queue_cur->passed_det) goto havoc_stage; + /* Skip deterministic fuzzing if exec path checksum puts this out of scope + for this master instance. */ + + if (master_max && (queue_cur->exec_cksum % master_max) != master_id - 1) + goto havoc_stage; + /********************************************* * SIMPLE BITFLIP (+dictionary construction) * *********************************************/ @@ -5136,7 +5182,7 @@ /* Effector map setup. These macros calculate: EFF_APOS - position of a particular file offset in the map. - EFF_ALEN - length of an map with a particular number of bytes. + EFF_ALEN - length of a map with a particular number of bytes. EFF_SPAN_ALEN - map span for a sequence of bytes. */ @@ -6567,8 +6613,14 @@ path = alloc_printf("%s/%s", qd_path, qd_ent->d_name); + /* Allow this to fail in case the other fuzzer is resuming or so... */ + fd = open(path, O_RDONLY); - if (fd < 0) PFATAL("Unable to open '%s'", path); + + if (fd < 0) { + ck_free(path); + continue; + } if (fstat(fd, &st)) PFATAL("fstat() failed"); @@ -6802,7 +6854,6 @@ OKF(cPIN "Persistent mode binary detected."); setenv(PERSIST_ENV_VAR, "1", 1); - no_var_check = 1; } else if (getenv("AFL_PERSISTENT")) { @@ -6814,6 +6865,7 @@ OKF(cPIN "Deferred forkserver binary detected."); setenv(DEFER_ENV_VAR, "1", 1); + persistent_mode = 1; } else if (getenv("AFL_DEFER_FORKSRV")) { @@ -7556,18 +7608,23 @@ u8 *extras_dir = 0; u8 mem_limit_given = 0; u8 exit_1 = !!getenv("AFL_BENCH_JUST_ONE"); - char** use_argv; + struct timeval tv; + struct timezone tz; + SAYF(cCYA "afl-fuzz " cBRI VERSION cRST " by <lcamtuf@google.com>\n"); doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; + gettimeofday(&tv, &tz); + srandom(tv.tv_sec ^ tv.tv_usec ^ getpid()); + while ((opt = getopt(argc, argv, "+i:o:f:m:t:T:dnCB:S:M:x:Q")) > 0) switch (opt) { - case 'i': + case 'i': /* input dir */ if (in_dir) FATAL("Multiple -i options not supported"); in_dir = optarg; @@ -7582,15 +7639,30 @@ out_dir = optarg; break; - case 'M': + case 'M': /* master sync ID */ force_deterministic = 1; /* Fall through */ - case 'S': /* sync ID */ + case 'S': { /* secondary sync ID */ + + u8* c; + + if (sync_id) FATAL("Multiple -S or -M options not supported"); + sync_id = optarg; + + if ((c = strchr(sync_id, ':'))) { + + *c = 0; + + if (sscanf(c + 1, "%u/%u", &master_id, &master_max) != 2 || + !master_id || !master_max || master_id > master_max || + master_max > 1000000) FATAL("Bogus master ID passed to -M"); + + } + + } - if (sync_id) FATAL("Multiple -S or -M options not supported"); - sync_id = optarg; break; case 'f': /* target file */ @@ -7599,13 +7671,13 @@ out_file = optarg; break; - case 'x': + case 'x': /* dictionary */ if (extras_dir) FATAL("Multiple -x options not supported"); extras_dir = optarg; break; - case 't': { + case 't': { /* timeout */ u8 suffix = 0; @@ -7622,7 +7694,7 @@ } - case 'm': { + case 'm': { /* mem limit */ u8 suffix = 'M'; @@ -7659,14 +7731,14 @@ break; - case 'd': + case 'd': /* skip deterministic */ if (skip_deterministic) FATAL("Multiple -d options not supported"); skip_deterministic = 1; use_splicing = 1; break; - case 'B': + case 'B': /* load bitmap */ /* This is a secret undocumented option! It is useful if you find an interesting test case during a normal fuzzing process, and want @@ -7685,26 +7757,26 @@ read_bitmap(in_bitmap); break; - case 'C': + case 'C': /* crash mode */ if (crash_mode) FATAL("Multiple -C options not supported"); crash_mode = FAULT_CRASH; break; - case 'n': + case 'n': /* dumb mode */ if (dumb_mode) FATAL("Multiple -n options not supported"); if (getenv("AFL_DUMB_FORKSRV")) dumb_mode = 2; else dumb_mode = 1; break; - case 'T': + case 'T': /* banner */ if (use_banner) FATAL("Multiple -T options not supported"); use_banner = optarg; break; - case 'Q': + case 'Q': /* QEMU mode */ if (qemu_mode) FATAL("Multiple -Q options not supported"); qemu_mode = 1; @@ -7738,7 +7810,6 @@ if (getenv("AFL_NO_FORKSRV")) no_forkserver = 1; if (getenv("AFL_NO_CPU_RED")) no_cpu_meter_red = 1; - if (getenv("AFL_NO_VAR_CHECK")) no_var_check = 1; if (getenv("AFL_SHUFFLE_QUEUE")) shuffle_queue = 1; if (dumb_mode == 2 && no_forkserver) @@ -7764,6 +7835,7 @@ setup_post(); setup_shm(); + init_count_class16(); setup_dirs_fds(); read_testcases(); @@ -7796,7 +7868,7 @@ seek_to = find_start_position(); - write_stats_file(0, 0); + write_stats_file(0, 0, 0); save_auto(); if (stop_soon) goto stop_fuzzing; @@ -7872,7 +7944,7 @@ if (queue_cur) show_stats(); write_bitmap(); - write_stats_file(0, 0); + write_stats_file(0, 0, 0); save_auto(); stop_fuzzing: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/config.h new/afl-2.21b/config.h --- old/afl-2.17b/config.h 2016-06-27 21:06:37.000000000 +0200 +++ new/afl-2.21b/config.h 2016-07-23 01:21:30.000000000 +0200 @@ -21,7 +21,7 @@ /* Version string: */ -#define VERSION "2.17b" +#define VERSION "2.21b" /****************************************************** * * @@ -61,13 +61,9 @@ /* Number of calibration cycles per every new test case (and for test cases that show variable behavior): */ -#define CAL_CYCLES 10 +#define CAL_CYCLES 8 #define CAL_CYCLES_LONG 40 -/* The same, but when AFL_NO_VAR_CHECK is set in the environment: */ - -#define CAL_CYCLES_NO_VAR 4 - /* Number of subsequent hangs before abandoning an input file: */ #define HANG_LIMIT 250 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/docs/ChangeLog new/afl-2.21b/docs/ChangeLog --- old/afl-2.17b/docs/ChangeLog 2016-06-28 04:17:51.000000000 +0200 +++ new/afl-2.21b/docs/ChangeLog 2016-07-23 01:21:22.000000000 +0200 @@ -13,10 +13,50 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. Not sure if you should upgrade? The lowest currently recommended version -is 2.07b. If you're stuck on an earlier release, it's strongly advisable +is 2.18b. If you're stuck on an earlier release, it's strongly advisable to get on with the times. -------------- +Version 2.21b: +-------------- + + - Added some crash reporting notes for Solaris in docs/INSTALL, as + investigated by Martin Carpenter. + + - Fixed a minor UI mix-up with havoc strategy stats. + +-------------- +Version 2.20b: +-------------- + + - Revamped the handling of variable paths, replacing path count with a + "stability" score to give users a much better signal. Based on the + feedback from Vegard Nossum. + + - Made a stability improvement to the syncing behavior with resuming + fuzzers. Based on the feedback from Vegard. + + - Changed the UI to include current input bitmap density along with + total density. Ditto. + + - Added experimental support for parallelizing -M. + +-------------- +Version 2.19b: +-------------- + + - Made a fix to make sure that auto CPU binding happens at non-overlapping + times. + +-------------- +Version 2.18b: +-------------- + + - Made several performance improvements to has_new_bits() and + classify_counts(). This should offer a robust performance bump with + fast targets. + +-------------- Version 2.17b: -------------- @@ -1495,7 +1535,7 @@ - Refactored the code slightly to make more frequent updates to fuzzer_stats and to provide more detail about synchronization. - - Added a fflush(stdout) call for non-tty operation, as requested by + - Added an fflush(stdout) call for non-tty operation, as requested by Joonas Kuorilehto. - Added some detail to fuzzer_stats for parity with plot_file. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/docs/INSTALL new/afl-2.21b/docs/INSTALL --- old/afl-2.17b/docs/INSTALL 2016-06-07 20:17:00.000000000 +0200 +++ new/afl-2.21b/docs/INSTALL 2016-07-22 20:48:18.000000000 +0200 @@ -140,11 +140,13 @@ Do *not* specify --with-as=/usr/gnu/bin/as - this will produce a GCC binary that ignores the -B flag and you will be back to square one. -If you have system-wide crash reporting enabled, you may run into problems -similar to the gotchas for Linux and MacOS X, but I have not verified this. -More information about AppCrash can be found here: +Note that Solaris reportedly comes withe crash reporting enabled, which causes +problems with crashes being misinterpreted as hangs, similarly to the gotchas +for Linux and MacOS X. AFL does not auto-detect crash reporting on this +particular platform, but you may need to run the following command: - http://www.oracle.com/technetwork/server-storage/solaris10/app-crash-142906.... +$ coreadm -d global -d global-setid -d process -d proc-setid \ + -d kzone -d log User emulation mode of QEMU is not available on Solaris, so black-box instrumentation mode (-Q) will not work. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/docs/README new/afl-2.21b/docs/README --- old/afl-2.17b/docs/README 2016-06-19 00:24:18.000000000 +0200 +++ new/afl-2.21b/docs/README 2016-07-21 20:54:39.000000000 +0200 @@ -464,6 +464,7 @@ Daniel Godas-Lopez Franjo Ivancic Austin Seipp Daniel Komaromy Daniel Binderman Jonathan Metzman + Vegard Nossum Thank you! diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/docs/env_variables.txt new/afl-2.21b/docs/env_variables.txt --- old/afl-2.17b/docs/env_variables.txt 2016-06-27 20:43:23.000000000 +0200 +++ new/afl-2.21b/docs/env_variables.txt 2016-07-21 20:42:24.000000000 +0200 @@ -99,11 +99,6 @@ normally done when starting up the forkserver and causes a pretty significant performance drop. - - Setting AFL_NO_VAR_CHECK skips the detection of variable test cases, - greatly speeding up session resumption and path discovery for complex - multi-threaded apps (but depriving you of a potentially useful signal - in more orderly programs). - - AFL_EXIT_WHEN_DONE causes afl-fuzz to terminate when all existing paths have been fuzzed and there were no new finds for a while. This would be normally indicated by the cycle counter in the UI turning green. May be diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/docs/parallel_fuzzing.txt new/afl-2.21b/docs/parallel_fuzzing.txt --- old/afl-2.17b/docs/parallel_fuzzing.txt 2016-04-23 08:54:06.000000000 +0200 +++ new/afl-2.21b/docs/parallel_fuzzing.txt 2016-07-21 22:21:48.000000000 +0200 @@ -51,13 +51,25 @@ for any test cases found by other fuzzers - and will incorporate them into its own fuzzing when they are deemed interesting enough. -The only difference between the -M and -S modes is that the master instance -will still perform deterministic checks; while the secondary instances will +The difference between the -M and -S modes is that the master instance will +still perform deterministic checks; while the secondary instances will proceed straight to random tweaks. If you don't want to do deterministic fuzzing at all, it's OK to run all instances with -S. With very slow or complex targets, or when running heavily parallelized jobs, this is usually a good plan. -You can monitor the progress of your jobs from the command line with the +Note that running multiple -M instances is wasteful, although there is an +experimental support for parallelizing the deterministic checks. To leverage +that, you need to create -M instances like so: + +$ ./afl-fuzz -i testcase_dir -o sync_dir -M masterA:1/3 [...] +$ ./afl-fuzz -i testcase_dir -o sync_dir -M masterB:2/3 [...] +$ ./afl-fuzz -i testcase_dir -o sync_dir -M masterC:3/3 [...] + +...where the first value after ':' is the sequential ID of a particular master +instance (starting at 1), and the second value is the total number of fuzzers to +distribute the deterministic fuzzing across. + +You can also monitor the progress of your jobs from the command line with the provided afl-whatsup tool. When the instances are no longer finding new paths, it's probably time to stop. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/docs/sister_projects.txt new/afl-2.21b/docs/sister_projects.txt --- old/afl-2.17b/docs/sister_projects.txt 2016-06-27 21:33:46.000000000 +0200 +++ new/afl-2.21b/docs/sister_projects.txt 2016-07-12 04:42:04.000000000 +0200 @@ -78,6 +78,13 @@ https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2016/june/pr... +WinAFL (Ivan Fratric) +--------------------- + + As the name implies, allows you to fuzz Windows binaries (using DynamoRio). + + https://github.com/ivanfratric/winafl + ---------------- Network fuzzing: ---------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/docs/status_screen.txt new/afl-2.21b/docs/status_screen.txt --- old/afl-2.17b/docs/status_screen.txt 2016-02-21 01:01:37.000000000 +0100 +++ new/afl-2.21b/docs/status_screen.txt 2016-07-21 22:37:18.000000000 +0200 @@ -119,7 +119,7 @@ --------------- +--------------------------------------+ - | map density : 4763 (29.07%) | + | map density : 10.15% / 29.07% | | count coverage : 4.03 bits/tuple | +--------------------------------------+ @@ -127,7 +127,11 @@ instrumentation embedded in the target binary. The first line in the box tells you how many branch tuples we have already -hit, in proportion to how much the bitmap can hold. Be wary of extremes: +hit, in proportion to how much the bitmap can hold. The number on the left +describes the current input; the one on the right is the value for the entire +input corpus. + +Be wary of extremes: - Absolute numbers below 200 or so suggest one of three things: that the program is extremely simple; that it is not instrumented properly (e.g., @@ -271,7 +275,7 @@ | pend fav : 583 | | own finds : 0 | | imported : 0 | - | variable : 0 | + | stability : 100.00% | +---------------------+ The first field in this section tracks the path depth reached through the @@ -291,27 +295,33 @@ imported from other fuzzer instances when doing parallelized fuzzing; and the number of inputs that produce seemingly variable behavior in the tested binary. -That last bit is actually fairly interesting. There are four quasi-common -explanations for variable behavior of the tested program: - - - Use of uninitialized memory in conjunction with some intrinsic sources of - entropy in the tested binary. This can be indicative of a security bug. - - - Attempts to create files that were already created during previous runs, or - otherwise interact with some form of persistent state. This is harmless, - but you may want to instruct the targeted program to write to stdout or to - /dev/null to avoid surprises (and disable the creation of temporary files - and similar artifacts, if applicable). - - - Hitting functionality that is actually designed to behave randomly. For - example, when fuzzing sqlite, the fuzzer will dutifully detect variable - behavior once the mutation engine generates something like: - - select random(); - - - Multiple threads executing at once in semi-random order. This is usually - just a nuisance, but if the number of variable paths is very high, try the - following options: +That last bit is actually fairly interesting: it measures the consistency of +observed traces. If a program always behaves the same for the same input data, +it will earn a score of 100%. When the value is over 90%, the fuzzing process +is still unlikely to be negatively affected. If it gets much lower, you may +be in trouble, since AFL will have difficulty discerning between meaningful +and "phantom" effects of tweaking the input file. + +Now, most targets will just get a 100% score, but when you see lower figures, +there are several things to look at: + + - The use of uninitialized memory in conjunction with some intrinsic sources + of entropy in the tested binary. Harmless to AFL, but could be indicative + of a security bug. + + - Attempts to manipulate persistent resources, such as left over temporary + files or shared memory objects. This is usually harmless, but you may want + to double-check to make sure the program isn't bailing out prematurely. + Running out of disk space, SHM handles, or other global resources can + trigger this, too. + + - Hitting some functionality that is actually designed to behave randomly. + Generally harmless. For example, when fuzzing sqlite, an input like + 'select random();' will trigger a variable execution path. + + - Multiple threads executing at once in semi-random order. This is harmless + when the 'stability' metric stays over 90% or so, but can become an issue + if not. Here's what to try: - Use afl-clang-fast from llvm_mode/ - it uses a thread-local tracking model that is less prone to concurrency issues, @@ -323,17 +333,10 @@ - Replace pthreads with GNU Pth (https://www.gnu.org/software/pth/), which allows you to use a deterministic scheduler. -Less likely causes may include running out of disk space, SHM handles, or other -globally limited resources. - The paths where variable behavior is detected are marked with a matching entry in the <out_dir>/queue/.state/variable_behavior/ directory, so you can look them up easily. -If you can't suppress variable behavior and don't want to see these warnings, -simply set AFL_NO_VAR_CHECK=1 in the environment before running afl-fuzz. This -will also dramatically speed up session resumption. - 9) CPU load ----------- @@ -378,6 +381,7 @@ - cur_path - currently processed entry number - pending_favs - number of favored entries still waiting to be fuzzed - pending_total - number of all entries waiting to be fuzzed + - stability - percentage of bitmap bytes that behave consistently - variable_paths - number of test cases showing variable behavior - unique_crashes - number of unique crashes recorded - unique_hangs - number of unique hangs encountered diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/llvm_mode/README.llvm new/afl-2.21b/llvm_mode/README.llvm --- old/afl-2.17b/llvm_mode/README.llvm 2016-06-07 20:14:22.000000000 +0200 +++ new/afl-2.21b/llvm_mode/README.llvm 2016-07-21 20:42:06.000000000 +0200 @@ -163,8 +163,8 @@ When running in this mode, the execution paths will inherently vary a bit depending on whether the input loop is being entered for the first time or -executed again. To avoid spurious warnings, the feature implies -AFL_NO_VAR_CHECK and hides the "variable path" warnings in the UI. +executed again. This can cause the "stability" metric in the UI to dip +slightly under 100%. PS. Because there are task switches still involved, the mode isn't as fast as "pure" in-process fuzzing offered, say, by LLVM's LibFuzzer; but it is a lot diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/afl-2.17b/types.h new/afl-2.21b/types.h --- old/afl-2.17b/types.h 2015-02-09 06:06:27.000000000 +0100 +++ new/afl-2.21b/types.h 2016-07-03 06:32:05.000000000 +0200 @@ -76,4 +76,7 @@ #define MEM_BARRIER() \ asm volatile("" ::: "memory") +#define likely(_x) __builtin_expect(!!(_x), 1) +#define unlikely(_x) __builtin_expect(!!(_x), 0) + #endif /* ! _HAVE_TYPES_H */
participants (1)
-
root@hilbert.suse.de