Index: third_party/afl/src/afl-fuzz.c |
diff --git a/third_party/afl/src/afl-fuzz.c b/third_party/afl/src/afl-fuzz.c |
index 2d362933aa5c93379f228f2a9238bb477747e571..5ca8c8f02b8f7f3d0a18d3c560f5fd5f895640c9 100644 |
--- a/third_party/afl/src/afl-fuzz.c |
+++ b/third_party/afl/src/afl-fuzz.c |
@@ -60,7 +60,8 @@ |
# include <sys/sysctl.h> |
#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ |
-/* For supporting -Z on systems that have sched_setaffinity. */ |
+/* For systems that have sched_setaffinity; right now just Linux, but one |
+ can hope... */ |
#ifdef __linux__ |
# define HAVE_AFFINITY 1 |
@@ -111,12 +112,12 @@ EXP_ST u8 skip_deterministic, /* Skip deterministic stages? */ |
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 */ |
@@ -134,6 +135,8 @@ EXP_ST u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */ |
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? */ |
@@ -153,6 +156,7 @@ EXP_ST u32 queued_paths, /* Total number of queued testcases */ |
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 */ |
@@ -165,6 +169,7 @@ EXP_ST u64 total_crashes, /* Total number of crashes */ |
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 */ |
@@ -182,6 +187,8 @@ static u8 *stage_name = "init", /* Name of the current fuzz stage */ |
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 */ |
@@ -200,14 +207,11 @@ static u64 total_cal_us, /* Total calibration time (us) */ |
static u64 total_bitmap_size, /* Total bit count for all bitmaps */ |
total_bitmap_entries; /* Number of bitmaps counted */ |
-static u32 cpu_core_count; /* CPU core count */ |
+static s32 cpu_core_count; /* CPU core count */ |
#ifdef HAVE_AFFINITY |
-static u8 use_affinity; /* Using -Z */ |
- |
-static u32 cpu_aff_main, /* Affinity for main process */ |
- cpu_aff_child; /* Affinity for fuzzed child */ |
+static s32 cpu_aff = -1; /* Selected CPU core */ |
#endif /* HAVE_AFFINITY */ |
@@ -340,31 +344,12 @@ static u64 get_cur_time_us(void) { |
} |
-#ifdef HAVE_AFFINITY |
- |
-/* Set CPU affinity (on systems that support it). */ |
- |
-static void set_cpu_affinity(u32 cpu_id) { |
- |
- cpu_set_t c; |
- |
- CPU_ZERO(&c); |
- CPU_SET(cpu_id, &c); |
- |
- if (sched_setaffinity(0, sizeof(c), &c)) |
- PFATAL("sched_setaffinity failed"); |
- |
-} |
- |
-#endif /* HAVE_AFFINITY */ |
- |
- |
/* Generate a random number (from 0 to limit - 1). This may |
have slight bias. */ |
static inline u32 UR(u32 limit) { |
- if (!rand_cnt--) { |
+ if (unlikely(!rand_cnt--)) { |
u32 seed[2]; |
@@ -398,6 +383,122 @@ static void shuffle_ptrs(void** ptrs, u32 cnt) { |
} |
+#ifdef HAVE_AFFINITY |
+ |
+/* Build a list of processes bound to specific cores. Returns -1 if nothing |
+ can be found. Assumes an upper bound of 4k CPUs. */ |
+ |
+static void bind_to_free_cpu(void) { |
+ |
+ DIR* d; |
+ struct dirent* de; |
+ cpu_set_t c; |
+ |
+ u8 cpu_used[4096] = { 0 }; |
+ u32 i; |
+ |
+ if (cpu_core_count < 2) return; |
+ |
+ if (getenv("AFL_NO_AFFINITY")) { |
+ |
+ WARNF("Not binding to a CPU core (AFL_NO_AFFINITY set)."); |
+ return; |
+ |
+ } |
+ |
+ d = opendir("/proc"); |
+ |
+ if (!d) { |
+ |
+ WARNF("Unable to access /proc - can't scan for free CPU cores."); |
+ return; |
+ |
+ } |
+ |
+ ACTF("Checking CPU core loadout..."); |
+ |
+ /* Introduce some jitter, in case multiple AFL tasks are doing the same |
+ thing at the same time... */ |
+ |
+ usleep(R(1000) * 250); |
+ |
+ /* Scan all /proc/<pid>/status entries, checking for Cpus_allowed_list. |
+ Flag all processes bound to a specific CPU using cpu_used[]. This will |
+ fail for some exotic binding setups, but is likely good enough in almost |
+ all real-world use cases. */ |
+ |
+ while ((de = readdir(d))) { |
+ |
+ u8* fn; |
+ FILE* f; |
+ u8 tmp[MAX_LINE]; |
+ u8 has_vmsize = 0; |
+ |
+ if (!isdigit(de->d_name[0])) continue; |
+ |
+ fn = alloc_printf("/proc/%s/status", de->d_name); |
+ |
+ if (!(f = fopen(fn, "r"))) { |
+ ck_free(fn); |
+ continue; |
+ } |
+ |
+ while (fgets(tmp, MAX_LINE, f)) { |
+ |
+ u32 hval; |
+ |
+ /* Processes without VmSize are probably kernel tasks. */ |
+ |
+ if (!strncmp(tmp, "VmSize:\t", 8)) has_vmsize = 1; |
+ |
+ if (!strncmp(tmp, "Cpus_allowed_list:\t", 19) && |
+ !strchr(tmp, '-') && !strchr(tmp, ',') && |
+ sscanf(tmp + 19, "%u", &hval) == 1 && hval < sizeof(cpu_used) && |
+ has_vmsize) { |
+ |
+ cpu_used[hval] = 1; |
+ break; |
+ |
+ } |
+ |
+ } |
+ |
+ ck_free(fn); |
+ fclose(f); |
+ |
+ } |
+ |
+ closedir(d); |
+ |
+ for (i = 0; i < cpu_core_count; i++) if (!cpu_used[i]) break; |
+ |
+ if (i == cpu_core_count) { |
+ |
+ SAYF("\n" cLRD "[-] " cRST |
+ "Uh-oh, looks like all %u CPU cores on your system are allocated to\n" |
+ " other instances of afl-fuzz (or similar CPU-locked tasks). Starting\n" |
+ " another fuzzer on this machine is probably a bad plan, but if you are\n" |
+ " absolutely sure, you can set AFL_NO_AFFINITY and try again.\n", |
+ cpu_core_count); |
+ |
+ FATAL("No more free CPU cores"); |
+ |
+ } |
+ |
+ OKF("Found a free CPU core, binding to #%u.", i); |
+ |
+ cpu_aff = i; |
+ |
+ CPU_ZERO(&c); |
+ CPU_SET(i, &c); |
+ |
+ if (sched_setaffinity(0, sizeof(c), &c)) |
+ PFATAL("sched_setaffinity failed"); |
+ |
+} |
+ |
+#endif /* HAVE_AFFINITY */ |
+ |
#ifndef IGNORE_FINDS |
/* Helper function to compare buffers; returns first and last differing offset. We |
@@ -768,9 +869,6 @@ EXP_ST void read_bitmap(u8* fname) { |
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__ |
@@ -793,53 +891,39 @@ static inline u8 has_new_bits(u8* virgin_map) { |
while (i--) { |
-#ifdef __x86_64__ |
- |
- u64 cur = *current; |
- u64 vir = *virgin; |
- |
-#else |
- |
- u32 cur = *current; |
- u32 vir = *virgin; |
+ /* 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. */ |
-#endif /* ^__x86_64__ */ |
- |
- /* 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; |
} |
@@ -887,6 +971,8 @@ static u32 count_bits(u8* mem) { |
} |
+#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. */ |
@@ -948,21 +1034,11 @@ static u32 count_non_255_bytes(u8* mem) { |
is hit or not. Called on every new crash or hang, should be |
reasonably fast. */ |
-#define AREP4(_sym) (_sym), (_sym), (_sym), (_sym) |
-#define AREP8(_sym) AREP4(_sym), AREP4(_sym) |
-#define AREP16(_sym) AREP8(_sym), AREP8(_sym) |
-#define AREP32(_sym) AREP16(_sym), AREP16(_sym) |
-#define AREP64(_sym) AREP32(_sym), AREP32(_sym) |
-#define AREP128(_sym) AREP64(_sym), AREP64(_sym) |
- |
-static u8 simplify_lookup[256] = { |
- /* 4 */ 1, 128, 128, 128, |
- /* +4 */ AREP4(128), |
- /* +8 */ AREP8(128), |
- /* +16 */ AREP16(128), |
- /* +32 */ AREP32(128), |
- /* +64 */ AREP64(128), |
- /* +128 */ AREP128(128) |
+static const u8 simplify_lookup[256] = { |
+ |
+ [0] = 1, |
+ [1 ... 255] = 128 |
+ |
}; |
#ifdef __x86_64__ |
@@ -975,7 +1051,7 @@ static void simplify_trace(u64* mem) { |
/* Optimize for sparse bitmaps. */ |
- if (*mem) { |
+ if (unlikely(*mem)) { |
u8* mem8 = (u8*)mem; |
@@ -1006,7 +1082,7 @@ static void simplify_trace(u32* mem) { |
/* Optimize for sparse bitmaps. */ |
- if (*mem) { |
+ if (unlikely(*mem)) { |
u8* mem8 = (u8*)mem; |
@@ -1029,17 +1105,36 @@ static void simplify_trace(u32* mem) { |
preprocessing step for any newly acquired traces. Called on every exec, |
must be fast. */ |
-static u8 count_class_lookup[256] = { |
+static const u8 count_class_lookup8[256] = { |
- /* 0 - 3: 4 */ 0, 1, 2, 4, |
- /* 4 - 7: +4 */ AREP4(8), |
- /* 8 - 15: +8 */ AREP8(16), |
- /* 16 - 31: +16 */ AREP16(32), |
- /* 32 - 127: +96 */ AREP64(64), AREP32(64), |
- /* 128+: +128 */ AREP128(128) |
+ [0] = 0, |
+ [1] = 1, |
+ [2] = 2, |
+ [3] = 4, |
+ [4 ... 7] = 8, |
+ [8 ... 15] = 16, |
+ [16 ... 31] = 32, |
+ [32 ... 127] = 64, |
+ [128 ... 255] = 128 |
}; |
+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) { |
@@ -1050,18 +1145,14 @@ static inline void classify_counts(u64* mem) { |
/* 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]]; |
} |
@@ -1081,14 +1172,12 @@ static inline void classify_counts(u32* mem) { |
/* 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]]; |
} |
@@ -1897,10 +1986,6 @@ EXP_ST void init_forkserver(char** argv) { |
struct rlimit r; |
-#ifdef HAVE_AFFINITY |
- if (use_affinity) set_cpu_affinity(cpu_aff_child); |
-#endif /* HAVE_AFFINITY */ |
- |
/* Umpf. On OpenBSD, the default fd limit for root users is set to |
soft 128. Let's try to fix that... */ |
@@ -2199,10 +2284,6 @@ static u8 run_target(char** argv) { |
struct rlimit r; |
-#ifdef HAVE_AFFINITY |
- if (use_affinity) set_cpu_affinity(cpu_aff_child); |
-#endif /* HAVE_AFFINITY */ |
- |
if (mem_limit) { |
r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; |
@@ -2321,7 +2402,8 @@ static u8 run_target(char** argv) { |
} |
- child_pid = 0; |
+ if (!WIFSTOPPED(status)) child_pid = 0; |
+ |
it.it_value.tv_sec = 0; |
it.it_value.tv_usec = 0; |
@@ -2440,7 +2522,11 @@ static void show_stats(void); |
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; |
@@ -2457,7 +2543,7 @@ static u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem, |
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. */ |
@@ -2465,6 +2551,8 @@ static u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem, |
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++) { |
@@ -2494,12 +2582,29 @@ static u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem, |
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); |
+ |
+ } |
} |
@@ -2538,9 +2643,15 @@ abort_calibration: |
/* 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; |
@@ -3129,6 +3240,7 @@ static u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) { |
unique_crashes++; |
last_crash_time = get_cur_time(); |
+ last_crash_execs = total_execs; |
break; |
@@ -3226,9 +3338,9 @@ static void find_timeout(void) { |
/* 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; |
@@ -3247,46 +3359,51 @@ static void write_stats_file(double bitmap_cvg, double eps) { |
/* 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); |
@@ -3709,7 +3826,7 @@ static void show_stats(void) { |
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; |
@@ -3762,12 +3879,17 @@ static void show_stats(void) { |
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(); |
@@ -3929,8 +4051,8 @@ static void show_stats(void) { |
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); |
@@ -4074,9 +4196,14 @@ static void show_stats(void) { |
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 < 85 && var_byte_count > 40) |
+ ? cLRD : ((queued_variable && (!persistent_mode || var_byte_count > 20)) |
+ ? cMGN : cRST), tmp); |
if (!bytes_trim_out) { |
@@ -4132,10 +4259,10 @@ static void show_stats(void) { |
#ifdef HAVE_AFFINITY |
- if (use_affinity) { |
+ if (cpu_aff >= 0) { |
- SAYF(SP10 cGRA "[cpu@%02u:%s%3u%%" cGRA "]\r" cRST, |
- MIN(cpu_aff_child, 99), cpu_color, |
+ SAYF(SP10 cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, |
+ MIN(cpu_aff, 999), cpu_color, |
MIN(cur_utilization, 999)); |
} else { |
@@ -4144,6 +4271,7 @@ static void show_stats(void) { |
cpu_color, MIN(cur_utilization, 999)); |
} |
+ |
#else |
SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, |
@@ -4886,6 +5014,12 @@ static u8 fuzz_one(char** argv) { |
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) * |
*********************************************/ |
@@ -5055,7 +5189,7 @@ static u8 fuzz_one(char** argv) { |
/* 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. |
*/ |
@@ -6486,8 +6620,14 @@ static void sync_fuzzers(char** argv) { |
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"); |
@@ -6721,7 +6861,7 @@ EXP_ST void check_binary(u8* fname) { |
OKF(cPIN "Persistent mode binary detected."); |
setenv(PERSIST_ENV_VAR, "1", 1); |
- no_var_check = 1; |
+ persistent_mode = 1; |
} else if (getenv("AFL_PERSISTENT")) { |
@@ -6838,9 +6978,6 @@ static void usage(u8* argv0) { |
" -T text - text banner to show on the screen\n" |
" -M / -S id - distributed mode (see parallel_fuzzing.txt)\n" |
-#ifdef HAVE_AFFINITY |
- " -Z core_id - set CPU affinity (see perf_tips.txt)\n" |
-#endif /* HAVE_AFFINITY */ |
" -C - crash exploration mode (the peruvian rabbit thing)\n\n" |
"For additional tips, please consult %s/README.\n\n", |
@@ -7138,27 +7275,27 @@ static void get_core_count(void) { |
#else |
- if (!cpu_core_count) { |
+#ifdef HAVE_AFFINITY |
- /* On Linux, a simple way is to look at /proc/stat, especially since we'd |
- be parsing it anyway for other reasons later on. But do this only if |
- cpu_core_count hasn't been obtained before as a result of specifying |
- -Z. */ |
+ cpu_core_count = sysconf(_SC_NPROCESSORS_ONLN); |
- FILE* f = fopen("/proc/stat", "r"); |
- u8 tmp[1024]; |
+#else |
- if (!f) return; |
+ FILE* f = fopen("/proc/stat", "r"); |
+ u8 tmp[1024]; |
- while (fgets(tmp, sizeof(tmp), f)) |
- if (!strncmp(tmp, "cpu", 3) && isdigit(tmp[3])) cpu_core_count++; |
+ if (!f) return; |
- fclose(f); |
- } |
+ while (fgets(tmp, sizeof(tmp), f)) |
+ if (!strncmp(tmp, "cpu", 3) && isdigit(tmp[3])) cpu_core_count++; |
+ |
+ fclose(f); |
+ |
+#endif /* ^HAVE_AFFINITY */ |
#endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__) */ |
- if (cpu_core_count) { |
+ if (cpu_core_count > 0) { |
cur_runnable = (u32)get_runnable_processes(); |
@@ -7187,17 +7324,12 @@ static void get_core_count(void) { |
} |
- } else WARNF("Unable to figure out the number of CPU cores."); |
- |
-#ifdef HAVE_AFFINITY |
+ } else { |
- if (use_affinity) |
- OKF("Using specified CPU affinity: main = %u, child = %u", |
- cpu_aff_main, cpu_aff_child); |
- else if (cpu_core_count > 1) |
- OKF(cBRI "Try setting CPU affinity (-Z) for a performance boost!" cRST); |
+ cpu_core_count = 0; |
+ WARNF("Unable to figure out the number of CPU cores."); |
-#endif /* HAVE_AFFINITY */ |
+ } |
} |
@@ -7483,18 +7615,23 @@ int main(int argc, char** argv) { |
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; |
- while ((opt = getopt(argc, argv, "+i:o:f:m:t:T:dnCB:S:M:x:QZ:")) > 0) |
+ 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; |
@@ -7509,12 +7646,30 @@ int main(int argc, char** argv) { |
out_dir = optarg; |
break; |
- case 'M': |
+ case 'M': { /* master 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; |
- force_deterministic = 1; |
- /* Fall through */ |
+ 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"); |
- case 'S': /* sync ID */ |
+ } |
+ |
+ force_deterministic = 1; |
+ |
+ } |
+ |
+ break; |
+ |
+ case 'S': |
if (sync_id) FATAL("Multiple -S or -M options not supported"); |
sync_id = optarg; |
@@ -7526,13 +7681,13 @@ int main(int argc, char** argv) { |
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; |
@@ -7549,7 +7704,7 @@ int main(int argc, char** argv) { |
} |
- case 'm': { |
+ case 'm': { /* mem limit */ |
u8 suffix = 'M'; |
@@ -7586,43 +7741,14 @@ int main(int argc, char** argv) { |
break; |
-#ifdef HAVE_AFFINITY |
- |
- case 'Z': { |
- |
- s32 i; |
- |
- if (use_affinity) FATAL("Multiple -Z options not supported"); |
- use_affinity = 1; |
- |
- cpu_core_count = sysconf(_SC_NPROCESSORS_ONLN); |
- |
- i = sscanf(optarg, "%u,%u", &cpu_aff_main, &cpu_aff_child); |
- |
- if (i < 1 || cpu_aff_main >= cpu_core_count) |
- FATAL("Bogus primary core ID passed to -Z (expected 0-%u)", |
- cpu_core_count - 1); |
- |
- if (i == 1) cpu_aff_child = cpu_aff_main; |
- |
- if (cpu_aff_child >= cpu_core_count) |
- FATAL("Bogus secondary core ID passed to -Z (expected 0-%u)", |
- cpu_core_count - 1); |
- |
- break; |
- |
- } |
- |
-#endif /* HAVE_AFFINITY */ |
- |
- 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 |
@@ -7641,26 +7767,26 @@ int main(int argc, char** argv) { |
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; |
@@ -7680,10 +7806,6 @@ int main(int argc, char** argv) { |
setup_signal_handlers(); |
check_asan_opts(); |
-#ifdef HAVE_AFFINITY |
- if (use_affinity) set_cpu_affinity(cpu_aff_main); |
-#endif /* HAVE_AFFINITY */ |
- |
if (sync_id) fix_up_sync(); |
if (!strcmp(in_dir, out_dir)) |
@@ -7698,14 +7820,18 @@ int main(int argc, char** argv) { |
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) |
FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); |
+ if (getenv("AFL_PRELOAD")) { |
+ setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); |
+ setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); |
+ } |
+ |
if (getenv("AFL_LD_PRELOAD")) |
- setenv("LD_PRELOAD", getenv("AFL_LD_PRELOAD"), 1); |
+ FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD"); |
save_cmdline(argc, argv); |
@@ -7714,11 +7840,17 @@ int main(int argc, char** argv) { |
check_if_tty(); |
get_core_count(); |
+ |
+#ifdef HAVE_AFFINITY |
+ bind_to_free_cpu(); |
+#endif /* HAVE_AFFINITY */ |
+ |
check_crash_handling(); |
check_cpu_governor(); |
setup_post(); |
setup_shm(); |
+ init_count_class16(); |
setup_dirs_fds(); |
read_testcases(); |
@@ -7751,7 +7883,7 @@ int main(int argc, char** argv) { |
seek_to = find_start_position(); |
- write_stats_file(0, 0); |
+ write_stats_file(0, 0, 0); |
save_auto(); |
if (stop_soon) goto stop_fuzzing; |
@@ -7827,13 +7959,13 @@ int main(int argc, char** argv) { |
if (queue_cur) show_stats(); |
write_bitmap(); |
- write_stats_file(0, 0); |
+ write_stats_file(0, 0, 0); |
save_auto(); |
stop_fuzzing: |
SAYF(CURSOR_SHOW cLRD "\n\n+++ Testing aborted %s +++\n" cRST, |
- stop_soon == 2 ? "programatically" : "by user"); |
+ stop_soon == 2 ? "programmatically" : "by user"); |
/* Running for more than 30 minutes but still doing first cycle? */ |