run code formatter

This commit is contained in:
Andrea Fioraldi
2019-09-02 18:49:43 +02:00
parent 2ae4ca91b4
commit b24639d011
57 changed files with 8674 additions and 7125 deletions

View File

@ -159,8 +159,8 @@ afl-gotcpu: src/afl-gotcpu.c $(COMM_HDR) | test_x86
code-format: code-format:
./.custom-format.py -i src/* ./.custom-format.py -i src/*.c
./.custom-format.py -i include/* ./.custom-format.py -i include/*.h
./.custom-format.py -i libdislocator/*.c ./.custom-format.py -i libdislocator/*.c
./.custom-format.py -i libtokencap/*.c ./.custom-format.py -i libtokencap/*.c
./.custom-format.py -i llvm_mode/*.c ./.custom-format.py -i llvm_mode/*.c

View File

@ -37,7 +37,7 @@
#include "config.h" #include "config.h"
#include "types.h" #include "types.h"
/* /*
------------------ ------------------
Performances notes Performances notes
------------------ ------------------
@ -106,47 +106,47 @@
static const u8* trampoline_fmt_32 = static const u8* trampoline_fmt_32 =
"\n" "\n"
"/* --- AFL TRAMPOLINE (32-BIT) --- */\n" "/* --- AFL TRAMPOLINE (32-BIT) --- */\n"
"\n" "\n"
".align 4\n" ".align 4\n"
"\n" "\n"
"leal -16(%%esp), %%esp\n" "leal -16(%%esp), %%esp\n"
"movl %%edi, 0(%%esp)\n" "movl %%edi, 0(%%esp)\n"
"movl %%edx, 4(%%esp)\n" "movl %%edx, 4(%%esp)\n"
"movl %%ecx, 8(%%esp)\n" "movl %%ecx, 8(%%esp)\n"
"movl %%eax, 12(%%esp)\n" "movl %%eax, 12(%%esp)\n"
"movl $0x%08x, %%ecx\n" "movl $0x%08x, %%ecx\n"
"call __afl_maybe_log\n" "call __afl_maybe_log\n"
"movl 12(%%esp), %%eax\n" "movl 12(%%esp), %%eax\n"
"movl 8(%%esp), %%ecx\n" "movl 8(%%esp), %%ecx\n"
"movl 4(%%esp), %%edx\n" "movl 4(%%esp), %%edx\n"
"movl 0(%%esp), %%edi\n" "movl 0(%%esp), %%edi\n"
"leal 16(%%esp), %%esp\n" "leal 16(%%esp), %%esp\n"
"\n" "\n"
"/* --- END --- */\n" "/* --- END --- */\n"
"\n"; "\n";
static const u8* trampoline_fmt_64 = static const u8* trampoline_fmt_64 =
"\n" "\n"
"/* --- AFL TRAMPOLINE (64-BIT) --- */\n" "/* --- AFL TRAMPOLINE (64-BIT) --- */\n"
"\n" "\n"
".align 4\n" ".align 4\n"
"\n" "\n"
"leaq -(128+24)(%%rsp), %%rsp\n" "leaq -(128+24)(%%rsp), %%rsp\n"
"movq %%rdx, 0(%%rsp)\n" "movq %%rdx, 0(%%rsp)\n"
"movq %%rcx, 8(%%rsp)\n" "movq %%rcx, 8(%%rsp)\n"
"movq %%rax, 16(%%rsp)\n" "movq %%rax, 16(%%rsp)\n"
"movq $0x%08x, %%rcx\n" "movq $0x%08x, %%rcx\n"
"call __afl_maybe_log\n" "call __afl_maybe_log\n"
"movq 16(%%rsp), %%rax\n" "movq 16(%%rsp), %%rax\n"
"movq 8(%%rsp), %%rcx\n" "movq 8(%%rsp), %%rcx\n"
"movq 0(%%rsp), %%rdx\n" "movq 0(%%rsp), %%rdx\n"
"leaq (128+24)(%%rsp), %%rsp\n" "leaq (128+24)(%%rsp), %%rsp\n"
"\n" "\n"
"/* --- END --- */\n" "/* --- END --- */\n"
"\n"; "\n";
static const u8* main_payload_32 = static const u8* main_payload_32 =
@ -398,9 +398,9 @@ static const u8* main_payload_32 =
recognize .string. */ recognize .string. */
#ifdef __APPLE__ #ifdef __APPLE__
# define CALL_L64(str) "call _" str "\n" # define CALL_L64(str) "call _" str "\n"
#else #else
# define CALL_L64(str) "call " str "@PLT\n" # define CALL_L64(str) "call " str "@PLT\n"
#endif /* ^__APPLE__ */ #endif /* ^__APPLE__ */
static const u8* main_payload_64 = static const u8* main_payload_64 =
@ -415,7 +415,7 @@ static const u8* main_payload_64 =
"\n" "\n"
"__afl_maybe_log:\n" "__afl_maybe_log:\n"
"\n" "\n"
#if defined(__OpenBSD__) || (defined(__FreeBSD__) && (__FreeBSD__ < 9)) #if defined(__OpenBSD__) || (defined(__FreeBSD__) && (__FreeBSD__ < 9))
" .byte 0x9f /* lahf */\n" " .byte 0x9f /* lahf */\n"
#else #else
" lahf\n" " lahf\n"
@ -448,7 +448,7 @@ static const u8* main_payload_64 =
"__afl_return:\n" "__afl_return:\n"
"\n" "\n"
" addb $127, %al\n" " addb $127, %al\n"
#if defined(__OpenBSD__) || (defined(__FreeBSD__) && (__FreeBSD__ < 9)) #if defined(__OpenBSD__) || (defined(__FreeBSD__) && (__FreeBSD__ < 9))
" .byte 0x9e /* sahf */\n" " .byte 0x9e /* sahf */\n"
#else #else
" sahf\n" " sahf\n"
@ -737,9 +737,9 @@ static const u8* main_payload_64 =
#ifdef __APPLE__ #ifdef __APPLE__
" .comm __afl_area_ptr, 8\n" " .comm __afl_area_ptr, 8\n"
#ifndef COVERAGE_ONLY # ifndef COVERAGE_ONLY
" .comm __afl_prev_loc, 8\n" " .comm __afl_prev_loc, 8\n"
#endif /* !COVERAGE_ONLY */ # endif /* !COVERAGE_ONLY */
" .comm __afl_fork_pid, 4\n" " .comm __afl_fork_pid, 4\n"
" .comm __afl_temp, 4\n" " .comm __afl_temp, 4\n"
" .comm __afl_setup_failure, 1\n" " .comm __afl_setup_failure, 1\n"
@ -747,9 +747,9 @@ static const u8* main_payload_64 =
#else #else
" .lcomm __afl_area_ptr, 8\n" " .lcomm __afl_area_ptr, 8\n"
#ifndef COVERAGE_ONLY # ifndef COVERAGE_ONLY
" .lcomm __afl_prev_loc, 8\n" " .lcomm __afl_prev_loc, 8\n"
#endif /* !COVERAGE_ONLY */ # endif /* !COVERAGE_ONLY */
" .lcomm __afl_fork_pid, 4\n" " .lcomm __afl_fork_pid, 4\n"
" .lcomm __afl_temp, 4\n" " .lcomm __afl_temp, 4\n"
" .lcomm __afl_setup_failure, 1\n" " .lcomm __afl_setup_failure, 1\n"
@ -765,3 +765,4 @@ static const u8* main_payload_64 =
"\n"; "\n";
#endif /* !_HAVE_AFL_AS_H */ #endif /* !_HAVE_AFL_AS_H */

View File

@ -27,12 +27,12 @@
#define MESSAGES_TO_STDOUT #define MESSAGES_TO_STDOUT
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE # define _GNU_SOURCE
#endif #endif
#define _FILE_OFFSET_BITS 64 #define _FILE_OFFSET_BITS 64
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "android-ashmem.h" # include "android-ashmem.h"
#endif #endif
#include "config.h" #include "config.h"
@ -68,7 +68,7 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/file.h> #include <sys/file.h>
#if defined(__APPLE__) || defined(__FreeBSD__) || defined (__OpenBSD__) #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
# include <sys/sysctl.h> # include <sys/sysctl.h>
# define HAVE_ARC4RANDOM 1 # define HAVE_ARC4RANDOM 1
#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ #endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */
@ -88,45 +88,47 @@
struct queue_entry { struct queue_entry {
u8* fname; /* File name for the test case */ u8* fname; /* File name for the test case */
u32 len; /* Input length */ u32 len; /* Input length */
u8 cal_failed, /* Calibration failed? */ u8 cal_failed, /* Calibration failed? */
trim_done, /* Trimmed? */ trim_done, /* Trimmed? */
was_fuzzed, /* historical, but needed for MOpt */ was_fuzzed, /* historical, but needed for MOpt */
passed_det, /* Deterministic stages passed? */ passed_det, /* Deterministic stages passed? */
has_new_cov, /* Triggers new coverage? */ has_new_cov, /* Triggers new coverage? */
var_behavior, /* Variable behavior? */ var_behavior, /* Variable behavior? */
favored, /* Currently favored? */ favored, /* Currently favored? */
fs_redundant; /* Marked as redundant in the fs? */ fs_redundant; /* Marked as redundant in the fs? */
u32 bitmap_size, /* Number of bits set in bitmap */ u32 bitmap_size, /* Number of bits set in bitmap */
fuzz_level, /* Number of fuzzing iterations */ fuzz_level, /* Number of fuzzing iterations */
exec_cksum; /* Checksum of the execution trace */ exec_cksum; /* Checksum of the execution trace */
u64 exec_us, /* Execution time (us) */ u64 exec_us, /* Execution time (us) */
handicap, /* Number of queue cycles behind */ handicap, /* Number of queue cycles behind */
n_fuzz, /* Number of fuzz, does not overflow */ n_fuzz, /* Number of fuzz, does not overflow */
depth; /* Path depth */ depth; /* Path depth */
u8* trace_mini; /* Trace bytes, if kept */ u8* trace_mini; /* Trace bytes, if kept */
u32 tc_ref; /* Trace bytes ref count */ u32 tc_ref; /* Trace bytes ref count */
struct queue_entry *next, /* Next element, if any */ struct queue_entry *next, /* Next element, if any */
*next_100; /* 100 elements ahead */ *next_100; /* 100 elements ahead */
}; };
struct extra_data { struct extra_data {
u8* data; /* Dictionary token data */
u32 len; /* Dictionary token length */
u32 hit_cnt; /* Use count in the corpus */
};
u8* data; /* Dictionary token data */
u32 len; /* Dictionary token length */
u32 hit_cnt; /* Use count in the corpus */
};
/* Fuzzing stages */ /* Fuzzing stages */
enum { enum {
/* 00 */ STAGE_FLIP1, /* 00 */ STAGE_FLIP1,
/* 01 */ STAGE_FLIP2, /* 01 */ STAGE_FLIP2,
/* 02 */ STAGE_FLIP4, /* 02 */ STAGE_FLIP4,
@ -146,72 +148,60 @@ enum {
/* 16 */ STAGE_SPLICE, /* 16 */ STAGE_SPLICE,
/* 17 */ STAGE_PYTHON, /* 17 */ STAGE_PYTHON,
/* 18 */ STAGE_CUSTOM_MUTATOR /* 18 */ STAGE_CUSTOM_MUTATOR
}; };
/* Stage value types */ /* Stage value types */
enum { enum {
/* 00 */ STAGE_VAL_NONE, /* 00 */ STAGE_VAL_NONE,
/* 01 */ STAGE_VAL_LE, /* 01 */ STAGE_VAL_LE,
/* 02 */ STAGE_VAL_BE /* 02 */ STAGE_VAL_BE
}; };
/* Execution status fault codes */ /* Execution status fault codes */
enum { enum {
/* 00 */ FAULT_NONE, /* 00 */ FAULT_NONE,
/* 01 */ FAULT_TMOUT, /* 01 */ FAULT_TMOUT,
/* 02 */ FAULT_CRASH, /* 02 */ FAULT_CRASH,
/* 03 */ FAULT_ERROR, /* 03 */ FAULT_ERROR,
/* 04 */ FAULT_NOINST, /* 04 */ FAULT_NOINST,
/* 05 */ FAULT_NOBITS /* 05 */ FAULT_NOBITS
};
};
/* MOpt: /* MOpt:
Lots of globals, but mostly for the status UI and other things where it Lots of globals, but mostly for the status UI and other things where it
really makes no sense to haul them around as function parameters. */ really makes no sense to haul them around as function parameters. */
extern u64 limit_time_puppet, extern u64 limit_time_puppet, orig_hit_cnt_puppet, last_limit_time_start,
orig_hit_cnt_puppet, tmp_pilot_time, total_pacemaker_time, total_puppet_find, temp_puppet_find,
last_limit_time_start, most_time_key, most_time, most_execs_key, most_execs, old_hit_count;
tmp_pilot_time,
total_pacemaker_time,
total_puppet_find,
temp_puppet_find,
most_time_key,
most_time,
most_execs_key,
most_execs,
old_hit_count;
extern s32 SPLICE_CYCLES_puppet, extern s32 SPLICE_CYCLES_puppet, limit_time_sig, key_puppet, key_module;
limit_time_sig,
key_puppet,
key_module;
extern double w_init, extern double w_init, w_end, w_now;
w_end,
w_now;
extern s32 g_now; extern s32 g_now;
extern s32 g_max; extern s32 g_max;
#define operator_num 16 #define operator_num 16
#define swarm_num 5 #define swarm_num 5
#define period_core 500000 #define period_core 500000
extern u64 tmp_core_time; extern u64 tmp_core_time;
extern s32 swarm_now; extern s32 swarm_now;
extern double x_now[swarm_num][operator_num], extern double x_now[swarm_num][operator_num], L_best[swarm_num][operator_num],
L_best[swarm_num][operator_num], eff_best[swarm_num][operator_num], G_best[operator_num],
eff_best[swarm_num][operator_num], v_now[swarm_num][operator_num], probability_now[swarm_num][operator_num],
G_best[operator_num], swarm_fitness[swarm_num];
v_now[swarm_num][operator_num],
probability_now[swarm_num][operator_num],
swarm_fitness[swarm_num];
extern u64 stage_finds_puppet[swarm_num][operator_num], /* Patterns found per fuzz stage */ extern u64 stage_finds_puppet[swarm_num][operator_num], /* Patterns found per
fuzz stage */
stage_finds_puppet_v2[swarm_num][operator_num], stage_finds_puppet_v2[swarm_num][operator_num],
stage_cycles_puppet_v2[swarm_num][operator_num], stage_cycles_puppet_v2[swarm_num][operator_num],
stage_cycles_puppet_v3[swarm_num][operator_num], stage_cycles_puppet_v3[swarm_num][operator_num],
@ -221,9 +211,9 @@ extern u64 stage_finds_puppet[swarm_num][operator_num], /* Patterns fo
core_operator_finds_puppet_v2[operator_num], core_operator_finds_puppet_v2[operator_num],
core_operator_cycles_puppet[operator_num], core_operator_cycles_puppet[operator_num],
core_operator_cycles_puppet_v2[operator_num], core_operator_cycles_puppet_v2[operator_num],
core_operator_cycles_puppet_v3[operator_num]; /* Execs per fuzz stage */ core_operator_cycles_puppet_v3[operator_num]; /* Execs per fuzz stage */
#define RAND_C (rand()%1000*0.001) #define RAND_C (rand() % 1000 * 0.001)
#define v_max 1 #define v_max 1
#define v_min 0.05 #define v_min 0.05
#define limit_time_bound 1.1 #define limit_time_bound 1.1
@ -236,225 +226,228 @@ extern u64 stage_finds_puppet[swarm_num][operator_num], /* Patterns fo
#define period_pilot 50000 #define period_pilot 50000
extern double period_pilot_tmp; extern double period_pilot_tmp;
extern s32 key_lv; extern s32 key_lv;
extern u8 *in_dir, /* Input directory with test cases */ extern u8 *in_dir, /* Input directory with test cases */
*out_dir, /* Working & output directory */ *out_dir, /* Working & output directory */
*tmp_dir , /* Temporary directory for input */ *tmp_dir, /* Temporary directory for input */
*sync_dir, /* Synchronization directory */ *sync_dir, /* Synchronization directory */
*sync_id, /* Fuzzer ID */ *sync_id, /* Fuzzer ID */
*power_name, /* Power schedule name */ *power_name, /* Power schedule name */
*use_banner, /* Display banner */ *use_banner, /* Display banner */
*in_bitmap, /* Input bitmap */ *in_bitmap, /* Input bitmap */
*file_extension, /* File extension */ *file_extension, /* File extension */
*orig_cmdline; /* Original command line */ *orig_cmdline; /* Original command line */
extern u8 *doc_path, /* Path to documentation dir */ extern u8 *doc_path, /* Path to documentation dir */
*target_path, /* Path to target binary */ *target_path, /* Path to target binary */
*out_file; /* File to fuzz, if any */ *out_file; /* File to fuzz, if any */
extern u32 exec_tmout; /* Configurable exec timeout (ms) */ extern u32 exec_tmout; /* Configurable exec timeout (ms) */
extern u32 hang_tmout; /* Timeout used for hang det (ms) */ extern u32 hang_tmout; /* Timeout used for hang det (ms) */
extern u64 mem_limit; /* Memory cap for child (MB) */ extern u64 mem_limit; /* Memory cap for child (MB) */
extern u8 cal_cycles, /* Calibration cycles defaults */ extern u8 cal_cycles, /* Calibration cycles defaults */
cal_cycles_long, cal_cycles_long, debug, /* Debug mode */
debug, /* Debug mode */ python_only; /* Python-only mode */
python_only; /* Python-only mode */
extern u32 stats_update_freq; /* Stats update frequency (execs) */ extern u32 stats_update_freq; /* Stats update frequency (execs) */
enum { enum {
/* 00 */ EXPLORE, /* AFL default, Exploration-based constant schedule */
/* 01 */ FAST, /* Exponential schedule */ /* 00 */ EXPLORE, /* AFL default, Exploration-based constant schedule */
/* 02 */ COE, /* Cut-Off Exponential schedule */ /* 01 */ FAST, /* Exponential schedule */
/* 03 */ LIN, /* Linear schedule */ /* 02 */ COE, /* Cut-Off Exponential schedule */
/* 04 */ QUAD, /* Quadratic schedule */ /* 03 */ LIN, /* Linear schedule */
/* 05 */ EXPLOIT, /* AFL's exploitation-based const. */ /* 04 */ QUAD, /* Quadratic schedule */
/* 05 */ EXPLOIT, /* AFL's exploitation-based const. */
POWER_SCHEDULES_NUM POWER_SCHEDULES_NUM
}; };
extern char *power_names[POWER_SCHEDULES_NUM]; extern char* power_names[POWER_SCHEDULES_NUM];
extern u8 schedule; /* Power schedule (default: EXPLORE)*/ extern u8 schedule; /* Power schedule (default: EXPLORE)*/
extern u8 havoc_max_mult; extern u8 havoc_max_mult;
extern u8 skip_deterministic, /* Skip deterministic stages? */ extern u8 skip_deterministic, /* Skip deterministic stages? */
force_deterministic, /* Force deterministic stages? */ force_deterministic, /* Force deterministic stages? */
use_splicing, /* Recombine input files? */ use_splicing, /* Recombine input files? */
dumb_mode, /* Run in non-instrumented mode? */ dumb_mode, /* Run in non-instrumented mode? */
score_changed, /* Scoring for favorites changed? */ score_changed, /* Scoring for favorites changed? */
kill_signal, /* Signal that killed the child */ kill_signal, /* Signal that killed the child */
resuming_fuzz, /* Resuming an older fuzzing job? */ resuming_fuzz, /* Resuming an older fuzzing job? */
timeout_given, /* Specific timeout given? */ timeout_given, /* Specific timeout given? */
not_on_tty, /* stdout is not a tty */ not_on_tty, /* stdout is not a tty */
term_too_small, /* terminal dimensions too small */ term_too_small, /* terminal dimensions too small */
no_forkserver, /* Disable forkserver? */ no_forkserver, /* Disable forkserver? */
crash_mode, /* Crash mode! Yeah! */ crash_mode, /* Crash mode! Yeah! */
in_place_resume, /* Attempt in-place resume? */ in_place_resume, /* Attempt in-place resume? */
auto_changed, /* Auto-generated tokens changed? */ auto_changed, /* Auto-generated tokens changed? */
no_cpu_meter_red, /* Feng shui on the status screen */ no_cpu_meter_red, /* Feng shui on the status screen */
no_arith, /* Skip most arithmetic ops */ no_arith, /* Skip most arithmetic ops */
shuffle_queue, /* Shuffle input queue? */ shuffle_queue, /* Shuffle input queue? */
bitmap_changed, /* Time to update bitmap? */ bitmap_changed, /* Time to update bitmap? */
qemu_mode, /* Running in QEMU mode? */ qemu_mode, /* Running in QEMU mode? */
unicorn_mode, /* Running in Unicorn mode? */ unicorn_mode, /* Running in Unicorn mode? */
skip_requested, /* Skip request, via SIGUSR1 */ 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? */ persistent_mode, /* Running in persistent mode? */
deferred_mode, /* Deferred forkserver mode? */ deferred_mode, /* Deferred forkserver mode? */
fixed_seed, /* do not reseed */ fixed_seed, /* do not reseed */
fast_cal, /* Try to calibrate faster? */ fast_cal, /* Try to calibrate faster? */
uses_asan; /* Target uses ASAN? */ uses_asan; /* Target uses ASAN? */
extern s32 out_fd, /* Persistent fd for out_file */ extern s32 out_fd, /* Persistent fd for out_file */
#ifndef HAVE_ARC4RANDOM #ifndef HAVE_ARC4RANDOM
dev_urandom_fd, /* Persistent fd for /dev/urandom */ dev_urandom_fd, /* Persistent fd for /dev/urandom */
#endif #endif
dev_null_fd, /* Persistent fd for /dev/null */ dev_null_fd, /* Persistent fd for /dev/null */
fsrv_ctl_fd, /* Fork server control pipe (write) */ fsrv_ctl_fd, /* Fork server control pipe (write) */
fsrv_st_fd; /* Fork server status pipe (read) */ fsrv_st_fd; /* Fork server status pipe (read) */
extern s32 forksrv_pid, /* PID of the fork server */ extern s32 forksrv_pid, /* PID of the fork server */
child_pid, /* PID of the fuzzed program */ child_pid, /* PID of the fuzzed program */
out_dir_fd; /* FD of the lock file */ out_dir_fd; /* FD of the lock file */
extern u8* trace_bits; /* SHM with instrumentation bitmap */ extern u8* trace_bits; /* SHM with instrumentation bitmap */
extern u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */ extern u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */
virgin_tmout[MAP_SIZE], /* Bits we haven't seen in tmouts */ virgin_tmout[MAP_SIZE], /* Bits we haven't seen in tmouts */
virgin_crash[MAP_SIZE]; /* Bits we haven't seen in crashes */ virgin_crash[MAP_SIZE]; /* Bits we haven't seen in crashes */
extern u8 var_bytes[MAP_SIZE]; /* Bytes that appear to be variable */ extern u8 var_bytes[MAP_SIZE]; /* Bytes that appear to be variable */
extern volatile u8 stop_soon, /* Ctrl-C pressed? */ extern volatile u8 stop_soon, /* Ctrl-C pressed? */
clear_screen, /* Window resized? */ clear_screen, /* Window resized? */
child_timed_out; /* Traced process timed out? */ child_timed_out; /* Traced process timed out? */
extern u32 queued_paths, /* Total number of queued testcases */ extern u32 queued_paths, /* Total number of queued testcases */
queued_variable, /* Testcases with variable behavior */ queued_variable, /* Testcases with variable behavior */
queued_at_start, /* Total number of initial inputs */ queued_at_start, /* Total number of initial inputs */
queued_discovered, /* Items discovered during this run */ queued_discovered, /* Items discovered during this run */
queued_imported, /* Items imported via -S */ queued_imported, /* Items imported via -S */
queued_favored, /* Paths deemed favorable */ queued_favored, /* Paths deemed favorable */
queued_with_cov, /* Paths with new coverage bytes */ queued_with_cov, /* Paths with new coverage bytes */
pending_not_fuzzed, /* Queued but not done yet */ pending_not_fuzzed, /* Queued but not done yet */
pending_favored, /* Pending favored paths */ pending_favored, /* Pending favored paths */
cur_skipped_paths, /* Abandoned inputs in cur cycle */ cur_skipped_paths, /* Abandoned inputs in cur cycle */
cur_depth, /* Current path depth */ cur_depth, /* Current path depth */
max_depth, /* Max path depth */ max_depth, /* Max path depth */
useless_at_start, /* Number of useless starting paths */ useless_at_start, /* Number of useless starting paths */
var_byte_count, /* Bitmap bytes with var behavior */ var_byte_count, /* Bitmap bytes with var behavior */
current_entry, /* Current queue entry ID */ current_entry, /* Current queue entry ID */
havoc_div; /* Cycle count divisor for havoc */ havoc_div; /* Cycle count divisor for havoc */
extern u64 total_crashes, /* Total number of crashes */ extern u64 total_crashes, /* Total number of crashes */
unique_crashes, /* Crashes with unique signatures */ unique_crashes, /* Crashes with unique signatures */
total_tmouts, /* Total number of timeouts */ total_tmouts, /* Total number of timeouts */
unique_tmouts, /* Timeouts with unique signatures */ unique_tmouts, /* Timeouts with unique signatures */
unique_hangs, /* Hangs with unique signatures */ unique_hangs, /* Hangs with unique signatures */
total_execs, /* Total execve() calls */ total_execs, /* Total execve() calls */
slowest_exec_ms, /* Slowest testcase non hang in ms */ slowest_exec_ms, /* Slowest testcase non hang in ms */
start_time, /* Unix start time (ms) */ start_time, /* Unix start time (ms) */
last_path_time, /* Time for most recent path (ms) */ last_path_time, /* Time for most recent path (ms) */
last_crash_time, /* Time for most recent crash (ms) */ last_crash_time, /* Time for most recent crash (ms) */
last_hang_time, /* Time for most recent hang (ms) */ last_hang_time, /* Time for most recent hang (ms) */
last_crash_execs, /* Exec counter at last crash */ last_crash_execs, /* Exec counter at last crash */
queue_cycle, /* Queue round counter */ queue_cycle, /* Queue round counter */
cycles_wo_finds, /* Cycles without any new paths */ cycles_wo_finds, /* Cycles without any new paths */
trim_execs, /* Execs done to trim input files */ trim_execs, /* Execs done to trim input files */
bytes_trim_in, /* Bytes coming into the trimmer */ bytes_trim_in, /* Bytes coming into the trimmer */
bytes_trim_out, /* Bytes coming outa the trimmer */ bytes_trim_out, /* Bytes coming outa the trimmer */
blocks_eff_total, /* Blocks subject to effector maps */ blocks_eff_total, /* Blocks subject to effector maps */
blocks_eff_select; /* Blocks selected as fuzzable */ blocks_eff_select; /* Blocks selected as fuzzable */
extern u32 subseq_tmouts; /* Number of timeouts in a row */ extern u32 subseq_tmouts; /* Number of timeouts in a row */
extern u8 *stage_name, /* Name of the current fuzz stage */ extern u8 *stage_name, /* Name of the current fuzz stage */
*stage_short, /* Short stage name */ *stage_short, /* Short stage name */
*syncing_party; /* Currently syncing with... */ *syncing_party; /* Currently syncing with... */
extern s32 stage_cur, stage_max; /* Stage progression */ extern s32 stage_cur, stage_max; /* Stage progression */
extern s32 splicing_with; /* Splicing with which test case? */ extern s32 splicing_with; /* Splicing with which test case? */
extern u32 master_id, master_max; /* Master instance job splitting */ extern u32 master_id, master_max; /* Master instance job splitting */
extern u32 syncing_case; /* Syncing with case #... */ extern u32 syncing_case; /* Syncing with case #... */
extern s32 stage_cur_byte, /* Byte offset of current stage op */ extern s32 stage_cur_byte, /* Byte offset of current stage op */
stage_cur_val; /* Value used for stage op */ stage_cur_val; /* Value used for stage op */
extern u8 stage_val_type; /* Value type (STAGE_VAL_*) */ extern u8 stage_val_type; /* Value type (STAGE_VAL_*) */
extern u64 stage_finds[32], /* Patterns found per fuzz stage */ extern u64 stage_finds[32], /* Patterns found per fuzz stage */
stage_cycles[32]; /* Execs per fuzz stage */ stage_cycles[32]; /* Execs per fuzz stage */
#ifndef HAVE_ARC4RANDOM #ifndef HAVE_ARC4RANDOM
extern u32 rand_cnt; /* Random number counter */ extern u32 rand_cnt; /* Random number counter */
#endif #endif
extern u64 total_cal_us, /* Total calibration time (us) */ extern u64 total_cal_us, /* Total calibration time (us) */
total_cal_cycles; /* Total calibration cycles */ total_cal_cycles; /* Total calibration cycles */
extern u64 total_bitmap_size, /* Total bit count for all bitmaps */ extern u64 total_bitmap_size, /* Total bit count for all bitmaps */
total_bitmap_entries; /* Number of bitmaps counted */ total_bitmap_entries; /* Number of bitmaps counted */
extern s32 cpu_core_count; /* CPU core count */ extern s32 cpu_core_count; /* CPU core count */
#ifdef HAVE_AFFINITY #ifdef HAVE_AFFINITY
extern s32 cpu_aff; /* Selected CPU core */ extern s32 cpu_aff; /* Selected CPU core */
#endif /* HAVE_AFFINITY */ #endif /* HAVE_AFFINITY */
extern FILE* plot_file; /* Gnuplot output file */ extern FILE* plot_file; /* Gnuplot output file */
extern struct queue_entry *queue, /* Fuzzing queue (linked list) */
*queue_cur, /* Current offset within the queue */
extern struct queue_entry *queue, /* Fuzzing queue (linked list) */ *queue_top, /* Top of the list */
*queue_cur, /* Current offset within the queue */ *q_prev100; /* Previous 100 marker */
*queue_top, /* Top of the list */
*q_prev100; /* Previous 100 marker */
extern struct queue_entry* extern struct queue_entry*
top_rated[MAP_SIZE]; /* Top entries for bitmap bytes */ top_rated[MAP_SIZE]; /* Top entries for bitmap bytes */
extern struct extra_data* extras; /* Extra tokens to fuzz with */ extern struct extra_data* extras; /* Extra tokens to fuzz with */
extern u32 extras_cnt; /* Total number of tokens read */ extern u32 extras_cnt; /* Total number of tokens read */
extern struct extra_data* a_extras; /* Automatically selected extras */ extern struct extra_data* a_extras; /* Automatically selected extras */
extern u32 a_extras_cnt; /* Total number of tokens available */ extern u32 a_extras_cnt; /* Total number of tokens available */
u8* (*post_handler)(u8* buf, u32* len); u8* (*post_handler)(u8* buf, u32* len);
/* hooks for the custom mutator function */ /* hooks for the custom mutator function */
size_t (*custom_mutator)(u8 *data, size_t size, u8* mutated_out, size_t max_size, unsigned int seed); size_t (*custom_mutator)(u8* data, size_t size, u8* mutated_out,
size_t (*pre_save_handler)(u8 *data, size_t size, u8 **new_data); size_t max_size, unsigned int seed);
size_t (*pre_save_handler)(u8* data, size_t size, u8** new_data);
/* Interesting values, as per config.h */ /* Interesting values, as per config.h */
extern s8 interesting_8[INTERESTING_8_LEN]; extern s8 interesting_8[INTERESTING_8_LEN];
extern s16 interesting_16[INTERESTING_8_LEN + INTERESTING_16_LEN]; extern s16 interesting_16[INTERESTING_8_LEN + INTERESTING_16_LEN];
extern s32 interesting_32[INTERESTING_8_LEN + INTERESTING_16_LEN + INTERESTING_32_LEN]; extern s32
interesting_32[INTERESTING_8_LEN + INTERESTING_16_LEN + INTERESTING_32_LEN];
/* Python stuff */ /* Python stuff */
#ifdef USE_PYTHON #ifdef USE_PYTHON
#include <Python.h> # include <Python.h>
extern PyObject *py_module; extern PyObject* py_module;
enum { enum {
/* 00 */ PY_FUNC_INIT, /* 00 */ PY_FUNC_INIT,
/* 01 */ PY_FUNC_FUZZ, /* 01 */ PY_FUNC_FUZZ,
/* 02 */ PY_FUNC_INIT_TRIM, /* 02 */ PY_FUNC_INIT_TRIM,
/* 03 */ PY_FUNC_POST_TRIM, /* 03 */ PY_FUNC_POST_TRIM,
/* 04 */ PY_FUNC_TRIM, /* 04 */ PY_FUNC_TRIM,
PY_FUNC_COUNT PY_FUNC_COUNT
}; };
extern PyObject *py_functions[PY_FUNC_COUNT]; extern PyObject* py_functions[PY_FUNC_COUNT];
#endif #endif
@ -462,13 +455,13 @@ extern PyObject *py_functions[PY_FUNC_COUNT];
/* Python */ /* Python */
#ifdef USE_PYTHON #ifdef USE_PYTHON
int init_py(); int init_py();
void finalize_py(); void finalize_py();
void fuzz_py(char*, size_t, char*, size_t, char**, size_t*); void fuzz_py(char*, size_t, char*, size_t, char**, size_t*);
u32 init_trim_py(char*, size_t); u32 init_trim_py(char*, size_t);
u32 post_trim_py(char); u32 post_trim_py(char);
void trim_py(char**, size_t*); void trim_py(char**, size_t*);
u8 trim_case_python(char**, struct queue_entry*, u8*); u8 trim_case_python(char**, struct queue_entry*, u8*);
#endif #endif
/* Queue */ /* Queue */
@ -480,16 +473,16 @@ void add_to_queue(u8*, u32, u8);
void destroy_queue(void); void destroy_queue(void);
void update_bitmap_score(struct queue_entry*); void update_bitmap_score(struct queue_entry*);
void cull_queue(void); void cull_queue(void);
u32 calculate_score(struct queue_entry*); u32 calculate_score(struct queue_entry*);
/* Bitmap */ /* Bitmap */
void write_bitmap(void); void write_bitmap(void);
void read_bitmap(u8*); void read_bitmap(u8*);
u8 has_new_bits(u8*); u8 has_new_bits(u8*);
u32 count_bits(u8*); u32 count_bits(u8*);
u32 count_bytes(u8*); u32 count_bytes(u8*);
u32 count_non_255_bytes(u8*); u32 count_non_255_bytes(u8*);
#ifdef __x86_64__ #ifdef __x86_64__
void simplify_trace(u64*); void simplify_trace(u64*);
void classify_counts(u64*); void classify_counts(u64*);
@ -529,51 +522,51 @@ void show_init_stats(void);
/* Run */ /* Run */
u8 run_target(char**, u32); u8 run_target(char**, u32);
void write_to_testcase(void*, u32); void write_to_testcase(void*, u32);
void write_with_gap(void*, u32, u32, u32); void write_with_gap(void*, u32, u32, u32);
u8 calibrate_case(char**, struct queue_entry*, u8*, u32, u8); u8 calibrate_case(char**, struct queue_entry*, u8*, u32, u8);
void sync_fuzzers(char**); void sync_fuzzers(char**);
u8 trim_case(char**, struct queue_entry*, u8*); u8 trim_case(char**, struct queue_entry*, u8*);
u8 common_fuzz_stuff(char**, u8*, u32); u8 common_fuzz_stuff(char**, u8*, u32);
/* Fuzz one */ /* Fuzz one */
u8 fuzz_one_original(char**); u8 fuzz_one_original(char**);
static u8 pilot_fuzzing(char**); static u8 pilot_fuzzing(char**);
u8 core_fuzzing(char**); u8 core_fuzzing(char**);
void pso_updating(void); void pso_updating(void);
u8 fuzz_one(char**); u8 fuzz_one(char**);
/* Init */ /* Init */
#ifdef HAVE_AFFINITY #ifdef HAVE_AFFINITY
void bind_to_free_cpu(void); void bind_to_free_cpu(void);
#endif #endif
void setup_post(void); void setup_post(void);
void setup_custom_mutator(void); void setup_custom_mutator(void);
void read_testcases(void); void read_testcases(void);
void perform_dry_run(char**); void perform_dry_run(char**);
void pivot_inputs(void); void pivot_inputs(void);
u32 find_start_position(void); u32 find_start_position(void);
void find_timeout(void); void find_timeout(void);
double get_runnable_processes(void); double get_runnable_processes(void);
void nuke_resume_dir(void); void nuke_resume_dir(void);
void maybe_delete_out_dir(void); void maybe_delete_out_dir(void);
void setup_dirs_fds(void); void setup_dirs_fds(void);
void setup_cmdline_file(char**); void setup_cmdline_file(char**);
void setup_stdio_file(void); void setup_stdio_file(void);
void check_crash_handling(void); void check_crash_handling(void);
void check_cpu_governor(void); void check_cpu_governor(void);
void get_core_count(void); void get_core_count(void);
void fix_up_sync(void); void fix_up_sync(void);
void check_asan_opts(void); void check_asan_opts(void);
void check_binary(u8*); void check_binary(u8*);
void fix_up_banner(u8*); void fix_up_banner(u8*);
void check_if_tty(void); void check_if_tty(void);
void setup_signal_handlers(void); void setup_signal_handlers(void);
char** get_qemu_argv(u8*, char**, int); char** get_qemu_argv(u8*, char**, int);
void save_cmdline(u32, char**); void save_cmdline(u32, char**);
/**** Inline routines ****/ /**** Inline routines ****/
@ -581,25 +574,27 @@ void save_cmdline(u32, char**);
have slight bias. */ have slight bias. */
static inline u32 UR(u32 limit) { static inline u32 UR(u32 limit) {
#ifdef HAVE_ARC4RANDOM #ifdef HAVE_ARC4RANDOM
if (fixed_seed) { if (fixed_seed) { return random() % limit; }
return random() % limit;
}
/* The boundary not being necessarily a power of 2, /* The boundary not being necessarily a power of 2,
we need to ensure the result uniformity. */ we need to ensure the result uniformity. */
return arc4random_uniform(limit); return arc4random_uniform(limit);
#else #else
if (!fixed_seed && unlikely(!rand_cnt--)) { if (!fixed_seed && unlikely(!rand_cnt--)) {
u32 seed[2]; u32 seed[2];
ck_read(dev_urandom_fd, &seed, sizeof(seed), "/dev/urandom"); ck_read(dev_urandom_fd, &seed, sizeof(seed), "/dev/urandom");
srandom(seed[0]); srandom(seed[0]);
rand_cnt = (RESEED_RNG / 2) + (seed[1] % RESEED_RNG); rand_cnt = (RESEED_RNG / 2) + (seed[1] % RESEED_RNG);
} }
return random() % limit; return random() % limit;
#endif #endif
} }
/* Find first power of two greater or equal to val (assuming val under /* Find first power of two greater or equal to val (assuming val under
@ -608,7 +603,8 @@ static inline u32 UR(u32 limit) {
static u64 next_p2(u64 val) { static u64 next_p2(u64 val) {
u64 ret = 1; u64 ret = 1;
while (val > ret) ret <<= 1; while (val > ret)
ret <<= 1;
return ret; return ret;
} }
@ -617,7 +613,7 @@ static u64 next_p2(u64 val) {
static u64 get_cur_time(void) { static u64 get_cur_time(void) {
struct timeval tv; struct timeval tv;
struct timezone tz; struct timezone tz;
gettimeofday(&tv, &tz); gettimeofday(&tv, &tz);
@ -626,12 +622,11 @@ static u64 get_cur_time(void) {
} }
/* Get unix time in microseconds */ /* Get unix time in microseconds */
static u64 get_cur_time_us(void) { static u64 get_cur_time_us(void) {
struct timeval tv; struct timeval tv;
struct timezone tz; struct timezone tz;
gettimeofday(&tv, &tz); gettimeofday(&tv, &tz);

View File

@ -31,82 +31,105 @@
/* User-facing macro to sprintf() to a dynamically allocated buffer. */ /* User-facing macro to sprintf() to a dynamically allocated buffer. */
#define alloc_printf(_str...) ({ \ #define alloc_printf(_str...) \
u8* _tmp; \ ({ \
s32 _len = snprintf(NULL, 0, _str); \ \
u8* _tmp; \
s32 _len = snprintf(NULL, 0, _str); \
if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \ if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
_tmp = ck_alloc(_len + 1); \ _tmp = ck_alloc(_len + 1); \
snprintf((char*)_tmp, _len + 1, _str); \ snprintf((char*)_tmp, _len + 1, _str); \
_tmp; \ _tmp; \
\
}) })
/* Macro to enforce allocation limits as a last-resort defense against /* Macro to enforce allocation limits as a last-resort defense against
integer overflows. */ integer overflows. */
#define ALLOC_CHECK_SIZE(_s) do { \ #define ALLOC_CHECK_SIZE(_s) \
if ((_s) > MAX_ALLOC) \ do { \
ABORT("Bad alloc request: %u bytes", (_s)); \ \
if ((_s) > MAX_ALLOC) ABORT("Bad alloc request: %u bytes", (_s)); \
\
} while (0) } while (0)
/* Macro to check malloc() failures and the like. */ /* Macro to check malloc() failures and the like. */
#define ALLOC_CHECK_RESULT(_r, _s) do { \ #define ALLOC_CHECK_RESULT(_r, _s) \
if (!(_r)) \ do { \
ABORT("Out of memory: can't allocate %u bytes", (_s)); \ \
if (!(_r)) ABORT("Out of memory: can't allocate %u bytes", (_s)); \
\
} while (0) } while (0)
/* Magic tokens used to mark used / freed chunks. */ /* Magic tokens used to mark used / freed chunks. */
#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */ #define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */ #define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */ #define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
/* Positions of guard tokens in relation to the user-visible pointer. */ /* Positions of guard tokens in relation to the user-visible pointer. */
#define ALLOC_C1(_ptr) (((u32*)(_ptr))[-2]) #define ALLOC_C1(_ptr) (((u32*)(_ptr))[-2])
#define ALLOC_S(_ptr) (((u32*)(_ptr))[-1]) #define ALLOC_S(_ptr) (((u32*)(_ptr))[-1])
#define ALLOC_C2(_ptr) (((u8*)(_ptr))[ALLOC_S(_ptr)]) #define ALLOC_C2(_ptr) (((u8*)(_ptr))[ALLOC_S(_ptr)])
#define ALLOC_OFF_HEAD 8 #define ALLOC_OFF_HEAD 8
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1) #define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
/* Allocator increments for ck_realloc_block(). */ /* Allocator increments for ck_realloc_block(). */
#define ALLOC_BLK_INC 256 #define ALLOC_BLK_INC 256
/* Sanity-checking macros for pointers. */ /* Sanity-checking macros for pointers. */
#define CHECK_PTR(_p) do { \ #define CHECK_PTR(_p) \
if (_p) { \ do { \
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\ \
if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \ if (_p) { \
ABORT("Use after free."); \ \
else ABORT("Corrupted head alloc canary."); \ if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) { \
} \ \
} \ if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
ABORT("Use after free."); \
else \
ABORT("Corrupted head alloc canary."); \
\
} \
\
} \
\
} while (0) } while (0)
/* /*
#define CHECK_PTR(_p) do { \ #define CHECK_PTR(_p) do { \
\
if (_p) { \ if (_p) { \
\
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\ if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\
\
if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \ if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
ABORT("Use after free."); \ ABORT("Use after free."); \
else ABORT("Corrupted head alloc canary."); \ else ABORT("Corrupted head alloc canary."); \
\
} \ } \
if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \ if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
ABORT("Corrupted tail alloc canary."); \ ABORT("Corrupted tail alloc canary."); \
\
} \ } \
\
} while (0) } while (0)
*/ */
#define CHECK_PTR_EXPR(_p) ({ \ #define CHECK_PTR_EXPR(_p) \
typeof (_p) _tmp = (_p); \ ({ \
CHECK_PTR(_tmp); \ \
_tmp; \ typeof(_p) _tmp = (_p); \
CHECK_PTR(_tmp); \
_tmp; \
\
}) })
/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized /* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
requests. */ requests. */
@ -123,14 +146,13 @@ static inline void* DFL_ck_alloc_nozero(u32 size) {
ret += ALLOC_OFF_HEAD; ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1; ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size; ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2; ALLOC_C2(ret) = ALLOC_MAGIC_C2;
return (void *)ret; return (void*)ret;
} }
/* Allocate a buffer, returning zeroed memory. */ /* Allocate a buffer, returning zeroed memory. */
static inline void* DFL_ck_alloc(u32 size) { static inline void* DFL_ck_alloc(u32 size) {
@ -144,7 +166,6 @@ static inline void* DFL_ck_alloc(u32 size) {
} }
/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD /* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
is set, the old memory will be also clobbered with 0xFF. */ is set, the old memory will be also clobbered with 0xFF. */
@ -163,20 +184,19 @@ static inline void DFL_ck_free(void* mem) {
ALLOC_C1(mem) = ALLOC_MAGIC_F; ALLOC_C1(mem) = ALLOC_MAGIC_F;
u8 *realStart = mem; u8* realStart = mem;
free(realStart - ALLOC_OFF_HEAD); free(realStart - ALLOC_OFF_HEAD);
} }
/* Re-allocate a buffer, checking for issues and zeroing any newly-added tail. /* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
old memory is clobbered with 0xFF. */ old memory is clobbered with 0xFF. */
static inline void* DFL_ck_realloc(void* orig, u32 size) { static inline void* DFL_ck_realloc(void* orig, u32 size) {
u8* ret; u8* ret;
u32 old_size = 0; u32 old_size = 0;
if (!size) { if (!size) {
@ -193,9 +213,9 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
ALLOC_C1(orig) = ALLOC_MAGIC_F; ALLOC_C1(orig) = ALLOC_MAGIC_F;
#endif /* !DEBUG_BUILD */ #endif /* !DEBUG_BUILD */
old_size = ALLOC_S(orig); old_size = ALLOC_S(orig);
u8 *origu8 = orig; u8* origu8 = orig;
origu8 -= ALLOC_OFF_HEAD; origu8 -= ALLOC_OFF_HEAD;
orig = origu8; orig = origu8;
ALLOC_CHECK_SIZE(old_size); ALLOC_CHECK_SIZE(old_size);
@ -219,7 +239,7 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
if (orig) { if (orig) {
u8 *origu8 = orig; u8* origu8 = orig;
memcpy(ret + ALLOC_OFF_HEAD, origu8 + ALLOC_OFF_HEAD, MIN(size, old_size)); memcpy(ret + ALLOC_OFF_HEAD, origu8 + ALLOC_OFF_HEAD, MIN(size, old_size));
memset(origu8 + ALLOC_OFF_HEAD, 0xFF, old_size); memset(origu8 + ALLOC_OFF_HEAD, 0xFF, old_size);
@ -234,17 +254,15 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) {
ret += ALLOC_OFF_HEAD; ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1; ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size; ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2; ALLOC_C2(ret) = ALLOC_MAGIC_C2;
if (size > old_size) if (size > old_size) memset(ret + old_size, 0, size - old_size);
memset(ret + old_size, 0, size - old_size);
return (void *)ret; return (void*)ret;
} }
/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up /* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
repeated small reallocs without complicating the user code). */ repeated small reallocs without complicating the user code). */
@ -268,13 +286,12 @@ static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
} }
/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */ /* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
static inline u8* DFL_ck_strdup(u8* str) { static inline u8* DFL_ck_strdup(u8* str) {
u8* ret; u8* ret;
u32 size; u32 size;
if (!str) return NULL; if (!str) return NULL;
@ -287,38 +304,36 @@ static inline u8* DFL_ck_strdup(u8* str) {
ret += ALLOC_OFF_HEAD; ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1; ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size; ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2; ALLOC_C2(ret) = ALLOC_MAGIC_C2;
return memcpy(ret, str, size); return memcpy(ret, str, size);
} }
/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized /* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
or NULL inputs. */ or NULL inputs. */
static inline void* DFL_ck_memdup(void* mem, u32 size) { static inline void* DFL_ck_memdup(void* mem, u32 size) {
u8* ret; u8* ret;
if (!mem || !size) return NULL; if (!mem || !size) return NULL;
ALLOC_CHECK_SIZE(size); ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL); ret = malloc(size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size); ALLOC_CHECK_RESULT(ret, size);
ret += ALLOC_OFF_HEAD; ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1; ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size; ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2; ALLOC_C2(ret) = ALLOC_MAGIC_C2;
return memcpy(ret, mem, size); return memcpy(ret, mem, size);
} }
/* Create a buffer with a block of text, appending a NUL terminator at the end. /* Create a buffer with a block of text, appending a NUL terminator at the end.
Returns NULL for zero-sized or NULL inputs. */ Returns NULL for zero-sized or NULL inputs. */
@ -331,11 +346,11 @@ static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
ALLOC_CHECK_SIZE(size); ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL + 1); ret = malloc(size + ALLOC_OFF_TOTAL + 1);
ALLOC_CHECK_RESULT(ret, size); ALLOC_CHECK_RESULT(ret, size);
ret += ALLOC_OFF_HEAD; ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1; ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size; ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2; ALLOC_C2(ret) = ALLOC_MAGIC_C2;
memcpy(ret, mem, size); memcpy(ret, mem, size);
@ -345,22 +360,21 @@ static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
} }
#ifndef DEBUG_BUILD #ifndef DEBUG_BUILD
/* In non-debug mode, we just do straightforward aliasing of the above functions /* In non-debug mode, we just do straightforward aliasing of the above functions
to user-visible names such as ck_alloc(). */ to user-visible names such as ck_alloc(). */
#define ck_alloc DFL_ck_alloc # define ck_alloc DFL_ck_alloc
#define ck_alloc_nozero DFL_ck_alloc_nozero # define ck_alloc_nozero DFL_ck_alloc_nozero
#define ck_realloc DFL_ck_realloc # define ck_realloc DFL_ck_realloc
#define ck_realloc_block DFL_ck_realloc_block # define ck_realloc_block DFL_ck_realloc_block
#define ck_strdup DFL_ck_strdup # define ck_strdup DFL_ck_strdup
#define ck_memdup DFL_ck_memdup # define ck_memdup DFL_ck_memdup
#define ck_memdup_str DFL_ck_memdup_str # define ck_memdup_str DFL_ck_memdup_str
#define ck_free DFL_ck_free # define ck_free DFL_ck_free
#define alloc_report() # define alloc_report()
#else #else
@ -369,34 +383,35 @@ static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
/* Alloc tracking data structures: */ /* Alloc tracking data structures: */
#define ALLOC_BUCKETS 4096 # define ALLOC_BUCKETS 4096
struct TRK_obj { struct TRK_obj {
void *ptr;
void* ptr;
char *file, *func; char *file, *func;
u32 line; u32 line;
}; };
#ifdef AFL_MAIN # ifdef AFL_MAIN
struct TRK_obj* TRK[ALLOC_BUCKETS]; struct TRK_obj* TRK[ALLOC_BUCKETS];
u32 TRK_cnt[ALLOC_BUCKETS]; u32 TRK_cnt[ALLOC_BUCKETS];
# define alloc_report() TRK_report() # define alloc_report() TRK_report()
#else # else
extern struct TRK_obj* TRK[ALLOC_BUCKETS]; extern struct TRK_obj* TRK[ALLOC_BUCKETS];
extern u32 TRK_cnt[ALLOC_BUCKETS]; extern u32 TRK_cnt[ALLOC_BUCKETS];
# define alloc_report() # define alloc_report()
#endif /* ^AFL_MAIN */ # endif /* ^AFL_MAIN */
/* Bucket-assigning function for a given pointer: */ /* Bucket-assigning function for a given pointer: */
#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS) # define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
/* Add a new entry to the list of allocated objects. */ /* Add a new entry to the list of allocated objects. */
@ -415,7 +430,7 @@ static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
if (!TRK[bucket][i].ptr) { if (!TRK[bucket][i].ptr) {
TRK[bucket][i].ptr = ptr; TRK[bucket][i].ptr = ptr;
TRK[bucket][i].file = (char*)file; TRK[bucket][i].file = (char*)file;
TRK[bucket][i].func = (char*)func; TRK[bucket][i].func = (char*)func;
TRK[bucket][i].line = line; TRK[bucket][i].line = line;
@ -425,10 +440,10 @@ static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
/* No space available - allocate more. */ /* No space available - allocate more. */
TRK[bucket] = DFL_ck_realloc_block(TRK[bucket], TRK[bucket] = DFL_ck_realloc_block(
(TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj)); TRK[bucket], (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
TRK[bucket][i].ptr = ptr; TRK[bucket][i].ptr = ptr;
TRK[bucket][i].file = (char*)file; TRK[bucket][i].file = (char*)file;
TRK[bucket][i].func = (char*)func; TRK[bucket][i].func = (char*)func;
TRK[bucket][i].line = line; TRK[bucket][i].line = line;
@ -437,7 +452,6 @@ static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
} }
/* Remove entry from the list of allocated objects. */ /* Remove entry from the list of allocated objects. */
static inline void TRK_free_buf(void* ptr, const char* file, const char* func, static inline void TRK_free_buf(void* ptr, const char* file, const char* func,
@ -460,12 +474,11 @@ static inline void TRK_free_buf(void* ptr, const char* file, const char* func,
} }
WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)", WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)", func, file,
func, file, line); line);
} }
/* Do a final report on all non-deallocated objects. */ /* Do a final report on all non-deallocated objects. */
static inline void TRK_report(void) { static inline void TRK_report(void) {
@ -482,7 +495,6 @@ static inline void TRK_report(void) {
} }
/* Simple wrappers for non-debugging functions: */ /* Simple wrappers for non-debugging functions: */
static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func, static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func,
@ -494,7 +506,6 @@ static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func,
} }
static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file, static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file,
const char* func, u32 line) { const char* func, u32 line) {
@ -505,7 +516,6 @@ static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file,
} }
static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file, static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file,
const char* func, u32 line) { const char* func, u32 line) {
@ -516,7 +526,6 @@ static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file,
} }
static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func, static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func,
u32 line) { u32 line) {
@ -526,7 +535,6 @@ static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func,
} }
static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file, static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file,
const char* func, u32 line) { const char* func, u32 line) {
@ -536,7 +544,6 @@ static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file,
} }
static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file, static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file,
const char* func, u32 line) { const char* func, u32 line) {
@ -546,9 +553,8 @@ static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file,
} }
static inline void TRK_ck_free(void* ptr, const char* file, const char* func,
static inline void TRK_ck_free(void* ptr, const char* file, u32 line) {
const char* func, u32 line) {
TRK_free_buf(ptr, file, func, line); TRK_free_buf(ptr, file, func, line);
DFL_ck_free(ptr); DFL_ck_free(ptr);
@ -557,30 +563,27 @@ static inline void TRK_ck_free(void* ptr, const char* file,
/* Aliasing user-facing names to tracking functions: */ /* Aliasing user-facing names to tracking functions: */
#define ck_alloc(_p1) \ # define ck_alloc(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_alloc_nozero(_p1) \ #define ck_alloc_nozero(_p1) TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_realloc(_p1, _p2) \ # define ck_realloc(_p1, _p2)\
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_realloc_block(_p1, _p2) \ # define ck_realloc_block(_p1, _p2)\
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_strdup(_p1) \ # define ck_strdup(_p1) TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
#define ck_memdup(_p1, _p2) \ # define ck_memdup(_p1, _p2)\
TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_memdup_str(_p1, _p2) \ # define ck_memdup_str(_p1, _p2)\
TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
#define ck_free(_p1) \ # define ck_free(_p1) TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
#endif /* ^!DEBUG_BUILD */ #endif /* ^!DEBUG_BUILD */
#endif /* ! _HAVE_ALLOC_INL_H */ #endif /* ! _HAVE_ALLOC_INL_H */

View File

@ -8,74 +8,73 @@
#include <sys/mman.h> #include <sys/mman.h>
#if __ANDROID_API__ >= 26 #if __ANDROID_API__ >= 26
#define shmat bionic_shmat # define shmat bionic_shmat
#define shmctl bionic_shmctl # define shmctl bionic_shmctl
#define shmdt bionic_shmdt # define shmdt bionic_shmdt
#define shmget bionic_shmget # define shmget bionic_shmget
#endif #endif
#include <sys/shm.h> #include <sys/shm.h>
#undef shmat #undef shmat
#undef shmctl #undef shmctl
#undef shmdt #undef shmdt
#undef shmget #undef shmget
#include <stdio.h> #include <stdio.h>
#define ASHMEM_DEVICE "/dev/ashmem" #define ASHMEM_DEVICE "/dev/ashmem"
static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) {
{
int ret = 0; int ret = 0;
if (__cmd == IPC_RMID) { if (__cmd == IPC_RMID) {
int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
struct ashmem_pin pin = {0, length}; int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); struct ashmem_pin pin = {0, length};
close(__shmid); ret = ioctl(__shmid, ASHMEM_UNPIN, &pin);
} close(__shmid);
}
return ret;
return ret;
} }
static inline int shmget (key_t __key, size_t __size, int __shmflg) static inline int shmget(key_t __key, size_t __size, int __shmflg) {
{
int fd,ret;
char ourkey[11];
fd = open(ASHMEM_DEVICE, O_RDWR); int fd, ret;
if (fd < 0) char ourkey[11];
return fd;
sprintf(ourkey,"%d",__key); fd = open(ASHMEM_DEVICE, O_RDWR);
ret = ioctl(fd, ASHMEM_SET_NAME, ourkey); if (fd < 0) return fd;
if (ret < 0)
goto error;
ret = ioctl(fd, ASHMEM_SET_SIZE, __size); sprintf(ourkey, "%d", __key);
if (ret < 0) ret = ioctl(fd, ASHMEM_SET_NAME, ourkey);
goto error; if (ret < 0) goto error;
return fd; ret = ioctl(fd, ASHMEM_SET_SIZE, __size);
if (ret < 0) goto error;
return fd;
error: error:
close(fd); close(fd);
return ret; return ret;
} }
static inline void *shmat (int __shmid, const void *__shmaddr, int __shmflg) static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
{
int size; int size;
void *ptr; void *ptr;
size = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); size = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
if (size < 0) { if (size < 0) { return NULL; }
return NULL;
}
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, __shmid, 0); ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, __shmid, 0);
if (ptr == MAP_FAILED) { if (ptr == MAP_FAILED) { return NULL; }
return NULL;
}
return ptr; return ptr;
} }
#endif #endif

View File

@ -4,3 +4,4 @@
void detect_file_args(char **argv, u8 *prog_in); void detect_file_args(char **argv, u8 *prog_in);
#endif #endif

View File

@ -21,7 +21,7 @@
/* Version string: */ /* Version string: */
#define VERSION "++2.53d" // c = release, d = volatile github dev #define VERSION "++2.53d" // c = release, d = volatile github dev
/****************************************************** /******************************************************
* * * *
@ -41,64 +41,64 @@
/* Default timeout for fuzzed code (milliseconds). This is the upper bound, /* Default timeout for fuzzed code (milliseconds). This is the upper bound,
also used for detecting hangs; the actual value is auto-scaled: */ also used for detecting hangs; the actual value is auto-scaled: */
#define EXEC_TIMEOUT 1000 #define EXEC_TIMEOUT 1000
/* Timeout rounding factor when auto-scaling (milliseconds): */ /* Timeout rounding factor when auto-scaling (milliseconds): */
#define EXEC_TM_ROUND 20 #define EXEC_TM_ROUND 20
/* Default memory limit for child process (MB): */ /* Default memory limit for child process (MB): */
#ifndef __x86_64__ #ifndef __x86_64__
# define MEM_LIMIT 25 # define MEM_LIMIT 25
#else #else
# define MEM_LIMIT 50 # define MEM_LIMIT 50
#endif /* ^!__x86_64__ */ #endif /* ^!__x86_64__ */
/* Default memory limit when running in QEMU mode (MB): */ /* Default memory limit when running in QEMU mode (MB): */
#define MEM_LIMIT_QEMU 200 #define MEM_LIMIT_QEMU 200
/* Default memory limit when running in Unicorn mode (MB): */ /* Default memory limit when running in Unicorn mode (MB): */
#define MEM_LIMIT_UNICORN 200 #define MEM_LIMIT_UNICORN 200
/* Number of calibration cycles per every new test case (and for test /* Number of calibration cycles per every new test case (and for test
cases that show variable behavior): */ cases that show variable behavior): */
#define CAL_CYCLES 8 #define CAL_CYCLES 8
#define CAL_CYCLES_LONG 40 #define CAL_CYCLES_LONG 40
/* Number of subsequent timeouts before abandoning an input file: */ /* Number of subsequent timeouts before abandoning an input file: */
#define TMOUT_LIMIT 250 #define TMOUT_LIMIT 250
/* Maximum number of unique hangs or crashes to record: */ /* Maximum number of unique hangs or crashes to record: */
#define KEEP_UNIQUE_HANG 500 #define KEEP_UNIQUE_HANG 500
#define KEEP_UNIQUE_CRASH 5000 #define KEEP_UNIQUE_CRASH 5000
/* Baseline number of random tweaks during a single 'havoc' stage: */ /* Baseline number of random tweaks during a single 'havoc' stage: */
#define HAVOC_CYCLES 256 #define HAVOC_CYCLES 256
#define HAVOC_CYCLES_INIT 1024 #define HAVOC_CYCLES_INIT 1024
/* Maximum multiplier for the above (should be a power of two, beware /* Maximum multiplier for the above (should be a power of two, beware
of 32-bit int overflows): */ of 32-bit int overflows): */
#define HAVOC_MAX_MULT 16 #define HAVOC_MAX_MULT 16
#define HAVOC_MAX_MULT_MOPT 32 #define HAVOC_MAX_MULT_MOPT 32
/* Absolute minimum number of havoc cycles (after all adjustments): */ /* Absolute minimum number of havoc cycles (after all adjustments): */
#define HAVOC_MIN 16 #define HAVOC_MIN 16
/* Power Schedule Divisor */ /* Power Schedule Divisor */
#define POWER_BETA 1 #define POWER_BETA 1
#define MAX_FACTOR (POWER_BETA * 32) #define MAX_FACTOR (POWER_BETA * 32)
/* Maximum stacking for havoc-stage tweaks. The actual value is calculated /* Maximum stacking for havoc-stage tweaks. The actual value is calculated
like this: like this:
n = random between 1 and HAVOC_STACK_POW2 n = random between 1 and HAVOC_STACK_POW2
stacking = 2^n stacking = 2^n
@ -106,116 +106,116 @@
In other words, the default (n = 7) produces 2, 4, 8, 16, 32, 64, or In other words, the default (n = 7) produces 2, 4, 8, 16, 32, 64, or
128 stacked tweaks: */ 128 stacked tweaks: */
#define HAVOC_STACK_POW2 7 #define HAVOC_STACK_POW2 7
/* Caps on block sizes for cloning and deletion operations. Each of these /* Caps on block sizes for cloning and deletion operations. Each of these
ranges has a 33% probability of getting picked, except for the first ranges has a 33% probability of getting picked, except for the first
two cycles where smaller blocks are favored: */ two cycles where smaller blocks are favored: */
#define HAVOC_BLK_SMALL 32 #define HAVOC_BLK_SMALL 32
#define HAVOC_BLK_MEDIUM 128 #define HAVOC_BLK_MEDIUM 128
#define HAVOC_BLK_LARGE 1500 #define HAVOC_BLK_LARGE 1500
/* Extra-large blocks, selected very rarely (<5% of the time): */ /* Extra-large blocks, selected very rarely (<5% of the time): */
#define HAVOC_BLK_XL 32768 #define HAVOC_BLK_XL 32768
/* Probabilities of skipping non-favored entries in the queue, expressed as /* Probabilities of skipping non-favored entries in the queue, expressed as
percentages: */ percentages: */
#define SKIP_TO_NEW_PROB 99 /* ...when there are new, pending favorites */ #define SKIP_TO_NEW_PROB 99 /* ...when there are new, pending favorites */
#define SKIP_NFAV_OLD_PROB 95 /* ...no new favs, cur entry already fuzzed */ #define SKIP_NFAV_OLD_PROB 95 /* ...no new favs, cur entry already fuzzed */
#define SKIP_NFAV_NEW_PROB 75 /* ...no new favs, cur entry not fuzzed yet */ #define SKIP_NFAV_NEW_PROB 75 /* ...no new favs, cur entry not fuzzed yet */
/* Splicing cycle count: */ /* Splicing cycle count: */
#define SPLICE_CYCLES 15 #define SPLICE_CYCLES 15
/* Nominal per-splice havoc cycle length: */ /* Nominal per-splice havoc cycle length: */
#define SPLICE_HAVOC 32 #define SPLICE_HAVOC 32
/* Maximum offset for integer addition / subtraction stages: */ /* Maximum offset for integer addition / subtraction stages: */
#define ARITH_MAX 35 #define ARITH_MAX 35
/* Limits for the test case trimmer. The absolute minimum chunk size; and /* Limits for the test case trimmer. The absolute minimum chunk size; and
the starting and ending divisors for chopping up the input file: */ the starting and ending divisors for chopping up the input file: */
#define TRIM_MIN_BYTES 4 #define TRIM_MIN_BYTES 4
#define TRIM_START_STEPS 16 #define TRIM_START_STEPS 16
#define TRIM_END_STEPS 1024 #define TRIM_END_STEPS 1024
/* Maximum size of input file, in bytes (keep under 100MB): */ /* Maximum size of input file, in bytes (keep under 100MB): */
#define MAX_FILE (1 * 1024 * 1024) #define MAX_FILE (1 * 1024 * 1024)
/* The same, for the test case minimizer: */ /* The same, for the test case minimizer: */
#define TMIN_MAX_FILE (10 * 1024 * 1024) #define TMIN_MAX_FILE (10 * 1024 * 1024)
/* Block normalization steps for afl-tmin: */ /* Block normalization steps for afl-tmin: */
#define TMIN_SET_MIN_SIZE 4 #define TMIN_SET_MIN_SIZE 4
#define TMIN_SET_STEPS 128 #define TMIN_SET_STEPS 128
/* Maximum dictionary token size (-x), in bytes: */ /* Maximum dictionary token size (-x), in bytes: */
#define MAX_DICT_FILE 128 #define MAX_DICT_FILE 128
/* Length limits for auto-detected dictionary tokens: */ /* Length limits for auto-detected dictionary tokens: */
#define MIN_AUTO_EXTRA 3 #define MIN_AUTO_EXTRA 3
#define MAX_AUTO_EXTRA 32 #define MAX_AUTO_EXTRA 32
/* Maximum number of user-specified dictionary tokens to use in deterministic /* Maximum number of user-specified dictionary tokens to use in deterministic
steps; past this point, the "extras/user" step will be still carried out, steps; past this point, the "extras/user" step will be still carried out,
but with proportionally lower odds: */ but with proportionally lower odds: */
#define MAX_DET_EXTRAS 200 #define MAX_DET_EXTRAS 200
/* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing /* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing
(first value), and to keep in memory as candidates. The latter should be much (first value), and to keep in memory as candidates. The latter should be much
higher than the former. */ higher than the former. */
#define USE_AUTO_EXTRAS 50 #define USE_AUTO_EXTRAS 50
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10) #define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10)
/* Scaling factor for the effector map used to skip some of the more /* Scaling factor for the effector map used to skip some of the more
expensive deterministic steps. The actual divisor is set to expensive deterministic steps. The actual divisor is set to
2^EFF_MAP_SCALE2 bytes: */ 2^EFF_MAP_SCALE2 bytes: */
#define EFF_MAP_SCALE2 3 #define EFF_MAP_SCALE2 3
/* Minimum input file length at which the effector logic kicks in: */ /* Minimum input file length at which the effector logic kicks in: */
#define EFF_MIN_LEN 128 #define EFF_MIN_LEN 128
/* Maximum effector density past which everything is just fuzzed /* Maximum effector density past which everything is just fuzzed
unconditionally (%): */ unconditionally (%): */
#define EFF_MAX_PERC 90 #define EFF_MAX_PERC 90
/* UI refresh frequency (Hz): */ /* UI refresh frequency (Hz): */
#define UI_TARGET_HZ 5 #define UI_TARGET_HZ 5
/* Fuzzer stats file and plot update intervals (sec): */ /* Fuzzer stats file and plot update intervals (sec): */
#define STATS_UPDATE_SEC 60 #define STATS_UPDATE_SEC 60
#define PLOT_UPDATE_SEC 5 #define PLOT_UPDATE_SEC 5
/* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */ /* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */
#define AVG_SMOOTHING 16 #define AVG_SMOOTHING 16
/* Sync interval (every n havoc cycles): */ /* Sync interval (every n havoc cycles): */
#define SYNC_INTERVAL 5 #define SYNC_INTERVAL 5
/* Output directory reuse grace period (minutes): */ /* Output directory reuse grace period (minutes): */
#define OUTPUT_GRACE 25 #define OUTPUT_GRACE 25
/* Uncomment to use simple file names (id_NNNNNN): */ /* Uncomment to use simple file names (id_NNNNNN): */
@ -223,42 +223,42 @@
/* List of interesting values to use in fuzzing. */ /* List of interesting values to use in fuzzing. */
#define INTERESTING_8 \ #define INTERESTING_8 \
-128, /* Overflow signed 8-bit when decremented */ \ -128, /* Overflow signed 8-bit when decremented */ \
-1, /* */ \ -1, /* */ \
0, /* */ \ 0, /* */ \
1, /* */ \ 1, /* */ \
16, /* One-off with common buffer size */ \ 16, /* One-off with common buffer size */ \
32, /* One-off with common buffer size */ \ 32, /* One-off with common buffer size */ \
64, /* One-off with common buffer size */ \ 64, /* One-off with common buffer size */ \
100, /* One-off with common buffer size */ \ 100, /* One-off with common buffer size */ \
127 /* Overflow signed 8-bit when incremented */ 127 /* Overflow signed 8-bit when incremented */
#define INTERESTING_8_LEN 9 #define INTERESTING_8_LEN 9
#define INTERESTING_16 \ #define INTERESTING_16 \
-32768, /* Overflow signed 16-bit when decremented */ \ -32768, /* Overflow signed 16-bit when decremented */ \
-129, /* Overflow signed 8-bit */ \ -129, /* Overflow signed 8-bit */ \
128, /* Overflow signed 8-bit */ \ 128, /* Overflow signed 8-bit */ \
255, /* Overflow unsig 8-bit when incremented */ \ 255, /* Overflow unsig 8-bit when incremented */ \
256, /* Overflow unsig 8-bit */ \ 256, /* Overflow unsig 8-bit */ \
512, /* One-off with common buffer size */ \ 512, /* One-off with common buffer size */ \
1000, /* One-off with common buffer size */ \ 1000, /* One-off with common buffer size */ \
1024, /* One-off with common buffer size */ \ 1024, /* One-off with common buffer size */ \
4096, /* One-off with common buffer size */ \ 4096, /* One-off with common buffer size */ \
32767 /* Overflow signed 16-bit when incremented */ 32767 /* Overflow signed 16-bit when incremented */
#define INTERESTING_16_LEN 10 #define INTERESTING_16_LEN 10
#define INTERESTING_32 \ #define INTERESTING_32 \
-2147483648LL, /* Overflow signed 32-bit when decremented */ \ -2147483648LL, /* Overflow signed 32-bit when decremented */ \
-100663046, /* Large negative number (endian-agnostic) */ \ -100663046, /* Large negative number (endian-agnostic) */ \
-32769, /* Overflow signed 16-bit */ \ -32769, /* Overflow signed 16-bit */ \
32768, /* Overflow signed 16-bit */ \ 32768, /* Overflow signed 16-bit */ \
65535, /* Overflow unsig 16-bit when incremented */ \ 65535, /* Overflow unsig 16-bit when incremented */ \
65536, /* Overflow unsig 16 bit */ \ 65536, /* Overflow unsig 16 bit */ \
100663045, /* Large positive number (endian-agnostic) */ \ 100663045, /* Large positive number (endian-agnostic) */ \
2147483647 /* Overflow signed 32-bit when incremented */ 2147483647 /* Overflow signed 32-bit when incremented */
#define INTERESTING_32_LEN 8 #define INTERESTING_32_LEN 8
@ -270,57 +270,57 @@
/* Call count interval between reseeding the libc PRNG from /dev/urandom: */ /* Call count interval between reseeding the libc PRNG from /dev/urandom: */
#define RESEED_RNG 10000 #define RESEED_RNG 10000
/* Maximum line length passed from GCC to 'as' and used for parsing /* Maximum line length passed from GCC to 'as' and used for parsing
configuration files: */ configuration files: */
#define MAX_LINE 8192 #define MAX_LINE 8192
/* Environment variable used to pass SHM ID to the called program. */ /* Environment variable used to pass SHM ID to the called program. */
#define SHM_ENV_VAR "__AFL_SHM_ID" #define SHM_ENV_VAR "__AFL_SHM_ID"
/* Other less interesting, internal-only variables. */ /* Other less interesting, internal-only variables. */
#define CLANG_ENV_VAR "__AFL_CLANG_MODE" #define CLANG_ENV_VAR "__AFL_CLANG_MODE"
#define AS_LOOP_ENV_VAR "__AFL_AS_LOOPCHECK" #define AS_LOOP_ENV_VAR "__AFL_AS_LOOPCHECK"
#define PERSIST_ENV_VAR "__AFL_PERSISTENT" #define PERSIST_ENV_VAR "__AFL_PERSISTENT"
#define DEFER_ENV_VAR "__AFL_DEFER_FORKSRV" #define DEFER_ENV_VAR "__AFL_DEFER_FORKSRV"
/* In-code signatures for deferred and persistent mode. */ /* In-code signatures for deferred and persistent mode. */
#define PERSIST_SIG "##SIG_AFL_PERSISTENT##" #define PERSIST_SIG "##SIG_AFL_PERSISTENT##"
#define DEFER_SIG "##SIG_AFL_DEFER_FORKSRV##" #define DEFER_SIG "##SIG_AFL_DEFER_FORKSRV##"
/* Distinctive bitmap signature used to indicate failed execution: */ /* Distinctive bitmap signature used to indicate failed execution: */
#define EXEC_FAIL_SIG 0xfee1dead #define EXEC_FAIL_SIG 0xfee1dead
/* Distinctive exit code used to indicate MSAN trip condition: */ /* Distinctive exit code used to indicate MSAN trip condition: */
#define MSAN_ERROR 86 #define MSAN_ERROR 86
/* Designated file descriptors for forkserver commands (the application will /* Designated file descriptors for forkserver commands (the application will
use FORKSRV_FD and FORKSRV_FD + 1): */ use FORKSRV_FD and FORKSRV_FD + 1): */
#define FORKSRV_FD 198 #define FORKSRV_FD 198
/* Fork server init timeout multiplier: we'll wait the user-selected /* Fork server init timeout multiplier: we'll wait the user-selected
timeout plus this much for the fork server to spin up. */ timeout plus this much for the fork server to spin up. */
#define FORK_WAIT_MULT 10 #define FORK_WAIT_MULT 10
/* Calibration timeout adjustments, to be a bit more generous when resuming /* Calibration timeout adjustments, to be a bit more generous when resuming
fuzzing sessions or trying to calibrate already-added internal finds. fuzzing sessions or trying to calibrate already-added internal finds.
The first value is a percentage, the other is in milliseconds: */ The first value is a percentage, the other is in milliseconds: */
#define CAL_TMOUT_PERC 125 #define CAL_TMOUT_PERC 125
#define CAL_TMOUT_ADD 50 #define CAL_TMOUT_ADD 50
/* Number of chances to calibrate a case before giving up: */ /* Number of chances to calibrate a case before giving up: */
#define CAL_CHANCES 3 #define CAL_CHANCES 3
/* Map size for the traced binary (2^MAP_SIZE_POW2). Must be greater than /* Map size for the traced binary (2^MAP_SIZE_POW2). Must be greater than
2; you probably want to keep it under 18 or so for performance reasons 2; you probably want to keep it under 18 or so for performance reasons
@ -328,28 +328,27 @@
problems with complex programs). You need to recompile the target binary problems with complex programs). You need to recompile the target binary
after changing this - otherwise, SEGVs may ensue. */ after changing this - otherwise, SEGVs may ensue. */
#define MAP_SIZE_POW2 16 #define MAP_SIZE_POW2 16
#define MAP_SIZE (1 << MAP_SIZE_POW2) #define MAP_SIZE (1 << MAP_SIZE_POW2)
/* Maximum allocator request size (keep well under INT_MAX): */ /* Maximum allocator request size (keep well under INT_MAX): */
#define MAX_ALLOC 0x40000000 #define MAX_ALLOC 0x40000000
/* A made-up hashing seed: */ /* A made-up hashing seed: */
#define HASH_CONST 0xa5b35705 #define HASH_CONST 0xa5b35705
/* Constants for afl-gotcpu to control busy loop timing: */ /* Constants for afl-gotcpu to control busy loop timing: */
#define CTEST_TARGET_MS 5000 #define CTEST_TARGET_MS 5000
#define CTEST_CORE_TRG_MS 1000 #define CTEST_CORE_TRG_MS 1000
#define CTEST_BUSY_CYCLES (10 * 1000 * 1000) #define CTEST_BUSY_CYCLES (10 * 1000 * 1000)
/* Enable NeverZero counters in QEMU mode */ /* Enable NeverZero counters in QEMU mode */
#define AFL_QEMU_NOT_ZERO #define AFL_QEMU_NOT_ZERO
/* Uncomment this to use inferior block-coverage-based instrumentation. Note /* Uncomment this to use inferior block-coverage-based instrumentation. Note
that you need to recompile the target binary for this to have any effect: */ that you need to recompile the target binary for this to have any effect: */
@ -368,3 +367,4 @@
// #define IGNORE_FINDS // #define IGNORE_FINDS
#endif /* ! _HAVE_CONFIG_H */ #endif /* ! _HAVE_CONFIG_H */

View File

@ -108,39 +108,39 @@
#ifdef FANCY_BOXES #ifdef FANCY_BOXES
# define SET_G1 "\x1b)0" /* Set G1 for box drawing */ # define SET_G1 "\x1b)0" /* Set G1 for box drawing */
# define RESET_G1 "\x1b)B" /* Reset G1 to ASCII */ # define RESET_G1 "\x1b)B" /* Reset G1 to ASCII */
# define bSTART "\x0e" /* Enter G1 drawing mode */ # define bSTART "\x0e" /* Enter G1 drawing mode */
# define bSTOP "\x0f" /* Leave G1 drawing mode */ # define bSTOP "\x0f" /* Leave G1 drawing mode */
# define bH "q" /* Horizontal line */ # define bH "q" /* Horizontal line */
# define bV "x" /* Vertical line */ # define bV "x" /* Vertical line */
# define bLT "l" /* Left top corner */ # define bLT "l" /* Left top corner */
# define bRT "k" /* Right top corner */ # define bRT "k" /* Right top corner */
# define bLB "m" /* Left bottom corner */ # define bLB "m" /* Left bottom corner */
# define bRB "j" /* Right bottom corner */ # define bRB "j" /* Right bottom corner */
# define bX "n" /* Cross */ # define bX "n" /* Cross */
# define bVR "t" /* Vertical, branch right */ # define bVR "t" /* Vertical, branch right */
# define bVL "u" /* Vertical, branch left */ # define bVL "u" /* Vertical, branch left */
# define bHT "v" /* Horizontal, branch top */ # define bHT "v" /* Horizontal, branch top */
# define bHB "w" /* Horizontal, branch bottom */ # define bHB "w" /* Horizontal, branch bottom */
#else #else
# define SET_G1 "" # define SET_G1 ""
# define RESET_G1 "" # define RESET_G1 ""
# define bSTART "" # define bSTART ""
# define bSTOP "" # define bSTOP ""
# define bH "-" # define bH "-"
# define bV "|" # define bV "|"
# define bLT "+" # define bLT "+"
# define bRT "+" # define bRT "+"
# define bLB "+" # define bLB "+"
# define bRB "+" # define bRB "+"
# define bX "+" # define bX "+"
# define bVR "+" # define bVR "+"
# define bVL "+" # define bVL "+"
# define bHT "+" # define bHT "+"
# define bHB "+" # define bHB "+"
#endif /* ^FANCY_BOXES */ #endif /* ^FANCY_BOXES */
@ -148,11 +148,11 @@
* Misc terminal codes * * Misc terminal codes *
***********************/ ***********************/
#define TERM_HOME "\x1b[H" #define TERM_HOME "\x1b[H"
#define TERM_CLEAR TERM_HOME "\x1b[2J" #define TERM_CLEAR TERM_HOME "\x1b[2J"
#define cEOL "\x1b[0K" #define cEOL "\x1b[0K"
#define CURSOR_HIDE "\x1b[?25l" #define CURSOR_HIDE "\x1b[?25l"
#define CURSOR_SHOW "\x1b[?25h" #define CURSOR_SHOW "\x1b[?25h"
/************************ /************************
* Debug & error macros * * Debug & error macros *
@ -161,91 +161,125 @@
/* Just print stuff to the appropriate stream. */ /* Just print stuff to the appropriate stream. */
#ifdef MESSAGES_TO_STDOUT #ifdef MESSAGES_TO_STDOUT
# define SAYF(x...) printf(x) # define SAYF(x...) printf(x)
#else #else
# define SAYF(x...) fprintf(stderr, x) # define SAYF(x...) fprintf(stderr, x)
#endif /* ^MESSAGES_TO_STDOUT */ #endif /* ^MESSAGES_TO_STDOUT */
/* Show a prefixed warning. */ /* Show a prefixed warning. */
#define WARNF(x...) do { \ #define WARNF(x...) \
do { \
\
SAYF(cYEL "[!] " cBRI "WARNING: " cRST x); \ SAYF(cYEL "[!] " cBRI "WARNING: " cRST x); \
SAYF(cRST "\n"); \ SAYF(cRST "\n"); \
\
} while (0) } while (0)
/* Show a prefixed "doing something" message. */ /* Show a prefixed "doing something" message. */
#define ACTF(x...) do { \ #define ACTF(x...) \
do { \
\
SAYF(cLBL "[*] " cRST x); \ SAYF(cLBL "[*] " cRST x); \
SAYF(cRST "\n"); \ SAYF(cRST "\n"); \
\
} while (0) } while (0)
/* Show a prefixed "success" message. */ /* Show a prefixed "success" message. */
#define OKF(x...) do { \ #define OKF(x...) \
do { \
\
SAYF(cLGN "[+] " cRST x); \ SAYF(cLGN "[+] " cRST x); \
SAYF(cRST "\n"); \ SAYF(cRST "\n"); \
\
} while (0) } while (0)
/* Show a prefixed fatal error message (not used in afl). */ /* Show a prefixed fatal error message (not used in afl). */
#define BADF(x...) do { \ #define BADF(x...) \
do { \
\
SAYF(cLRD "\n[-] " cRST x); \ SAYF(cLRD "\n[-] " cRST x); \
SAYF(cRST "\n"); \ SAYF(cRST "\n"); \
\
} while (0) } while (0)
/* Die with a verbose non-OS fatal error message. */ /* Die with a verbose non-OS fatal error message. */
#define FATAL(x...) do { \ #define FATAL(x...) \
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] PROGRAM ABORT : " \ do { \
cRST x); \ \
SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
__FUNCTION__, __FILE__, __LINE__); \ "\n[-] PROGRAM ABORT : " cRST x); \
exit(1); \ SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __FUNCTION__, \
__FILE__, __LINE__); \
exit(1); \
\
} while (0) } while (0)
/* Die by calling abort() to provide a core dump. */ /* Die by calling abort() to provide a core dump. */
#define ABORT(x...) do { \ #define ABORT(x...) \
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] PROGRAM ABORT : " \ do { \
cRST x); \ \
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
__FUNCTION__, __FILE__, __LINE__); \ "\n[-] PROGRAM ABORT : " cRST x); \
abort(); \ SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __FUNCTION__, \
__FILE__, __LINE__); \
abort(); \
\
} while (0) } while (0)
/* Die while also including the output of perror(). */ /* Die while also including the output of perror(). */
#define PFATAL(x...) do { \ #define PFATAL(x...) \
fflush(stdout); \ do { \
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] SYSTEM ERROR : " \ \
cRST x); \ fflush(stdout); \
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
__FUNCTION__, __FILE__, __LINE__); \ "\n[-] SYSTEM ERROR : " cRST x); \
SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \ SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __FUNCTION__, \
exit(1); \ __FILE__, __LINE__); \
SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \
exit(1); \
\
} while (0) } while (0)
/* Die with FAULT() or PFAULT() depending on the value of res (used to /* Die with FAULT() or PFAULT() depending on the value of res (used to
interpret different failure modes for read(), write(), etc). */ interpret different failure modes for read(), write(), etc). */
#define RPFATAL(res, x...) do { \ #define RPFATAL(res, x...) \
if (res < 0) PFATAL(x); else FATAL(x); \ do { \
\
if (res < 0) \
PFATAL(x); \
else \
FATAL(x); \
\
} while (0) } while (0)
/* Error-checking versions of read() and write() that call RPFATAL() as /* Error-checking versions of read() and write() that call RPFATAL() as
appropriate. */ appropriate. */
#define ck_write(fd, buf, len, fn) do { \ #define ck_write(fd, buf, len, fn) \
u32 _len = (len); \ do { \
s32 _res = write(fd, buf, _len); \ \
u32 _len = (len); \
s32 _res = write(fd, buf, _len); \
if (_res != _len) RPFATAL(_res, "Short write to %s", fn); \ if (_res != _len) RPFATAL(_res, "Short write to %s", fn); \
\
} while (0) } while (0)
#define ck_read(fd, buf, len, fn) do { \ #define ck_read(fd, buf, len, fn) \
u32 _len = (len); \ do { \
s32 _res = read(fd, buf, _len); \ \
u32 _len = (len); \
s32 _res = read(fd, buf, _len); \
if (_res != _len) RPFATAL(_res, "Short read from %s", fn); \ if (_res != _len) RPFATAL(_res, "Short read from %s", fn); \
\
} while (0) } while (0)
#endif /* ! _HAVE_DEBUG_H */ #endif /* ! _HAVE_DEBUG_H */

View File

@ -5,21 +5,21 @@ void handle_timeout(int sig);
void init_forkserver(char **argv); void init_forkserver(char **argv);
#ifdef __APPLE__ #ifdef __APPLE__
#define MSG_FORK_ON_APPLE \ # define MSG_FORK_ON_APPLE \
" - On MacOS X, the semantics of fork() syscalls are non-standard and " \ " - On MacOS X, the semantics of fork() syscalls are non-standard and " \
"may\n" \ "may\n" \
" break afl-fuzz performance optimizations when running " \ " break afl-fuzz performance optimizations when running " \
"platform-specific\n" \ "platform-specific\n" \
" targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n" " targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n"
#else #else
#define MSG_FORK_ON_APPLE "" # define MSG_FORK_ON_APPLE ""
#endif #endif
#ifdef RLIMIT_AS #ifdef RLIMIT_AS
#define MSG_ULIMIT_USAGE " ( ulimit -Sv $[%llu << 10];" # define MSG_ULIMIT_USAGE " ( ulimit -Sv $[%llu << 10];"
#else #else
#define MSG_ULIMIT_USAGE " ( ulimit -Sd $[%llu << 10];" # define MSG_ULIMIT_USAGE " ( ulimit -Sd $[%llu << 10];"
#endif /* ^RLIMIT_AS */ #endif /* ^RLIMIT_AS */
#endif #endif

View File

@ -31,12 +31,12 @@
#ifdef __x86_64__ #ifdef __x86_64__
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r)))) # define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
static inline u32 hash32(const void* key, u32 len, u32 seed) { static inline u32 hash32(const void* key, u32 len, u32 seed) {
const u64* data = (u64*)key; const u64* data = (u64*)key;
u64 h1 = seed ^ len; u64 h1 = seed ^ len;
len >>= 3; len >>= 3;
@ -45,12 +45,12 @@ static inline u32 hash32(const void* key, u32 len, u32 seed) {
u64 k1 = *data++; u64 k1 = *data++;
k1 *= 0x87c37b91114253d5ULL; k1 *= 0x87c37b91114253d5ULL;
k1 = ROL64(k1, 31); k1 = ROL64(k1, 31);
k1 *= 0x4cf5ad432745937fULL; k1 *= 0x4cf5ad432745937fULL;
h1 ^= k1; h1 ^= k1;
h1 = ROL64(h1, 27); h1 = ROL64(h1, 27);
h1 = h1 * 5 + 0x52dce729; h1 = h1 * 5 + 0x52dce729;
} }
@ -64,14 +64,14 @@ static inline u32 hash32(const void* key, u32 len, u32 seed) {
} }
#else #else
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r)))) # define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
static inline u32 hash32(const void* key, u32 len, u32 seed) { static inline u32 hash32(const void* key, u32 len, u32 seed) {
const u32* data = (u32*)key; const u32* data = (u32*)key;
u32 h1 = seed ^ len; u32 h1 = seed ^ len;
len >>= 2; len >>= 2;
@ -80,12 +80,12 @@ static inline u32 hash32(const void* key, u32 len, u32 seed) {
u32 k1 = *data++; u32 k1 = *data++;
k1 *= 0xcc9e2d51; k1 *= 0xcc9e2d51;
k1 = ROL32(k1, 15); k1 = ROL32(k1, 15);
k1 *= 0x1b873593; k1 *= 0x1b873593;
h1 ^= k1; h1 ^= k1;
h1 = ROL32(h1, 13); h1 = ROL32(h1, 13);
h1 = h1 * 5 + 0xe6546b64; h1 = h1 * 5 + 0xe6546b64;
} }
@ -102,3 +102,4 @@ static inline u32 hash32(const void* key, u32 len, u32 seed) {
#endif /* ^__x86_64__ */ #endif /* ^__x86_64__ */
#endif /* !_HAVE_HASH_H */ #endif /* !_HAVE_HASH_H */

View File

@ -5,3 +5,4 @@ void setup_shm(unsigned char dumb_mode);
void remove_shm(void); void remove_shm(void);
#endif #endif

View File

@ -46,26 +46,31 @@ typedef unsigned long long u64;
typedef uint64_t u64; typedef uint64_t u64;
#endif /* ^__x86_64__ */ #endif /* ^__x86_64__ */
typedef int8_t s8; typedef int8_t s8;
typedef int16_t s16; typedef int16_t s16;
typedef int32_t s32; typedef int32_t s32;
typedef int64_t s64; typedef int64_t s64;
#ifndef MIN #ifndef MIN
# define MIN(_a,_b) ((_a) > (_b) ? (_b) : (_a)) # define MIN(_a, _b) ((_a) > (_b) ? (_b) : (_a))
# define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) # define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#endif /* !MIN */ #endif /* !MIN */
#define SWAP16(_x) ({ \ #define SWAP16(_x) \
u16 _ret = (_x); \ ({ \
\
u16 _ret = (_x); \
(u16)((_ret << 8) | (_ret >> 8)); \ (u16)((_ret << 8) | (_ret >> 8)); \
\
}) })
#define SWAP32(_x) ({ \ #define SWAP32(_x) \
u32 _ret = (_x); \ ({ \
(u32)((_ret << 24) | (_ret >> 24) | \ \
((_ret << 8) & 0x00FF0000) | \ u32 _ret = (_x); \
((_ret >> 8) & 0x0000FF00)); \ (u32)((_ret << 24) | (_ret >> 24) | ((_ret << 8) & 0x00FF0000) | \
((_ret >> 8) & 0x0000FF00)); \
\
}) })
#ifdef AFL_LLVM_PASS #ifdef AFL_LLVM_PASS
@ -77,15 +82,15 @@ typedef int64_t s64;
#define STRINGIFY_INTERNAL(x) #x #define STRINGIFY_INTERNAL(x) #x
#define STRINGIFY(x) STRINGIFY_INTERNAL(x) #define STRINGIFY(x) STRINGIFY_INTERNAL(x)
#define MEM_BARRIER() \ #define MEM_BARRIER() __asm__ volatile("" ::: "memory")
__asm__ volatile("" ::: "memory")
#if __GNUC__ < 6 #if __GNUC__ < 6
#define likely(_x) (_x) # define likely(_x) (_x)
#define unlikely(_x) (_x) # define unlikely(_x) (_x)
#else #else
#define likely(_x) __builtin_expect(!!(_x), 1) # define likely(_x) __builtin_expect(!!(_x), 1)
#define unlikely(_x) __builtin_expect(!!(_x), 0) # define unlikely(_x) __builtin_expect(!!(_x), 0)
#endif #endif
#endif /* ! _HAVE_TYPES_H */ #endif /* ! _HAVE_TYPES_H */

View File

@ -38,23 +38,35 @@
/* Error / message handling: */ /* Error / message handling: */
#define DEBUGF(_x...) do { \ #define DEBUGF(_x...) \
if (alloc_verbose) { \ do { \
if (++call_depth == 1) { \ \
if (alloc_verbose) { \
\
if (++call_depth == 1) { \
\
fprintf(stderr, "[AFL] " _x); \ fprintf(stderr, "[AFL] " _x); \
fprintf(stderr, "\n"); \ fprintf(stderr, "\n"); \
} \ \
call_depth--; \ } \
} \ call_depth--; \
\
} \
\
} while (0) } while (0)
#define FATAL(_x...) do { \ #define FATAL(_x...) \
if (++call_depth == 1) { \ do { \
\
if (++call_depth == 1) { \
\
fprintf(stderr, "*** [AFL] " _x); \ fprintf(stderr, "*** [AFL] " _x); \
fprintf(stderr, " ***\n"); \ fprintf(stderr, " ***\n"); \
abort(); \ abort(); \
} \ \
call_depth--; \ } \
call_depth--; \
\
} while (0) } while (0)
/* Macro to count the number of pages needed to store a buffer: */ /* Macro to count the number of pages needed to store a buffer: */
@ -63,7 +75,7 @@
/* Canary & clobber bytes: */ /* Canary & clobber bytes: */
#define ALLOC_CANARY 0xAACCAACC #define ALLOC_CANARY 0xAACCAACC
#define ALLOC_CLOBBER 0xCC #define ALLOC_CLOBBER 0xCC
#define PTR_C(_p) (((u32*)(_p))[-1]) #define PTR_C(_p) (((u32*)(_p))[-1])
@ -73,14 +85,13 @@
static u32 max_mem = MAX_ALLOC; /* Max heap usage to permit */ static u32 max_mem = MAX_ALLOC; /* Max heap usage to permit */
static u8 alloc_verbose, /* Additional debug messages */ static u8 alloc_verbose, /* Additional debug messages */
hard_fail, /* abort() when max_mem exceeded? */ hard_fail, /* abort() when max_mem exceeded? */
no_calloc_over; /* abort() on calloc() overflows? */ no_calloc_over; /* abort() on calloc() overflows? */
static __thread size_t total_mem; /* Currently allocated mem */ static __thread size_t total_mem; /* Currently allocated mem */
static __thread u32 call_depth; /* To avoid recursion via fprintf() */ static __thread u32 call_depth; /* To avoid recursion via fprintf() */
/* This is the main alloc function. It allocates one page more than necessary, /* This is the main alloc function. It allocates one page more than necessary,
sets that tailing page to PROT_NONE, and then increments the return address sets that tailing page to PROT_NONE, and then increments the return address
so that it is right-aligned to that boundary. Since it always uses mmap(), so that it is right-aligned to that boundary. Since it always uses mmap(),
@ -90,14 +101,11 @@ static void* __dislocator_alloc(size_t len) {
void* ret; void* ret;
if (total_mem + len > max_mem || total_mem + len < total_mem) { if (total_mem + len > max_mem || total_mem + len < total_mem) {
if (hard_fail) if (hard_fail) FATAL("total allocs exceed %u MB", max_mem / 1024 / 1024);
FATAL("total allocs exceed %u MB", max_mem / 1024 / 1024);
DEBUGF("total allocs exceed %u MB, returning NULL", DEBUGF("total allocs exceed %u MB, returning NULL", max_mem / 1024 / 1024);
max_mem / 1024 / 1024);
return NULL; return NULL;
@ -142,7 +150,6 @@ static void* __dislocator_alloc(size_t len) {
} }
/* The "user-facing" wrapper for calloc(). This just checks for overflows and /* The "user-facing" wrapper for calloc(). This just checks for overflows and
displays debug messages if requested. */ displays debug messages if requested. */
@ -157,8 +164,11 @@ void* calloc(size_t elem_len, size_t elem_cnt) {
if (elem_cnt && len / elem_cnt != elem_len) { if (elem_cnt && len / elem_cnt != elem_len) {
if (no_calloc_over) { if (no_calloc_over) {
DEBUGF("calloc(%zu, %zu) would overflow, returning NULL", elem_len, elem_cnt);
DEBUGF("calloc(%zu, %zu) would overflow, returning NULL", elem_len,
elem_cnt);
return NULL; return NULL;
} }
FATAL("calloc(%zu, %zu) would overflow", elem_len, elem_cnt); FATAL("calloc(%zu, %zu) would overflow", elem_len, elem_cnt);
@ -174,7 +184,6 @@ void* calloc(size_t elem_len, size_t elem_cnt) {
} }
/* The wrapper for malloc(). Roughly the same, also clobbers the returned /* The wrapper for malloc(). Roughly the same, also clobbers the returned
memory (unlike calloc(), malloc() is not guaranteed to return zeroed memory (unlike calloc(), malloc() is not guaranteed to return zeroed
memory). */ memory). */
@ -193,7 +202,6 @@ void* malloc(size_t len) {
} }
/* The wrapper for free(). This simply marks the entire region as PROT_NONE. /* The wrapper for free(). This simply marks the entire region as PROT_NONE.
If the region is already freed, the code will segfault during the attempt to If the region is already freed, the code will segfault during the attempt to
read the canary. Not very graceful, but works, right? */ read the canary. Not very graceful, but works, right? */
@ -224,7 +232,6 @@ void free(void* ptr) {
} }
/* Realloc is pretty straightforward, too. We forcibly reallocate the buffer, /* Realloc is pretty straightforward, too. We forcibly reallocate the buffer,
move data, and then free (aka mprotect()) the original one. */ move data, and then free (aka mprotect()) the original one. */
@ -249,7 +256,6 @@ void* realloc(void* ptr, size_t len) {
} }
__attribute__((constructor)) void __dislocator_init(void) { __attribute__((constructor)) void __dislocator_init(void) {
u8* tmp = getenv("AFL_LD_LIMIT_MB"); u8* tmp = getenv("AFL_LD_LIMIT_MB");
@ -266,3 +272,4 @@ __attribute__((constructor)) void __dislocator_init(void) {
no_calloc_over = !!getenv("AFL_LD_NO_CALLOC_OVER"); no_calloc_over = !!getenv("AFL_LD_NO_CALLOC_OVER");
} }

View File

@ -30,27 +30,23 @@
# error "Sorry, this library is Linux-specific for now!" # error "Sorry, this library is Linux-specific for now!"
#endif /* !__linux__ */ #endif /* !__linux__ */
/* Mapping data and such */ /* Mapping data and such */
#define MAX_MAPPINGS 1024 #define MAX_MAPPINGS 1024
static struct mapping { static struct mapping { void *st, *en; } __tokencap_ro[MAX_MAPPINGS];
void *st, *en;
} __tokencap_ro[MAX_MAPPINGS];
static u32 __tokencap_ro_cnt; static u32 __tokencap_ro_cnt;
static u8 __tokencap_ro_loaded; static u8 __tokencap_ro_loaded;
static FILE* __tokencap_out_file; static FILE* __tokencap_out_file;
/* Identify read-only regions in memory. Only parameters that fall into these /* Identify read-only regions in memory. Only parameters that fall into these
ranges are worth dumping when passed to strcmp() and so on. Read-write ranges are worth dumping when passed to strcmp() and so on. Read-write
regions are far more likely to contain user input instead. */ regions are far more likely to contain user input instead. */
static void __tokencap_load_mappings(void) { static void __tokencap_load_mappings(void) {
u8 buf[MAX_LINE]; u8 buf[MAX_LINE];
FILE* f = fopen("/proc/self/maps", "r"); FILE* f = fopen("/proc/self/maps", "r");
__tokencap_ro_loaded = 1; __tokencap_ro_loaded = 1;
@ -59,8 +55,8 @@ static void __tokencap_load_mappings(void) {
while (fgets(buf, MAX_LINE, f)) { while (fgets(buf, MAX_LINE, f)) {
u8 rf, wf; u8 rf, wf;
void* st, *en; void *st, *en;
if (sscanf(buf, "%p-%p %c%c", &st, &en, &rf, &wf) != 4) continue; if (sscanf(buf, "%p-%p %c%c", &st, &en, &rf, &wf) != 4) continue;
if (wf == 'w' || rf != 'r') continue; if (wf == 'w' || rf != 'r') continue;
@ -76,7 +72,6 @@ static void __tokencap_load_mappings(void) {
} }
/* Check an address against the list of read-only mappings. */ /* Check an address against the list of read-only mappings. */
static u8 __tokencap_is_ro(const void* ptr) { static u8 __tokencap_is_ro(const void* ptr) {
@ -85,20 +80,19 @@ static u8 __tokencap_is_ro(const void* ptr) {
if (!__tokencap_ro_loaded) __tokencap_load_mappings(); if (!__tokencap_ro_loaded) __tokencap_load_mappings();
for (i = 0; i < __tokencap_ro_cnt; i++) for (i = 0; i < __tokencap_ro_cnt; i++)
if (ptr >= __tokencap_ro[i].st && ptr <= __tokencap_ro[i].en) return 1; if (ptr >= __tokencap_ro[i].st && ptr <= __tokencap_ro[i].en) return 1;
return 0; return 0;
} }
/* Dump an interesting token to output file, quoting and escaping it /* Dump an interesting token to output file, quoting and escaping it
properly. */ properly. */
static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) { static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) {
u8 buf[MAX_AUTO_EXTRA * 4 + 1]; u8 buf[MAX_AUTO_EXTRA * 4 + 1];
u32 i; u32 i;
u32 pos = 0; u32 pos = 0;
@ -120,9 +114,7 @@ static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) {
pos += 4; pos += 4;
break; break;
default: default: buf[pos++] = ptr[i];
buf[pos++] = ptr[i];
} }
@ -130,11 +122,10 @@ static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) {
buf[pos] = 0; buf[pos] = 0;
fprintf(__tokencap_out_file, "\"%s\"\n", buf); fprintf(__tokencap_out_file, "\"%s\"\n", buf);
} }
/* Replacements for strcmp(), memcmp(), and so on. Note that these will be used /* Replacements for strcmp(), memcmp(), and so on. Note that these will be used
only if the target is compiled with -fno-builtins and linked dynamically. */ only if the target is compiled with -fno-builtins and linked dynamically. */
@ -151,13 +142,13 @@ int strcmp(const char* str1, const char* str2) {
if (c1 != c2) return (c1 > c2) ? 1 : -1; if (c1 != c2) return (c1 > c2) ? 1 : -1;
if (!c1) return 0; if (!c1) return 0;
str1++; str2++; str1++;
str2++;
} }
} }
#undef strncmp #undef strncmp
int strncmp(const char* str1, const char* str2, size_t len) { int strncmp(const char* str1, const char* str2, size_t len) {
@ -171,7 +162,8 @@ int strncmp(const char* str1, const char* str2, size_t len) {
if (!c1) return 0; if (!c1) return 0;
if (c1 != c2) return (c1 > c2) ? 1 : -1; if (c1 != c2) return (c1 > c2) ? 1 : -1;
str1++; str2++; str1++;
str2++;
} }
@ -179,7 +171,6 @@ int strncmp(const char* str1, const char* str2, size_t len) {
} }
#undef strcasecmp #undef strcasecmp
int strcasecmp(const char* str1, const char* str2) { int strcasecmp(const char* str1, const char* str2) {
@ -193,13 +184,13 @@ int strcasecmp(const char* str1, const char* str2) {
if (c1 != c2) return (c1 > c2) ? 1 : -1; if (c1 != c2) return (c1 > c2) ? 1 : -1;
if (!c1) return 0; if (!c1) return 0;
str1++; str2++; str1++;
str2++;
} }
} }
#undef strncasecmp #undef strncasecmp
int strncasecmp(const char* str1, const char* str2, size_t len) { int strncasecmp(const char* str1, const char* str2, size_t len) {
@ -213,7 +204,8 @@ int strncasecmp(const char* str1, const char* str2, size_t len) {
if (!c1) return 0; if (!c1) return 0;
if (c1 != c2) return (c1 > c2) ? 1 : -1; if (c1 != c2) return (c1 > c2) ? 1 : -1;
str1++; str2++; str1++;
str2++;
} }
@ -221,7 +213,6 @@ int strncasecmp(const char* str1, const char* str2, size_t len) {
} }
#undef memcmp #undef memcmp
int memcmp(const void* mem1, const void* mem2, size_t len) { int memcmp(const void* mem1, const void* mem2, size_t len) {
@ -233,7 +224,8 @@ int memcmp(const void* mem1, const void* mem2, size_t len) {
unsigned char c1 = *(const char*)mem1, c2 = *(const char*)mem2; unsigned char c1 = *(const char*)mem1, c2 = *(const char*)mem2;
if (c1 != c2) return (c1 > c2) ? 1 : -1; if (c1 != c2) return (c1 > c2) ? 1 : -1;
mem1++; mem2++; mem1++;
mem2++;
} }
@ -241,7 +233,6 @@ int memcmp(const void* mem1, const void* mem2, size_t len) {
} }
#undef strstr #undef strstr
char* strstr(const char* haystack, const char* needle) { char* strstr(const char* haystack, const char* needle) {
@ -249,16 +240,17 @@ char* strstr(const char* haystack, const char* needle) {
if (__tokencap_is_ro(haystack)) if (__tokencap_is_ro(haystack))
__tokencap_dump(haystack, strlen(haystack), 1); __tokencap_dump(haystack, strlen(haystack), 1);
if (__tokencap_is_ro(needle)) if (__tokencap_is_ro(needle)) __tokencap_dump(needle, strlen(needle), 1);
__tokencap_dump(needle, strlen(needle), 1);
do { do {
const char* n = needle; const char* n = needle;
const char* h = haystack; const char* h = haystack;
while(*n && *h && *n == *h) n++, h++; while (*n && *h && *n == *h)
n++, h++;
if(!*n) return (char*)haystack; if (!*n) return (char*)haystack;
} while (*(haystack++)); } while (*(haystack++));
@ -266,7 +258,6 @@ char* strstr(const char* haystack, const char* needle) {
} }
#undef strcasestr #undef strcasestr
char* strcasestr(const char* haystack, const char* needle) { char* strcasestr(const char* haystack, const char* needle) {
@ -274,25 +265,24 @@ char* strcasestr(const char* haystack, const char* needle) {
if (__tokencap_is_ro(haystack)) if (__tokencap_is_ro(haystack))
__tokencap_dump(haystack, strlen(haystack), 1); __tokencap_dump(haystack, strlen(haystack), 1);
if (__tokencap_is_ro(needle)) if (__tokencap_is_ro(needle)) __tokencap_dump(needle, strlen(needle), 1);
__tokencap_dump(needle, strlen(needle), 1);
do { do {
const char* n = needle; const char* n = needle;
const char* h = haystack; const char* h = haystack;
while(*n && *h && tolower(*n) == tolower(*h)) n++, h++; while (*n && *h && tolower(*n) == tolower(*h))
n++, h++;
if(!*n) return (char*)haystack; if (!*n) return (char*)haystack;
} while(*(haystack++)); } while (*(haystack++));
return 0; return 0;
} }
/* Init code to open the output file (or default to stderr). */ /* Init code to open the output file (or default to stderr). */
__attribute__((constructor)) void __tokencap_init(void) { __attribute__((constructor)) void __tokencap_init(void) {

View File

@ -37,268 +37,349 @@ static cl::opt<bool> LoopHeadOpt("loophead", cl::desc("LoopHead"),
cl::init(false)); cl::init(false));
namespace { namespace {
struct InsTrim : public ModulePass {
protected: struct InsTrim : public ModulePass {
std::list<std::string> myWhitelist;
private: protected:
std::mt19937 generator; std::list<std::string> myWhitelist;
int total_instr = 0;
unsigned int genLabel() { private:
return generator() & (MAP_SIZE - 1); std::mt19937 generator;
} int total_instr = 0;
public: unsigned int genLabel() {
static char ID;
InsTrim() : ModulePass(ID), generator(0) { return generator() & (MAP_SIZE - 1);
char* instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
if (instWhiteListFilename) { }
std::string line;
std::ifstream fileStream; public:
fileStream.open(instWhiteListFilename); static char ID;
if (!fileStream) InsTrim() : ModulePass(ID), generator(0) {
report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
if (instWhiteListFilename) {
std::string line;
std::ifstream fileStream;
fileStream.open(instWhiteListFilename);
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
getline(fileStream, line);
while (fileStream) {
myWhitelist.push_back(line);
getline(fileStream, line); getline(fileStream, line);
while (fileStream) {
myWhitelist.push_back(line);
getline(fileStream, line);
}
} }
} }
void getAnalysisUsage(AnalysisUsage &AU) const override { }
AU.addRequired<DominatorTreeWrapperPass>();
} void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<DominatorTreeWrapperPass>();
}
#if LLVM_VERSION_MAJOR < 4 #if LLVM_VERSION_MAJOR < 4
const char * const char *
#else #else
StringRef StringRef
#endif #endif
getPassName() const override { getPassName() const override {
return "InstTrim Instrumentation";
return "InstTrim Instrumentation";
}
bool runOnModule(Module &M) override {
char be_quiet = 0;
if (isatty(2) && !getenv("AFL_QUIET")) {
SAYF(cCYA "LLVMInsTrim" VERSION cRST " by csienslab\n");
} else
be_quiet = 1;
#if LLVM_VERSION_MAJOR < 9
char *neverZero_counters_str;
if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL)
OKF("LLVM neverZero activated (by hexcoder)\n");
#endif
if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL ||
getenv("LOOPHEAD") != NULL) {
LoopHeadOpt = true;
} }
bool runOnModule(Module &M) override { // this is our default
char be_quiet = 0; MarkSetOpt = true;
if (isatty(2) && !getenv("AFL_QUIET")) {
SAYF(cCYA "LLVMInsTrim" VERSION cRST " by csienslab\n");
} else be_quiet = 1;
#if LLVM_VERSION_MAJOR < 9
char* neverZero_counters_str;
if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL)
OKF("LLVM neverZero activated (by hexcoder)\n");
#endif
if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL || getenv("LOOPHEAD") != NULL) {
LoopHeadOpt = true;
}
// this is our default /* // I dont think this makes sense to port into LLVMInsTrim
MarkSetOpt = true; char* inst_ratio_str = getenv("AFL_INST_RATIO");
unsigned int inst_ratio = 100;
/* // I dont think this makes sense to port into LLVMInsTrim if (inst_ratio_str) {
char* inst_ratio_str = getenv("AFL_INST_RATIO");
unsigned int inst_ratio = 100;
if (inst_ratio_str) {
if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || !inst_ratio || inst_ratio > 100)
FATAL("Bad value of AFL_INST_RATIO (must be between 1 and 100)");
}
*/
LLVMContext &C = M.getContext(); if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || !inst_ratio ||
IntegerType *Int8Ty = IntegerType::getInt8Ty(C); inst_ratio > 100) FATAL("Bad value of AFL_INST_RATIO (must be between 1
IntegerType *Int32Ty = IntegerType::getInt32Ty(C); and 100)");
GlobalVariable *CovMapPtr = new GlobalVariable( }
*/
LLVMContext &C = M.getContext();
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
GlobalVariable *CovMapPtr = new GlobalVariable(
M, PointerType::getUnqual(Int8Ty), false, GlobalValue::ExternalLinkage, M, PointerType::getUnqual(Int8Ty), false, GlobalValue::ExternalLinkage,
nullptr, "__afl_area_ptr"); nullptr, "__afl_area_ptr");
GlobalVariable *OldPrev = new GlobalVariable( GlobalVariable *OldPrev = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0,
0, GlobalVariable::GeneralDynamicTLSModel, 0, false); GlobalVariable::GeneralDynamicTLSModel, 0, false);
u64 total_rs = 0; u64 total_rs = 0;
u64 total_hs = 0; u64 total_hs = 0;
for (Function &F : M) {
if (!F.size()) { continue; }
if (!myWhitelist.empty()) {
bool instrumentBlock = false;
DebugLoc Loc;
StringRef instFilename;
for (auto &BB : F) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
if (!Loc) Loc = IP->getDebugLoc();
for (Function &F : M) {
if (!F.size()) {
continue;
} }
if (!myWhitelist.empty()) { if (Loc) {
bool instrumentBlock = false;
DebugLoc Loc; DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
StringRef instFilename;
unsigned int instLine = cDILoc->getLine();
instFilename = cDILoc->getFilename();
if (instFilename.str().empty()) {
/* If the original location is empty, try using the inlined location
*/
DILocation *oDILoc = cDILoc->getInlinedAt();
if (oDILoc) {
instFilename = oDILoc->getFilename();
instLine = oDILoc->getLine();
}
for (auto &BB : F) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
if (!Loc)
Loc = IP->getDebugLoc();
} }
if ( Loc ) { /* Continue only if we know where we actually are */
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode()); if (!instFilename.str().empty()) {
unsigned int instLine = cDILoc->getLine(); for (std::list<std::string>::iterator it = myWhitelist.begin();
instFilename = cDILoc->getFilename(); it != myWhitelist.end(); ++it) {
if (instFilename.str().empty()) { if (instFilename.str().length() >= it->length()) {
/* If the original location is empty, try using the inlined location */
DILocation *oDILoc = cDILoc->getInlinedAt();
if (oDILoc) {
instFilename = oDILoc->getFilename();
instLine = oDILoc->getLine();
}
}
/* Continue only if we know where we actually are */ if (instFilename.str().compare(
if (!instFilename.str().empty()) { instFilename.str().length() - it->length(),
for (std::list<std::string>::iterator it = myWhitelist.begin(); it != myWhitelist.end(); ++it) { it->length(), *it) == 0) {
if (instFilename.str().length() >= it->length()) {
if (instFilename.str().compare(instFilename.str().length() - it->length(), it->length(), *it) == 0) {
instrumentBlock = true;
break;
}
}
}
}
}
/* Either we couldn't figure out our location or the location is instrumentBlock = true;
* not whitelisted, so we skip instrumentation. */
if (!instrumentBlock) {
if (!instFilename.str().empty())
SAYF(cYEL "[!] " cBRI "Not in whitelist, skipping %s ...\n", instFilename.str().c_str());
else
SAYF(cYEL "[!] " cBRI "No filename information found, skipping it");
continue;
}
}
std::unordered_set<BasicBlock *> MS;
if (!MarkSetOpt) {
for (auto &BB : F) {
MS.insert(&BB);
}
total_rs += F.size();
} else {
auto Result = markNodes(&F);
auto RS = Result.first;
auto HS = Result.second;
MS.insert(RS.begin(), RS.end());
if (!LoopHeadOpt) {
MS.insert(HS.begin(), HS.end());
total_rs += MS.size();
} else {
DenseSet<std::pair<BasicBlock *, BasicBlock *>> EdgeSet;
DominatorTreeWrapperPass *DTWP = &getAnalysis<DominatorTreeWrapperPass>(F);
auto DT = &DTWP->getDomTree();
total_rs += RS.size();
total_hs += HS.size();
for (BasicBlock *BB : HS) {
bool Inserted = false;
for (auto BI = pred_begin(BB), BE = pred_end(BB);
BI != BE; ++BI
) {
auto Edge = BasicBlockEdge(*BI, BB);
if (Edge.isSingleEdge() && DT->dominates(Edge, BB)) {
EdgeSet.insert({*BI, BB});
Inserted = true;
break; break;
} }
} }
if (!Inserted) {
MS.insert(BB);
total_rs += 1;
total_hs -= 1;
}
} }
for (auto I = EdgeSet.begin(), E = EdgeSet.end(); I != E; ++I) {
auto PredBB = I->first; }
auto SuccBB = I->second;
auto NewBB = SplitBlockPredecessors(SuccBB, {PredBB}, ".split", }
DT, nullptr,
/* Either we couldn't figure out our location or the location is
* not whitelisted, so we skip instrumentation. */
if (!instrumentBlock) {
if (!instFilename.str().empty())
SAYF(cYEL "[!] " cBRI "Not in whitelist, skipping %s ...\n",
instFilename.str().c_str());
else
SAYF(cYEL "[!] " cBRI "No filename information found, skipping it");
continue;
}
}
std::unordered_set<BasicBlock *> MS;
if (!MarkSetOpt) {
for (auto &BB : F) {
MS.insert(&BB);
}
total_rs += F.size();
} else {
auto Result = markNodes(&F);
auto RS = Result.first;
auto HS = Result.second;
MS.insert(RS.begin(), RS.end());
if (!LoopHeadOpt) {
MS.insert(HS.begin(), HS.end());
total_rs += MS.size();
} else {
DenseSet<std::pair<BasicBlock *, BasicBlock *>> EdgeSet;
DominatorTreeWrapperPass * DTWP =
&getAnalysis<DominatorTreeWrapperPass>(F);
auto DT = &DTWP->getDomTree();
total_rs += RS.size();
total_hs += HS.size();
for (BasicBlock *BB : HS) {
bool Inserted = false;
for (auto BI = pred_begin(BB), BE = pred_end(BB); BI != BE; ++BI) {
auto Edge = BasicBlockEdge(*BI, BB);
if (Edge.isSingleEdge() && DT->dominates(Edge, BB)) {
EdgeSet.insert({*BI, BB});
Inserted = true;
break;
}
}
if (!Inserted) {
MS.insert(BB);
total_rs += 1;
total_hs -= 1;
}
}
for (auto I = EdgeSet.begin(), E = EdgeSet.end(); I != E; ++I) {
auto PredBB = I->first;
auto SuccBB = I->second;
auto NewBB =
SplitBlockPredecessors(SuccBB, {PredBB}, ".split", DT, nullptr,
#if LLVM_VERSION_MAJOR >= 8 #if LLVM_VERSION_MAJOR >= 8
nullptr, nullptr,
#endif #endif
false); false);
MS.insert(NewBB); MS.insert(NewBB);
}
} }
auto *EBB = &F.getEntryBlock(); }
if (succ_begin(EBB) == succ_end(EBB)) {
MS.insert(EBB); auto *EBB = &F.getEntryBlock();
total_rs += 1; if (succ_begin(EBB) == succ_end(EBB)) {
}
MS.insert(EBB);
total_rs += 1;
for (BasicBlock &BB : F) {
if (MS.find(&BB) == MS.end()) {
continue;
}
IRBuilder<> IRB(&*BB.getFirstInsertionPt());
IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), OldPrev);
}
} }
for (BasicBlock &BB : F) { for (BasicBlock &BB : F) {
auto PI = pred_begin(&BB);
auto PE = pred_end(&BB);
if (MarkSetOpt && MS.find(&BB) == MS.end()) {
continue;
}
if (MS.find(&BB) == MS.end()) { continue; }
IRBuilder<> IRB(&*BB.getFirstInsertionPt()); IRBuilder<> IRB(&*BB.getFirstInsertionPt());
Value *L = NULL; IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), OldPrev);
if (PI == PE) {
L = ConstantInt::get(Int32Ty, genLabel()); }
} else {
auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin()); }
DenseMap<BasicBlock *, unsigned> PredMap;
for (auto PI = pred_begin(&BB), PE = pred_end(&BB); for (BasicBlock &BB : F) {
PI != PE; ++PI
) { auto PI = pred_begin(&BB);
BasicBlock *PBB = *PI; auto PE = pred_end(&BB);
auto It = PredMap.insert({PBB, genLabel()}); if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; }
unsigned Label = It.first->second;
PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB); IRBuilder<> IRB(&*BB.getFirstInsertionPt());
} Value * L = NULL;
L = PN; if (PI == PE) {
L = ConstantInt::get(Int32Ty, genLabel());
} else {
auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin());
DenseMap<BasicBlock *, unsigned> PredMap;
for (auto PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) {
BasicBlock *PBB = *PI;
auto It = PredMap.insert({PBB, genLabel()});
unsigned Label = It.first->second;
PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB);
} }
/* Load prev_loc */ L = PN;
LoadInst *PrevLoc = IRB.CreateLoad(OldPrev);
PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *PrevLocCasted = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
/* Load SHM pointer */ }
LoadInst *MapPtr = IRB.CreateLoad(CovMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocCasted, L));
/* Update bitmap */ /* Load prev_loc */
LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); LoadInst *PrevLoc = IRB.CreateLoad(OldPrev);
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *PrevLocCasted = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty());
Value *Incr = IRB.CreateAdd(Counter, ConstantInt::get(Int8Ty, 1));
/* Load SHM pointer */
LoadInst *MapPtr = IRB.CreateLoad(CovMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *MapPtrIdx =
IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocCasted, L));
/* Update bitmap */
LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *Incr = IRB.CreateAdd(Counter, ConstantInt::get(Int8Ty, 1));
#if LLVM_VERSION_MAJOR < 9 #if LLVM_VERSION_MAJOR < 9
if (neverZero_counters_str != NULL) // with llvm 9 we make this the default as the bug in llvm is then fixed if (neverZero_counters_str !=
NULL) // with llvm 9 we make this the default as the bug in llvm is
// then fixed
#else #else
if (1) // with llvm 9 we make this the default as the bug in llvm is then fixed if (1) // with llvm 9 we make this the default as the bug in llvm is
// then fixed
#endif #endif
{ {
/* hexcoder: Realize a counter that skips zero during overflow. /* hexcoder: Realize a counter that skips zero during overflow.
* Once this counter reaches its maximum value, it next increments to 1 * Once this counter reaches its maximum value, it next increments to
* 1
* *
* Instead of * Instead of
* Counter + 1 -> Counter * Counter + 1 -> Counter
@ -306,38 +387,52 @@ namespace {
* Counter + 1 -> {Counter, OverflowFlag} * Counter + 1 -> {Counter, OverflowFlag}
* Counter + OverflowFlag -> Counter * Counter + OverflowFlag -> Counter
*/ */
auto cf = IRB.CreateICmpEQ(Incr, ConstantInt::get(Int8Ty, 0)); auto cf = IRB.CreateICmpEQ(Incr, ConstantInt::get(Int8Ty, 0));
auto carry = IRB.CreateZExt(cf, Int8Ty); auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry); Incr = IRB.CreateAdd(Incr, carry);
}
IRB.CreateStore(Incr, MapPtrIdx)->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
/* Set prev_loc to cur_loc >> 1 */
/*
StoreInst *Store = IRB.CreateStore(ConstantInt::get(Int32Ty, L >> 1), OldPrev);
Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
*/
total_instr++;
} }
IRB.CreateStore(Incr, MapPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
/* Set prev_loc to cur_loc >> 1 */
/*
StoreInst *Store = IRB.CreateStore(ConstantInt::get(Int32Ty, L >> 1),
OldPrev); Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C,
None));
*/
total_instr++;
} }
OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n"/*", ratio %u%%)."*/,
total_instr, total_rs, total_hs,
getenv("AFL_HARDEN") ? "hardened" :
((getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) ?
"ASAN/MSAN" : "non-hardened")/*, inst_ratio*/);
return false;
} }
}; // end of struct InsTrim
OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n" /*", ratio
%u%%)."*/
,
total_instr, total_rs, total_hs,
getenv("AFL_HARDEN")
? "hardened"
: ((getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN"))
? "ASAN/MSAN"
: "non-hardened") /*, inst_ratio*/);
return false;
}
}; // end of struct InsTrim
} // end of anonymous namespace } // end of anonymous namespace
char InsTrim::ID = 0; char InsTrim::ID = 0;
static void registerAFLPass(const PassManagerBuilder &, static void registerAFLPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) { legacy::PassManagerBase &PM) {
PM.add(new InsTrim()); PM.add(new InsTrim());
} }
static RegisterStandardPasses RegisterAFLPass( static RegisterStandardPasses RegisterAFLPass(
@ -345,3 +440,4 @@ static RegisterStandardPasses RegisterAFLPass(
static RegisterStandardPasses RegisterAFLPass0( static RegisterStandardPasses RegisterAFLPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass); PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass);

View File

@ -19,207 +19,267 @@
using namespace llvm; using namespace llvm;
DenseMap<BasicBlock *, uint32_t> LMap; DenseMap<BasicBlock *, uint32_t> LMap;
std::vector<BasicBlock *> Blocks; std::vector<BasicBlock *> Blocks;
std::set<uint32_t> Marked , Markabove; std::set<uint32_t> Marked, Markabove;
std::vector< std::vector<uint32_t> > Succs , Preds; std::vector<std::vector<uint32_t> > Succs, Preds;
void reset() {
void reset(){
LMap.clear(); LMap.clear();
Blocks.clear(); Blocks.clear();
Marked.clear(); Marked.clear();
Markabove.clear(); Markabove.clear();
} }
uint32_t start_point; uint32_t start_point;
void labelEachBlock(Function *F) { void labelEachBlock(Function *F) {
// Fake single endpoint; // Fake single endpoint;
LMap[NULL] = Blocks.size(); LMap[NULL] = Blocks.size();
Blocks.push_back(NULL); Blocks.push_back(NULL);
// Assign the unique LabelID to each block; // Assign the unique LabelID to each block;
for (auto I = F->begin(), E = F->end(); I != E; ++I) { for (auto I = F->begin(), E = F->end(); I != E; ++I) {
BasicBlock *BB = &*I; BasicBlock *BB = &*I;
LMap[BB] = Blocks.size(); LMap[BB] = Blocks.size();
Blocks.push_back(BB); Blocks.push_back(BB);
} }
start_point = LMap[&F->getEntryBlock()]; start_point = LMap[&F->getEntryBlock()];
} }
void buildCFG(Function *F) { void buildCFG(Function *F) {
Succs.resize( Blocks.size() );
Preds.resize( Blocks.size() ); Succs.resize(Blocks.size());
for( size_t i = 0 ; i < Succs.size() ; i ++ ){ Preds.resize(Blocks.size());
Succs[ i ].clear(); for (size_t i = 0; i < Succs.size(); i++) {
Preds[ i ].clear();
Succs[i].clear();
Preds[i].clear();
} }
//uint32_t FakeID = 0; // uint32_t FakeID = 0;
for (auto S = F->begin(), E = F->end(); S != E; ++S) { for (auto S = F->begin(), E = F->end(); S != E; ++S) {
BasicBlock *BB = &*S; BasicBlock *BB = &*S;
uint32_t MyID = LMap[BB]; uint32_t MyID = LMap[BB];
//if (succ_begin(BB) == succ_end(BB)) { // if (succ_begin(BB) == succ_end(BB)) {
//Succs[MyID].push_back(FakeID);
//Marked.insert(MyID); // Succs[MyID].push_back(FakeID);
// Marked.insert(MyID);
//} //}
for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) { for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) {
Succs[MyID].push_back(LMap[*I]); Succs[MyID].push_back(LMap[*I]);
} }
} }
} }
std::vector< std::vector<uint32_t> > tSuccs; std::vector<std::vector<uint32_t> > tSuccs;
std::vector<bool> tag , indfs; std::vector<bool> tag, indfs;
void DFStree(size_t now_id) { void DFStree(size_t now_id) {
if(tag[now_id]) return;
tag[now_id]=true; if (tag[now_id]) return;
indfs[now_id]=true; tag[now_id] = true;
for (auto succ: tSuccs[now_id]) { indfs[now_id] = true;
if(tag[succ] and indfs[succ]) { for (auto succ : tSuccs[now_id]) {
if (tag[succ] and indfs[succ]) {
Marked.insert(succ); Marked.insert(succ);
Markabove.insert(succ); Markabove.insert(succ);
continue; continue;
} }
Succs[now_id].push_back(succ); Succs[now_id].push_back(succ);
Preds[succ].push_back(now_id); Preds[succ].push_back(now_id);
DFStree(succ); DFStree(succ);
} }
indfs[now_id]=false;
indfs[now_id] = false;
} }
void turnCFGintoDAG(Function *F) { void turnCFGintoDAG(Function *F) {
tSuccs = Succs; tSuccs = Succs;
tag.resize(Blocks.size()); tag.resize(Blocks.size());
indfs.resize(Blocks.size()); indfs.resize(Blocks.size());
for (size_t i = 0; i < Blocks.size(); ++ i) { for (size_t i = 0; i < Blocks.size(); ++i) {
Succs[i].clear(); Succs[i].clear();
tag[i]=false; tag[i] = false;
indfs[i]=false; indfs[i] = false;
} }
DFStree(start_point); DFStree(start_point);
for (size_t i = 0; i < Blocks.size(); ++ i) for (size_t i = 0; i < Blocks.size(); ++i)
if( Succs[i].empty() ){ if (Succs[i].empty()) {
Succs[i].push_back(0); Succs[i].push_back(0);
Preds[0].push_back(i); Preds[0].push_back(i);
} }
} }
uint32_t timeStamp; uint32_t timeStamp;
namespace DominatorTree{ namespace DominatorTree {
std::vector< std::vector<uint32_t> > cov;
std::vector<uint32_t> dfn, nfd, par, sdom, idom, mom, mn; std::vector<std::vector<uint32_t> > cov;
std::vector<uint32_t> dfn, nfd, par, sdom, idom, mom, mn;
bool Compare(uint32_t u, uint32_t v) {
return dfn[u] < dfn[v];
}
uint32_t eval(uint32_t u) {
if (mom[u] == u) return u;
uint32_t res = eval(mom[u]);
if (Compare(sdom[mn[mom[u]]], sdom[mn[u]])) { mn[u] = mn[mom[u]]; }
return mom[u] = res;
}
void DFS(uint32_t now) {
timeStamp += 1;
dfn[now] = timeStamp;
nfd[timeStamp - 1] = now;
for (auto succ : Succs[now]) {
if (dfn[succ] == 0) {
par[succ] = now;
DFS(succ);
bool Compare(uint32_t u, uint32_t v) {
return dfn[u] < dfn[v];
}
uint32_t eval(uint32_t u) {
if( mom[u] == u ) return u;
uint32_t res = eval( mom[u] );
if(Compare(sdom[mn[mom[u]]] , sdom[mn[u]])) {
mn[u] = mn[mom[u]];
} }
return mom[u] = res;
} }
void DFS(uint32_t now) { }
timeStamp += 1;
dfn[now] = timeStamp; void DominatorTree(Function *F) {
nfd[timeStamp - 1] = now;
for( auto succ : Succs[now] ) { if (Blocks.empty()) return;
if( dfn[succ] == 0 ) { uint32_t s = start_point;
par[succ] = now;
DFS(succ); // Initialization
} mn.resize(Blocks.size());
} cov.resize(Blocks.size());
dfn.resize(Blocks.size());
nfd.resize(Blocks.size());
par.resize(Blocks.size());
mom.resize(Blocks.size());
sdom.resize(Blocks.size());
idom.resize(Blocks.size());
for (uint32_t i = 0; i < Blocks.size(); i++) {
dfn[i] = 0;
nfd[i] = Blocks.size();
cov[i].clear();
idom[i] = mom[i] = mn[i] = sdom[i] = i;
} }
void DominatorTree(Function *F) { timeStamp = 0;
if( Blocks.empty() ) return; DFS(s);
uint32_t s = start_point;
// Initialization for (uint32_t i = Blocks.size() - 1; i >= 1u; i--) {
mn.resize(Blocks.size());
cov.resize(Blocks.size()); uint32_t now = nfd[i];
dfn.resize(Blocks.size()); if (now == Blocks.size()) { continue; }
nfd.resize(Blocks.size()); for (uint32_t pre : Preds[now]) {
par.resize(Blocks.size());
mom.resize(Blocks.size()); if (dfn[pre]) {
sdom.resize(Blocks.size());
idom.resize(Blocks.size()); eval(pre);
if (Compare(sdom[mn[pre]], sdom[now])) { sdom[now] = sdom[mn[pre]]; }
}
for( uint32_t i = 0 ; i < Blocks.size() ; i ++ ) {
dfn[i] = 0;
nfd[i] = Blocks.size();
cov[i].clear();
idom[i] = mom[i] = mn[i] = sdom[i] = i;
} }
timeStamp = 0; cov[sdom[now]].push_back(now);
DFS(s); mom[now] = par[now];
for (uint32_t x : cov[par[now]]) {
eval(x);
if (Compare(sdom[mn[x]], par[now])) {
idom[x] = mn[x];
} else {
idom[x] = par[now];
for( uint32_t i = Blocks.size() - 1 ; i >= 1u ; i -- ) {
uint32_t now = nfd[i];
if( now == Blocks.size() ) {
continue;
}
for( uint32_t pre : Preds[ now ] ) {
if( dfn[ pre ] ) {
eval(pre);
if( Compare(sdom[mn[pre]], sdom[now]) ) {
sdom[now] = sdom[mn[pre]];
}
}
}
cov[sdom[now]].push_back(now);
mom[now] = par[now];
for( uint32_t x : cov[par[now]] ) {
eval(x);
if( Compare(sdom[mn[x]], par[now]) ) {
idom[x] = mn[x];
} else {
idom[x] = par[now];
}
} }
} }
for( uint32_t i = 1 ; i < Blocks.size() ; i += 1 ) {
uint32_t now = nfd[i];
if( now == Blocks.size() ) {
continue;
}
if(idom[now] != sdom[now])
idom[now] = idom[idom[now]];
}
} }
} // End of DominatorTree
std::vector<uint32_t> Visited, InStack; for (uint32_t i = 1; i < Blocks.size(); i += 1) {
std::vector<uint32_t> TopoOrder, InDeg;
std::vector< std::vector<uint32_t> > t_Succ , t_Pred; uint32_t now = nfd[i];
if (now == Blocks.size()) { continue; }
if (idom[now] != sdom[now]) idom[now] = idom[idom[now]];
}
}
} // namespace DominatorTree
std::vector<uint32_t> Visited, InStack;
std::vector<uint32_t> TopoOrder, InDeg;
std::vector<std::vector<uint32_t> > t_Succ, t_Pred;
void Go(uint32_t now, uint32_t tt) { void Go(uint32_t now, uint32_t tt) {
if( now == tt ) return;
if (now == tt) return;
Visited[now] = InStack[now] = timeStamp; Visited[now] = InStack[now] = timeStamp;
for(uint32_t nxt : Succs[now]) { for (uint32_t nxt : Succs[now]) {
if(Visited[nxt] == timeStamp and InStack[nxt] == timeStamp) {
if (Visited[nxt] == timeStamp and InStack[nxt] == timeStamp) {
Marked.insert(nxt); Marked.insert(nxt);
} }
t_Succ[now].push_back(nxt); t_Succ[now].push_back(nxt);
t_Pred[nxt].push_back(now); t_Pred[nxt].push_back(now);
InDeg[nxt] += 1; InDeg[nxt] += 1;
if(Visited[nxt] == timeStamp) { if (Visited[nxt] == timeStamp) { continue; }
continue;
}
Go(nxt, tt); Go(nxt, tt);
} }
InStack[now] = 0; InStack[now] = 0;
} }
void TopologicalSort(uint32_t ss, uint32_t tt) { void TopologicalSort(uint32_t ss, uint32_t tt) {
timeStamp += 1; timeStamp += 1;
Go(ss, tt); Go(ss, tt);
@ -227,76 +287,111 @@ void TopologicalSort(uint32_t ss, uint32_t tt) {
TopoOrder.clear(); TopoOrder.clear();
std::queue<uint32_t> wait; std::queue<uint32_t> wait;
wait.push(ss); wait.push(ss);
while( not wait.empty() ) { while (not wait.empty()) {
uint32_t now = wait.front(); wait.pop();
uint32_t now = wait.front();
wait.pop();
TopoOrder.push_back(now); TopoOrder.push_back(now);
for(uint32_t nxt : t_Succ[now]) { for (uint32_t nxt : t_Succ[now]) {
InDeg[nxt] -= 1; InDeg[nxt] -= 1;
if(InDeg[nxt] == 0u) { if (InDeg[nxt] == 0u) { wait.push(nxt); }
wait.push(nxt);
}
} }
} }
} }
std::vector< std::set<uint32_t> > NextMarked; std::vector<std::set<uint32_t> > NextMarked;
bool Indistinguish(uint32_t node1, uint32_t node2) { bool Indistinguish(uint32_t node1, uint32_t node2) {
if(NextMarked[node1].size() > NextMarked[node2].size()){
if (NextMarked[node1].size() > NextMarked[node2].size()) {
uint32_t _swap = node1; uint32_t _swap = node1;
node1 = node2; node1 = node2;
node2 = _swap; node2 = _swap;
} }
for(uint32_t x : NextMarked[node1]) {
if( NextMarked[node2].find(x) != NextMarked[node2].end() ) { for (uint32_t x : NextMarked[node1]) {
return true;
} if (NextMarked[node2].find(x) != NextMarked[node2].end()) { return true; }
} }
return false; return false;
} }
void MakeUniq(uint32_t now) { void MakeUniq(uint32_t now) {
bool StopFlag = false; bool StopFlag = false;
if (Marked.find(now) == Marked.end()) { if (Marked.find(now) == Marked.end()) {
for(uint32_t pred1 : t_Pred[now]) {
for(uint32_t pred2 : t_Pred[now]) { for (uint32_t pred1 : t_Pred[now]) {
if(pred1 == pred2) continue;
if(Indistinguish(pred1, pred2)) { for (uint32_t pred2 : t_Pred[now]) {
if (pred1 == pred2) continue;
if (Indistinguish(pred1, pred2)) {
Marked.insert(now); Marked.insert(now);
StopFlag = true; StopFlag = true;
break; break;
} }
} }
if (StopFlag) {
break; if (StopFlag) { break; }
}
} }
} }
if(Marked.find(now) != Marked.end()) {
if (Marked.find(now) != Marked.end()) {
NextMarked[now].insert(now); NextMarked[now].insert(now);
} else { } else {
for(uint32_t pred : t_Pred[now]) {
for(uint32_t x : NextMarked[pred]) { for (uint32_t pred : t_Pred[now]) {
for (uint32_t x : NextMarked[pred]) {
NextMarked[now].insert(x); NextMarked[now].insert(x);
} }
} }
} }
} }
void MarkSubGraph(uint32_t ss, uint32_t tt) { void MarkSubGraph(uint32_t ss, uint32_t tt) {
TopologicalSort(ss, tt);
if(TopoOrder.empty()) return;
for(uint32_t i : TopoOrder) { TopologicalSort(ss, tt);
if (TopoOrder.empty()) return;
for (uint32_t i : TopoOrder) {
NextMarked[i].clear(); NextMarked[i].clear();
} }
NextMarked[TopoOrder[0]].insert(TopoOrder[0]); NextMarked[TopoOrder[0]].insert(TopoOrder[0]);
for(uint32_t i = 1 ; i < TopoOrder.size() ; i += 1) { for (uint32_t i = 1; i < TopoOrder.size(); i += 1) {
MakeUniq(TopoOrder[i]); MakeUniq(TopoOrder[i]);
} }
} }
void MarkVertice(Function *F) { void MarkVertice(Function *F) {
uint32_t s = start_point; uint32_t s = start_point;
InDeg.resize(Blocks.size()); InDeg.resize(Blocks.size());
@ -306,26 +401,32 @@ void MarkVertice(Function *F) {
t_Pred.resize(Blocks.size()); t_Pred.resize(Blocks.size());
NextMarked.resize(Blocks.size()); NextMarked.resize(Blocks.size());
for( uint32_t i = 0 ; i < Blocks.size() ; i += 1 ) { for (uint32_t i = 0; i < Blocks.size(); i += 1) {
Visited[i] = InStack[i] = InDeg[i] = 0; Visited[i] = InStack[i] = InDeg[i] = 0;
t_Succ[i].clear(); t_Succ[i].clear();
t_Pred[i].clear(); t_Pred[i].clear();
} }
timeStamp = 0; timeStamp = 0;
uint32_t t = 0; uint32_t t = 0;
//MarkSubGraph(s, t); // MarkSubGraph(s, t);
//return; // return;
while (s != t) {
while( s != t ) {
MarkSubGraph(DominatorTree::idom[t], t); MarkSubGraph(DominatorTree::idom[t], t);
t = DominatorTree::idom[t]; t = DominatorTree::idom[t];
} }
} }
// return {marked nodes} // return {marked nodes}
std::pair<std::vector<BasicBlock *>, std::pair<std::vector<BasicBlock *>, std::vector<BasicBlock *> > markNodes(
std::vector<BasicBlock *> >markNodes(Function *F) { Function *F) {
assert(F->size() > 0 && "Function can not be empty"); assert(F->size() > 0 && "Function can not be empty");
reset(); reset();
@ -335,21 +436,30 @@ std::pair<std::vector<BasicBlock *>,
DominatorTree::DominatorTree(F); DominatorTree::DominatorTree(F);
MarkVertice(F); MarkVertice(F);
std::vector<BasicBlock *> Result , ResultAbove; std::vector<BasicBlock *> Result, ResultAbove;
for( uint32_t x : Markabove ) { for (uint32_t x : Markabove) {
auto it = Marked.find( x );
if( it != Marked.end() ) auto it = Marked.find(x);
Marked.erase( it ); if (it != Marked.end()) Marked.erase(it);
if( x ) if (x) ResultAbove.push_back(Blocks[x]);
ResultAbove.push_back(Blocks[x]);
}
for( uint32_t x : Marked ) {
if (x == 0) {
continue;
} else {
Result.push_back(Blocks[x]);
}
} }
return { Result , ResultAbove }; for (uint32_t x : Marked) {
if (x == 0) {
continue;
} else {
Result.push_back(Blocks[x]);
}
}
return {Result, ResultAbove};
} }

View File

@ -1,11 +1,12 @@
#ifndef __MARK_NODES__ #ifndef __MARK_NODES__
#define __MARK_NODES__ # define __MARK_NODES__
#include "llvm/IR/BasicBlock.h" # include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h" # include "llvm/IR/Function.h"
#include<vector> # include <vector>
std::pair<std::vector<llvm::BasicBlock *>, std::pair<std::vector<llvm::BasicBlock *>, std::vector<llvm::BasicBlock *>>
std::vector<llvm::BasicBlock *>> markNodes(llvm::Function *F); markNodes(llvm::Function *F);
#endif #endif

View File

@ -34,16 +34,15 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
static u8* obj_path; /* Path to runtime libraries */ static u8* obj_path; /* Path to runtime libraries */
static u8** cc_params; /* Parameters passed to the real CC */ static u8** cc_params; /* Parameters passed to the real CC */
static u32 cc_par_cnt = 1; /* Param count, including argv0 */ static u32 cc_par_cnt = 1; /* Param count, including argv0 */
/* Try to find the runtime libraries. If that fails, abort. */ /* Try to find the runtime libraries. If that fails, abort. */
static void find_obj(u8* argv0) { static void find_obj(u8* argv0) {
u8 *afl_path = getenv("AFL_PATH"); u8* afl_path = getenv("AFL_PATH");
u8 *slash, *tmp; u8 *slash, *tmp;
if (afl_path) { if (afl_path) {
@ -51,9 +50,11 @@ static void find_obj(u8* argv0) {
tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path); tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path);
if (!access(tmp, R_OK)) { if (!access(tmp, R_OK)) {
obj_path = afl_path; obj_path = afl_path;
ck_free(tmp); ck_free(tmp);
return; return;
} }
ck_free(tmp); ck_free(tmp);
@ -64,7 +65,7 @@ static void find_obj(u8* argv0) {
if (slash) { if (slash) {
u8 *dir; u8* dir;
*slash = 0; *slash = 0;
dir = ck_strdup(argv0); dir = ck_strdup(argv0);
@ -73,9 +74,11 @@ static void find_obj(u8* argv0) {
tmp = alloc_printf("%s/afl-llvm-rt.o", dir); tmp = alloc_printf("%s/afl-llvm-rt.o", dir);
if (!access(tmp, R_OK)) { if (!access(tmp, R_OK)) {
obj_path = dir; obj_path = dir;
ck_free(tmp); ck_free(tmp);
return; return;
} }
ck_free(tmp); ck_free(tmp);
@ -84,33 +87,43 @@ static void find_obj(u8* argv0) {
} }
if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) { if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) {
obj_path = AFL_PATH; obj_path = AFL_PATH;
return; return;
} }
FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so.cc'. Please set AFL_PATH"); FATAL(
"Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so.cc'. Please set "
} "AFL_PATH");
}
/* Copy argv to cc_params, making the necessary edits. */ /* Copy argv to cc_params, making the necessary edits. */
static void edit_params(u32 argc, char** argv) { static void edit_params(u32 argc, char** argv) {
u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1, bit_mode = 0; u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1, bit_mode = 0;
u8 *name; u8* name;
cc_params = ck_alloc((argc + 128) * sizeof(u8*)); cc_params = ck_alloc((argc + 128) * sizeof(u8*));
name = strrchr(argv[0], '/'); name = strrchr(argv[0], '/');
if (!name) name = argv[0]; else name++; if (!name)
name = argv[0];
else
name++;
if (!strcmp(name, "afl-clang-fast++")) { if (!strcmp(name, "afl-clang-fast++")) {
u8* alt_cxx = getenv("AFL_CXX"); u8* alt_cxx = getenv("AFL_CXX");
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++";
} else { } else {
u8* alt_cc = getenv("AFL_CC"); u8* alt_cc = getenv("AFL_CC");
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";
} }
/* There are three ways to compile with afl-clang-fast. In the traditional /* There are three ways to compile with afl-clang-fast. In the traditional
@ -118,36 +131,50 @@ static void edit_params(u32 argc, char** argv) {
much faster but has less coverage. Finally tere is the experimental much faster but has less coverage. Finally tere is the experimental
'trace-pc-guard' mode, we use native LLVM instrumentation callbacks 'trace-pc-guard' mode, we use native LLVM instrumentation callbacks
instead. For trace-pc-guard see: instead. For trace-pc-guard see:
http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards */ http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards
*/
// laf // laf
if (getenv("LAF_SPLIT_SWITCHES")||getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) { if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = alloc_printf("%s/split-switches-pass.so", obj_path); cc_params[cc_par_cnt++] =
alloc_printf("%s/split-switches-pass.so", obj_path);
} }
if (getenv("LAF_TRANSFORM_COMPARES")||getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) { if (getenv("LAF_TRANSFORM_COMPARES") ||
getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = alloc_printf("%s/compare-transform-pass.so", obj_path); cc_params[cc_par_cnt++] =
alloc_printf("%s/compare-transform-pass.so", obj_path);
} }
if (getenv("LAF_SPLIT_COMPARES")||getenv("AFL_LLVM_LAF_SPLIT_COMPARES")) { if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES")) {
cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = alloc_printf("%s/split-compares-pass.so", obj_path); cc_params[cc_par_cnt++] =
alloc_printf("%s/split-compares-pass.so", obj_path);
} }
// /laf // /laf
#ifdef USE_TRACE_PC #ifdef USE_TRACE_PC
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; // edge coverage by default cc_params[cc_par_cnt++] =
//cc_params[cc_par_cnt++] = "-mllvm"; "-fsanitize-coverage=trace-pc-guard"; // edge coverage by default
//cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-cmp,trace-div,trace-gep"; // cc_params[cc_par_cnt++] = "-mllvm";
//cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0"; // cc_params[cc_par_cnt++] =
// "-fsanitize-coverage=trace-cmp,trace-div,trace-gep"; cc_params[cc_par_cnt++]
// = "-sanitizer-coverage-block-threshold=0";
#else #else
cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-load";
@ -165,6 +192,7 @@ static void edit_params(u32 argc, char** argv) {
if (argc == 1 && !strcmp(argv[1], "-v")) maybe_linking = 0; if (argc == 1 && !strcmp(argv[1], "-v")) maybe_linking = 0;
while (--argc) { while (--argc) {
u8* cur = *(++argv); u8* cur = *(++argv);
if (!strcmp(cur, "-m32")) bit_mode = 32; if (!strcmp(cur, "-m32")) bit_mode = 32;
@ -175,15 +203,15 @@ static void edit_params(u32 argc, char** argv) {
if (!strcmp(cur, "-c") || !strcmp(cur, "-S") || !strcmp(cur, "-E")) if (!strcmp(cur, "-c") || !strcmp(cur, "-S") || !strcmp(cur, "-E"))
maybe_linking = 0; maybe_linking = 0;
if (!strcmp(cur, "-fsanitize=address") || if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
!strcmp(cur, "-fsanitize=memory")) asan_set = 1; asan_set = 1;
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
if (!strcmp(cur, "-shared")) maybe_linking = 0; if (!strcmp(cur, "-shared")) maybe_linking = 0;
if (!strcmp(cur, "-Wl,-z,defs") || if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined"))
!strcmp(cur, "-Wl,--no-undefined")) continue; continue;
cc_params[cc_par_cnt++] = cur; cc_params[cc_par_cnt++] = cur;
@ -193,8 +221,7 @@ static void edit_params(u32 argc, char** argv) {
cc_params[cc_par_cnt++] = "-fstack-protector-all"; cc_params[cc_par_cnt++] = "-fstack-protector-all";
if (!fortify_set) if (!fortify_set) cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
} }
@ -202,8 +229,7 @@ static void edit_params(u32 argc, char** argv) {
if (getenv("AFL_USE_ASAN")) { if (getenv("AFL_USE_ASAN")) {
if (getenv("AFL_USE_MSAN")) if (getenv("AFL_USE_MSAN")) FATAL("ASAN and MSAN are mutually exclusive");
FATAL("ASAN and MSAN are mutually exclusive");
if (getenv("AFL_HARDEN")) if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive"); FATAL("ASAN and AFL_HARDEN are mutually exclusive");
@ -213,8 +239,7 @@ static void edit_params(u32 argc, char** argv) {
} else if (getenv("AFL_USE_MSAN")) { } else if (getenv("AFL_USE_MSAN")) {
if (getenv("AFL_USE_ASAN")) if (getenv("AFL_USE_ASAN")) FATAL("ASAN and MSAN are mutually exclusive");
FATAL("ASAN and MSAN are mutually exclusive");
if (getenv("AFL_HARDEN")) if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive"); FATAL("MSAN and AFL_HARDEN are mutually exclusive");
@ -279,35 +304,41 @@ static void edit_params(u32 argc, char** argv) {
*/ */
cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)=" cc_params[cc_par_cnt++] =
"({ static volatile char *_B __attribute__((used)); " "-D__AFL_LOOP(_A)="
" _B = (char*)\"" PERSIST_SIG "\"; " "({ static volatile char *_B __attribute__((used)); "
" _B = (char*)\"" PERSIST_SIG
"\"; "
#ifdef __APPLE__ #ifdef __APPLE__
"__attribute__((visibility(\"default\"))) " "__attribute__((visibility(\"default\"))) "
"int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); " "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
#else #else
"__attribute__((visibility(\"default\"))) " "__attribute__((visibility(\"default\"))) "
"int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); " "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
#endif /* ^__APPLE__ */ #endif /* ^__APPLE__ */
"_L(_A); })"; "_L(_A); })";
cc_params[cc_par_cnt++] = "-D__AFL_INIT()=" cc_params[cc_par_cnt++] =
"do { static volatile char *_A __attribute__((used)); " "-D__AFL_INIT()="
" _A = (char*)\"" DEFER_SIG "\"; " "do { static volatile char *_A __attribute__((used)); "
" _A = (char*)\"" DEFER_SIG
"\"; "
#ifdef __APPLE__ #ifdef __APPLE__
"__attribute__((visibility(\"default\"))) " "__attribute__((visibility(\"default\"))) "
"void _I(void) __asm__(\"___afl_manual_init\"); " "void _I(void) __asm__(\"___afl_manual_init\"); "
#else #else
"__attribute__((visibility(\"default\"))) " "__attribute__((visibility(\"default\"))) "
"void _I(void) __asm__(\"__afl_manual_init\"); " "void _I(void) __asm__(\"__afl_manual_init\"); "
#endif /* ^__APPLE__ */ #endif /* ^__APPLE__ */
"_I(); } while (0)"; "_I(); } while (0)";
if (maybe_linking) { if (maybe_linking) {
if (x_set) { if (x_set) {
cc_params[cc_par_cnt++] = "-x"; cc_params[cc_par_cnt++] = "-x";
cc_params[cc_par_cnt++] = "none"; cc_params[cc_par_cnt++] = "none";
} }
switch (bit_mode) { switch (bit_mode) {
@ -340,7 +371,6 @@ static void edit_params(u32 argc, char** argv) {
} }
/* Main entry point */ /* Main entry point */
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -348,46 +378,53 @@ int main(int argc, char** argv) {
if (isatty(2) && !getenv("AFL_QUIET")) { if (isatty(2) && !getenv("AFL_QUIET")) {
#ifdef USE_TRACE_PC #ifdef USE_TRACE_PC
SAYF(cCYA "afl-clang-fast" VERSION cRST " [tpcg] by <lszekeres@google.com>\n"); SAYF(cCYA "afl-clang-fast" VERSION cRST
" [tpcg] by <lszekeres@google.com>\n");
#else #else
SAYF(cCYA "afl-clang-fast" VERSION cRST " by <lszekeres@google.com>\n"); SAYF(cCYA "afl-clang-fast" VERSION cRST " by <lszekeres@google.com>\n");
#endif /* ^USE_TRACE_PC */ #endif /* ^USE_TRACE_PC */
} }
if (argc < 2) { if (argc < 2) {
SAYF("\n" SAYF(
"This is a helper application for afl-fuzz. It serves as a drop-in replacement\n" "\n"
"for clang, letting you recompile third-party code with the required runtime\n" "This is a helper application for afl-fuzz. It serves as a drop-in "
"instrumentation. A common use pattern would be one of the following:\n\n" "replacement\n"
"for clang, letting you recompile third-party code with the required "
"runtime\n"
"instrumentation. A common use pattern would be one of the "
"following:\n\n"
" CC=%s/afl-clang-fast ./configure\n" " CC=%s/afl-clang-fast ./configure\n"
" CXX=%s/afl-clang-fast++ ./configure\n\n" " CXX=%s/afl-clang-fast++ ./configure\n\n"
"In contrast to the traditional afl-clang tool, this version is implemented as\n" "In contrast to the traditional afl-clang tool, this version is "
"an LLVM pass and tends to offer improved performance with slow programs.\n\n" "implemented as\n"
"an LLVM pass and tends to offer improved performance with slow "
"programs.\n\n"
"You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. Setting\n" "You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. "
"AFL_HARDEN enables hardening optimizations in the compiled code.\n\n", "Setting\n"
BIN_PATH, BIN_PATH); "AFL_HARDEN enables hardening optimizations in the compiled code.\n\n",
BIN_PATH, BIN_PATH);
exit(1); exit(1);
} }
find_obj(argv[0]); find_obj(argv[0]);
edit_params(argc, argv); edit_params(argc, argv);
/* /*
int i = 0; int i = 0;
printf("EXEC:"); printf("EXEC:");
while (cc_params[i] != NULL) while (cc_params[i] != NULL)
printf(" %s", cc_params[i++]); printf(" %s", cc_params[i++]);
printf("\n"); printf("\n");
*/ */
execvp(cc_params[0], (char**)cc_params); execvp(cc_params[0], (char**)cc_params);
@ -396,3 +433,4 @@ int main(int argc, char** argv) {
return 0; return 0;
} }

View File

@ -48,50 +48,52 @@ using namespace llvm;
namespace { namespace {
class AFLCoverage : public ModulePass { class AFLCoverage : public ModulePass {
public: public:
static char ID;
AFLCoverage() : ModulePass(ID) {
char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
if (instWhiteListFilename) {
std::string line;
std::ifstream fileStream;
fileStream.open(instWhiteListFilename);
if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
getline(fileStream, line);
while (fileStream) {
myWhitelist.push_back(line);
getline(fileStream, line);
static char ID;
AFLCoverage() : ModulePass(ID) {
char* instWhiteListFilename = getenv("AFL_LLVM_WHITELIST");
if (instWhiteListFilename) {
std::string line;
std::ifstream fileStream;
fileStream.open(instWhiteListFilename);
if (!fileStream)
report_fatal_error("Unable to open AFL_LLVM_WHITELIST");
getline(fileStream, line);
while (fileStream) {
myWhitelist.push_back(line);
getline(fileStream, line);
}
}
} }
bool runOnModule(Module &M) override; }
// StringRef getPassName() const override { }
// return "American Fuzzy Lop Instrumentation";
// }
protected: bool runOnModule(Module &M) override;
std::list<std::string> myWhitelist; // StringRef getPassName() const override {
}; // return "American Fuzzy Lop Instrumentation";
// }
} protected:
std::list<std::string> myWhitelist;
};
} // namespace
char AFLCoverage::ID = 0; char AFLCoverage::ID = 0;
bool AFLCoverage::runOnModule(Module &M) { bool AFLCoverage::runOnModule(Module &M) {
LLVMContext &C = M.getContext(); LLVMContext &C = M.getContext();
IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C); IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
unsigned int cur_loc = 0; unsigned int cur_loc = 0;
@ -103,11 +105,13 @@ bool AFLCoverage::runOnModule(Module &M) {
SAYF(cCYA "afl-llvm-pass" VERSION cRST " by <lszekeres@google.com>\n"); SAYF(cCYA "afl-llvm-pass" VERSION cRST " by <lszekeres@google.com>\n");
} else be_quiet = 1; } else
be_quiet = 1;
/* Decide instrumentation ratio */ /* Decide instrumentation ratio */
char* inst_ratio_str = getenv("AFL_INST_RATIO"); char * inst_ratio_str = getenv("AFL_INST_RATIO");
unsigned int inst_ratio = 100; unsigned int inst_ratio = 100;
if (inst_ratio_str) { if (inst_ratio_str) {
@ -119,7 +123,7 @@ bool AFLCoverage::runOnModule(Module &M) {
} }
#if LLVM_VERSION_MAJOR < 9 #if LLVM_VERSION_MAJOR < 9
char* neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO"); char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
#endif #endif
/* Get globals for the SHM region and the previous location. Note that /* Get globals for the SHM region and the previous location. Note that
@ -134,8 +138,8 @@ bool AFLCoverage::runOnModule(Module &M) {
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc");
#else #else
GlobalVariable *AFLPrevLoc = new GlobalVariable( GlobalVariable *AFLPrevLoc = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0,
0, GlobalVariable::GeneralDynamicTLSModel, 0, false); GlobalVariable::GeneralDynamicTLSModel, 0, false);
#endif #endif
/* Instrument all the things! */ /* Instrument all the things! */
@ -146,58 +150,77 @@ bool AFLCoverage::runOnModule(Module &M) {
for (auto &BB : F) { for (auto &BB : F) {
BasicBlock::iterator IP = BB.getFirstInsertionPt(); BasicBlock::iterator IP = BB.getFirstInsertionPt();
IRBuilder<> IRB(&(*IP)); IRBuilder<> IRB(&(*IP));
if (!myWhitelist.empty()) { if (!myWhitelist.empty()) {
bool instrumentBlock = false;
/* Get the current location using debug information. bool instrumentBlock = false;
* For now, just instrument the block if we are not able
* to determine our location. */
DebugLoc Loc = IP->getDebugLoc();
if ( Loc ) {
DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
unsigned int instLine = cDILoc->getLine(); /* Get the current location using debug information.
StringRef instFilename = cDILoc->getFilename(); * For now, just instrument the block if we are not able
* to determine our location. */
DebugLoc Loc = IP->getDebugLoc();
if (Loc) {
if (instFilename.str().empty()) { DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
/* If the original location is empty, try using the inlined location */
DILocation *oDILoc = cDILoc->getInlinedAt(); unsigned int instLine = cDILoc->getLine();
if (oDILoc) { StringRef instFilename = cDILoc->getFilename();
instFilename = oDILoc->getFilename();
instLine = oDILoc->getLine(); if (instFilename.str().empty()) {
}
} /* If the original location is empty, try using the inlined location
*/
DILocation *oDILoc = cDILoc->getInlinedAt();
if (oDILoc) {
instFilename = oDILoc->getFilename();
instLine = oDILoc->getLine();
}
/* Continue only if we know where we actually are */
if (!instFilename.str().empty()) {
for (std::list<std::string>::iterator it = myWhitelist.begin(); it != myWhitelist.end(); ++it) {
/* We don't check for filename equality here because
* filenames might actually be full paths. Instead we
* check that the actual filename ends in the filename
* specified in the list. */
if (instFilename.str().length() >= it->length()) {
if (instFilename.str().compare(instFilename.str().length() - it->length(), it->length(), *it) == 0) {
instrumentBlock = true;
break;
}
}
}
}
} }
/* Either we couldn't figure out our location or the location is /* Continue only if we know where we actually are */
* not whitelisted, so we skip instrumentation. */ if (!instFilename.str().empty()) {
if (!instrumentBlock) continue;
}
for (std::list<std::string>::iterator it = myWhitelist.begin();
it != myWhitelist.end(); ++it) {
/* We don't check for filename equality here because
* filenames might actually be full paths. Instead we
* check that the actual filename ends in the filename
* specified in the list. */
if (instFilename.str().length() >= it->length()) {
if (instFilename.str().compare(
instFilename.str().length() - it->length(),
it->length(), *it) == 0) {
instrumentBlock = true;
break;
}
}
}
}
}
/* Either we couldn't figure out our location or the location is
* not whitelisted, so we skip instrumentation. */
if (!instrumentBlock) continue;
}
if (AFL_R(100) >= inst_ratio) continue; if (AFL_R(100) >= inst_ratio) continue;
/* Make up cur_loc */ /* Make up cur_loc */
//cur_loc++; // cur_loc++;
cur_loc = AFL_R(MAP_SIZE); cur_loc = AFL_R(MAP_SIZE);
// only instrument if this basic block is the destination of a previous // only instrument if this basic block is the destination of a previous
@ -205,24 +228,27 @@ bool AFLCoverage::runOnModule(Module &M) {
// this gets rid of ~5-10% of instrumentations that are unnecessary // this gets rid of ~5-10% of instrumentations that are unnecessary
// result: a little more speed and less map pollution // result: a little more speed and less map pollution
int more_than_one = -1; int more_than_one = -1;
//fprintf(stderr, "BB %u: ", cur_loc); // fprintf(stderr, "BB %u: ", cur_loc);
for (BasicBlock *Pred : predecessors(&BB)) { for (BasicBlock *Pred : predecessors(&BB)) {
int count = 0; int count = 0;
if (more_than_one == -1) if (more_than_one == -1) more_than_one = 0;
more_than_one = 0; // fprintf(stderr, " %p=>", Pred);
//fprintf(stderr, " %p=>", Pred);
for (BasicBlock *Succ : successors(Pred)) { for (BasicBlock *Succ : successors(Pred)) {
//if (count > 0)
// if (count > 0)
// fprintf(stderr, "|"); // fprintf(stderr, "|");
if (Succ != NULL) count++; if (Succ != NULL) count++;
//fprintf(stderr, "%p", Succ); // fprintf(stderr, "%p", Succ);
} }
if (count > 1)
more_than_one = 1; if (count > 1) more_than_one = 1;
} }
//fprintf(stderr, " == %d\n", more_than_one);
if (more_than_one != 1) // fprintf(stderr, " == %d\n", more_than_one);
continue; if (more_than_one != 1) continue;
ConstantInt *CurLoc = ConstantInt::get(Int32Ty, cur_loc); ConstantInt *CurLoc = ConstantInt::get(Int32Ty, cur_loc);
@ -236,7 +262,8 @@ bool AFLCoverage::runOnModule(Module &M) {
LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr); LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr);
MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocCasted, CurLoc)); Value *MapPtrIdx =
IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocCasted, CurLoc));
/* Update bitmap */ /* Update bitmap */
@ -246,7 +273,9 @@ bool AFLCoverage::runOnModule(Module &M) {
Value *Incr = IRB.CreateAdd(Counter, ConstantInt::get(Int8Ty, 1)); Value *Incr = IRB.CreateAdd(Counter, ConstantInt::get(Int8Ty, 1));
#if LLVM_VERSION_MAJOR < 9 #if LLVM_VERSION_MAJOR < 9
if (neverZero_counters_str != NULL) { // with llvm 9 we make this the default as the bug in llvm is then fixed if (neverZero_counters_str !=
NULL) { // with llvm 9 we make this the default as the bug in llvm is
// then fixed
#endif #endif
/* hexcoder: Realize a counter that skips zero during overflow. /* hexcoder: Realize a counter that skips zero during overflow.
* Once this counter reaches its maximum value, it next increments to 1 * Once this counter reaches its maximum value, it next increments to 1
@ -257,48 +286,67 @@ bool AFLCoverage::runOnModule(Module &M) {
* Counter + 1 -> {Counter, OverflowFlag} * Counter + 1 -> {Counter, OverflowFlag}
* Counter + OverflowFlag -> Counter * Counter + OverflowFlag -> Counter
*/ */
/* // we keep the old solutions just in case /* // we keep the old solutions just in case
// Solution #1 // Solution #1
if (neverZero_counters_str[0] == '1') { if (neverZero_counters_str[0] == '1') {
CallInst *AddOv = IRB.CreateBinaryIntrinsic(Intrinsic::uadd_with_overflow, Counter, ConstantInt::get(Int8Ty, 1));
AddOv->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); CallInst *AddOv =
Value *SumWithOverflowBit = AddOv; IRB.CreateBinaryIntrinsic(Intrinsic::uadd_with_overflow, Counter,
Incr = IRB.CreateAdd(IRB.CreateExtractValue(SumWithOverflowBit, 0), // sum ConstantInt::get(Int8Ty, 1));
IRB.CreateZExt( // convert from one bit type to 8 bits type AddOv->setMetadata(M.getMDKindID("nosanitize"),
IRB.CreateExtractValue(SumWithOverflowBit, 1), // overflow MDNode::get(C, None)); Value *SumWithOverflowBit = AddOv; Incr =
Int8Ty)); IRB.CreateAdd(IRB.CreateExtractValue(SumWithOverflowBit, 0), // sum
// Solution #2 IRB.CreateZExt( // convert from one bit
} else if (neverZero_counters_str[0] == '2') { type to 8 bits type IRB.CreateExtractValue(SumWithOverflowBit, 1), //
auto cf = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, 255)); overflow Int8Ty));
Value *HowMuch = IRB.CreateAdd(ConstantInt::get(Int8Ty, 1), cf); // Solution #2
Incr = IRB.CreateAdd(Counter, HowMuch);
// Solution #3 } else if (neverZero_counters_str[0] == '2') {
} else if (neverZero_counters_str[0] == '3') {
*/ auto cf = IRB.CreateICmpEQ(Counter,
// this is the solution we choose because llvm9 should do the right thing here ConstantInt::get(Int8Ty, 255)); Value *HowMuch =
auto cf = IRB.CreateICmpEQ(Incr, ConstantInt::get(Int8Ty, 0)); IRB.CreateAdd(ConstantInt::get(Int8Ty, 1), cf); Incr =
auto carry = IRB.CreateZExt(cf, Int8Ty); IRB.CreateAdd(Counter, HowMuch);
Incr = IRB.CreateAdd(Incr, carry); // Solution #3
} else if (neverZero_counters_str[0] == '3') {
*/
// this is the solution we choose because llvm9 should do the right
// thing here
auto cf = IRB.CreateICmpEQ(Incr, ConstantInt::get(Int8Ty, 0));
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
/* /*
// Solution #4 // Solution #4
} else if (neverZero_counters_str[0] == '4') { } else if (neverZero_counters_str[0] == '4') {
auto cf = IRB.CreateICmpULT(Incr, ConstantInt::get(Int8Ty, 1)); auto cf = IRB.CreateICmpULT(Incr, ConstantInt::get(Int8Ty, 1));
auto carry = IRB.CreateZExt(cf, Int8Ty); auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry); Incr = IRB.CreateAdd(Incr, carry);
} else { } else {
fprintf(stderr, "Error: unknown value for AFL_NZERO_COUNTS: %s (valid is 1-4)\n", neverZero_counters_str);
exit(-1); fprintf(stderr, "Error: unknown value for AFL_NZERO_COUNTS: %s
(valid is 1-4)\n", neverZero_counters_str); exit(-1);
} }
*/ */
#if LLVM_VERSION_MAJOR < 9 #if LLVM_VERSION_MAJOR < 9
} }
#endif #endif
IRB.CreateStore(Incr, MapPtrIdx)->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); IRB.CreateStore(Incr, MapPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
/* Set prev_loc to cur_loc >> 1 */ /* Set prev_loc to cur_loc >> 1 */
StoreInst *Store = IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1), AFLPrevLoc); StoreInst *Store =
IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1), AFLPrevLoc);
Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
inst_blocks++; inst_blocks++;
@ -309,11 +357,16 @@ bool AFLCoverage::runOnModule(Module &M) {
if (!be_quiet) { if (!be_quiet) {
if (!inst_blocks) WARNF("No instrumentation targets found."); if (!inst_blocks)
else OKF("Instrumented %u locations (%s mode, ratio %u%%).", WARNF("No instrumentation targets found.");
inst_blocks, getenv("AFL_HARDEN") ? "hardened" : else
((getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) ? OKF("Instrumented %u locations (%s mode, ratio %u%%).", inst_blocks,
"ASAN/MSAN" : "non-hardened"), inst_ratio); getenv("AFL_HARDEN")
? "hardened"
: ((getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN"))
? "ASAN/MSAN"
: "non-hardened"),
inst_ratio);
} }
@ -321,7 +374,6 @@ bool AFLCoverage::runOnModule(Module &M) {
} }
static void registerAFLPass(const PassManagerBuilder &, static void registerAFLPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) { legacy::PassManagerBase &PM) {
@ -329,9 +381,9 @@ static void registerAFLPass(const PassManagerBuilder &,
} }
static RegisterStandardPasses RegisterAFLPass( static RegisterStandardPasses RegisterAFLPass(
PassManagerBuilder::EP_OptimizerLast, registerAFLPass); PassManagerBuilder::EP_OptimizerLast, registerAFLPass);
static RegisterStandardPasses RegisterAFLPass0( static RegisterStandardPasses RegisterAFLPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass); PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass);

View File

@ -20,7 +20,7 @@
*/ */
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "android-ashmem.h" # include "android-ashmem.h"
#endif #endif
#include "config.h" #include "config.h"
#include "types.h" #include "types.h"
@ -50,10 +50,9 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <fcntl.h> #include <fcntl.h>
/* Globals needed by the injected instrumentation. The __afl_area_initial region /* Globals needed by the injected instrumentation. The __afl_area_initial region
is used for instrumentation output before __afl_map_shm() has a chance to run. is used for instrumentation output before __afl_map_shm() has a chance to
It will end up as .comm, so it shouldn't be too wasteful. */ run. It will end up as .comm, so it shouldn't be too wasteful. */
u8 __afl_area_initial[MAP_SIZE]; u8 __afl_area_initial[MAP_SIZE];
u8* __afl_area_ptr = __afl_area_initial; u8* __afl_area_ptr = __afl_area_initial;
@ -64,43 +63,46 @@ u32 __afl_prev_loc;
__thread u32 __afl_prev_loc; __thread u32 __afl_prev_loc;
#endif #endif
/* Running in persistent mode? */ /* Running in persistent mode? */
static u8 is_persistent; static u8 is_persistent;
/* SHM setup. */ /* SHM setup. */
static void __afl_map_shm(void) { static void __afl_map_shm(void) {
u8 *id_str = getenv(SHM_ENV_VAR); u8* id_str = getenv(SHM_ENV_VAR);
/* If we're running under AFL, attach to the appropriate region, replacing the /* If we're running under AFL, attach to the appropriate region, replacing the
early-stage __afl_area_initial region that is needed to allow some really early-stage __afl_area_initial region that is needed to allow some really
hacky .init code to work correctly in projects such as OpenSSL. */ hacky .init code to work correctly in projects such as OpenSSL. */
if (id_str) { if (id_str) {
#ifdef USEMMAP #ifdef USEMMAP
const char *shm_file_path = id_str; const char* shm_file_path = id_str;
int shm_fd = -1; int shm_fd = -1;
unsigned char *shm_base = NULL; unsigned char* shm_base = NULL;
/* create the shared memory segment as if it was a file */ /* create the shared memory segment as if it was a file */
shm_fd = shm_open(shm_file_path, O_RDWR, 0600); shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
if (shm_fd == -1) { if (shm_fd == -1) {
printf("shm_open() failed\n"); printf("shm_open() failed\n");
exit(1); exit(1);
} }
/* map the shared memory segment to the address space of the process */ /* map the shared memory segment to the address space of the process */
shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shm_base == MAP_FAILED) { if (shm_base == MAP_FAILED) {
close(shm_fd); close(shm_fd);
shm_fd = -1; shm_fd = -1;
printf("mmap() failed\n"); printf("mmap() failed\n");
exit(2); exit(2);
} }
__afl_area_ptr = shm_base; __afl_area_ptr = shm_base;
@ -112,7 +114,7 @@ static void __afl_map_shm(void) {
/* Whooooops. */ /* Whooooops. */
if (__afl_area_ptr == (void *)-1) _exit(1); if (__afl_area_ptr == (void*)-1) _exit(1);
/* Write something into the bitmap so that even with low AFL_INST_RATIO, /* Write something into the bitmap so that even with low AFL_INST_RATIO,
our parent doesn't give up on us. */ our parent doesn't give up on us. */
@ -123,16 +125,15 @@ static void __afl_map_shm(void) {
} }
/* Fork server logic. */ /* Fork server logic. */
static void __afl_start_forkserver(void) { static void __afl_start_forkserver(void) {
static u8 tmp[4]; static u8 tmp[4];
s32 child_pid; s32 child_pid;
u8 child_stopped = 0;
u8 child_stopped = 0;
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL); void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
/* Phone home and tell the parent that we're OK. If parent isn't there, /* Phone home and tell the parent that we're OK. If parent isn't there,
@ -154,8 +155,10 @@ static void __afl_start_forkserver(void) {
process. */ process. */
if (child_stopped && was_killed) { if (child_stopped && was_killed) {
child_stopped = 0; child_stopped = 0;
if (waitpid(child_pid, &status, 0) < 0) _exit(1); if (waitpid(child_pid, &status, 0) < 0) _exit(1);
} }
if (!child_stopped) { if (!child_stopped) {
@ -168,12 +171,13 @@ static void __afl_start_forkserver(void) {
/* In child process: close fds, resume execution. */ /* In child process: close fds, resume execution. */
if (!child_pid) { if (!child_pid) {
signal(SIGCHLD, old_sigchld_handler); signal(SIGCHLD, old_sigchld_handler);
close(FORKSRV_FD); close(FORKSRV_FD);
close(FORKSRV_FD + 1); close(FORKSRV_FD + 1);
return; return;
} }
} else { } else {
@ -207,7 +211,6 @@ static void __afl_start_forkserver(void) {
} }
/* A simplified persistent mode handler, used as explained in README.llvm. */ /* A simplified persistent mode handler, used as explained in README.llvm. */
int __afl_persistent_loop(unsigned int max_cnt) { int __afl_persistent_loop(unsigned int max_cnt) {
@ -227,9 +230,10 @@ int __afl_persistent_loop(unsigned int max_cnt) {
memset(__afl_area_ptr, 0, MAP_SIZE); memset(__afl_area_ptr, 0, MAP_SIZE);
__afl_area_ptr[0] = 1; __afl_area_ptr[0] = 1;
__afl_prev_loc = 0; __afl_prev_loc = 0;
} }
cycle_cnt = max_cnt; cycle_cnt = max_cnt;
first_pass = 0; first_pass = 0;
return 1; return 1;
@ -262,7 +266,6 @@ int __afl_persistent_loop(unsigned int max_cnt) {
} }
/* This one can be called from user code when deferred forkserver mode /* This one can be called from user code when deferred forkserver mode
is enabled. */ is enabled. */
@ -280,7 +283,6 @@ void __afl_manual_init(void) {
} }
/* Proper initialization routine. */ /* Proper initialization routine. */
__attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) { __attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
@ -293,7 +295,6 @@ __attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
} }
/* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard. /* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard.
It remains non-operational in the traditional, plugin-backed LLVM mode. It remains non-operational in the traditional, plugin-backed LLVM mode.
For more info about 'trace-pc-guard', see README.llvm. For more info about 'trace-pc-guard', see README.llvm.
@ -302,9 +303,10 @@ __attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) {
edge (as opposed to every basic block). */ edge (as opposed to every basic block). */
void __sanitizer_cov_trace_pc_guard(uint32_t* guard) { void __sanitizer_cov_trace_pc_guard(uint32_t* guard) {
__afl_area_ptr[*guard]++;
}
__afl_area_ptr[*guard]++;
}
/* Init callback. Populates instrumentation IDs. Note that we're using /* Init callback. Populates instrumentation IDs. Note that we're using
ID of 0 as a special value to indicate non-instrumented bits. That may ID of 0 as a special value to indicate non-instrumented bits. That may
@ -321,8 +323,10 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) {
if (x) inst_ratio = atoi(x); if (x) inst_ratio = atoi(x);
if (!inst_ratio || inst_ratio > 100) { if (!inst_ratio || inst_ratio > 100) {
fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n"); fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n");
abort(); abort();
} }
/* Make sure that the first element in the range is always set - we use that /* Make sure that the first element in the range is always set - we use that
@ -333,11 +337,14 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) {
while (start < stop) { while (start < stop) {
if (R(100) < inst_ratio) *start = R(MAP_SIZE - 1) + 1; if (R(100) < inst_ratio)
else *start = 0; *start = R(MAP_SIZE - 1) + 1;
else
*start = 0;
start++; start++;
} }
} }

View File

@ -36,202 +36,236 @@ using namespace llvm;
namespace { namespace {
class CompareTransform : public ModulePass { class CompareTransform : public ModulePass {
public: public:
static char ID; static char ID;
CompareTransform() : ModulePass(ID) { CompareTransform() : ModulePass(ID) {
}
bool runOnModule(Module &M) override; }
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR < 4 #if LLVM_VERSION_MAJOR < 4
const char * getPassName() const override { const char *getPassName() const override {
#else
StringRef getPassName() const override {
#endif
return "transforms compare functions";
}
private:
bool transformCmps(Module &M, const bool processStrcmp, const bool processMemcmp
,const bool processStrncmp, const bool processStrcasecmp, const bool processStrncasecmp);
};
}
#else
StringRef getPassName() const override {
#endif
return "transforms compare functions";
}
private:
bool transformCmps(Module &M, const bool processStrcmp,
const bool processMemcmp, const bool processStrncmp,
const bool processStrcasecmp,
const bool processStrncasecmp);
};
} // namespace
char CompareTransform::ID = 0; char CompareTransform::ID = 0;
bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, const bool processMemcmp bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
, const bool processStrncmp, const bool processStrcasecmp, const bool processStrncasecmp) { const bool processMemcmp,
const bool processStrncmp,
const bool processStrcasecmp,
const bool processStrncasecmp) {
std::vector<CallInst*> calls; std::vector<CallInst *> calls;
LLVMContext &C = M.getContext(); LLVMContext & C = M.getContext();
IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType * Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C); IntegerType * Int32Ty = IntegerType::getInt32Ty(C);
IntegerType *Int64Ty = IntegerType::getInt64Ty(C); IntegerType * Int64Ty = IntegerType::getInt64Ty(C);
#if LLVM_VERSION_MAJOR < 9 #if LLVM_VERSION_MAJOR < 9
Constant* Constant *
#else #else
FunctionCallee FunctionCallee
#endif #endif
c = M.getOrInsertFunction("tolower", c = M.getOrInsertFunction("tolower", Int32Ty, Int32Ty
Int32Ty,
Int32Ty
#if LLVM_VERSION_MAJOR < 5 #if LLVM_VERSION_MAJOR < 5
, nullptr ,
nullptr
#endif #endif
); );
#if LLVM_VERSION_MAJOR < 9 #if LLVM_VERSION_MAJOR < 9
Function* tolowerFn = cast<Function>(c); Function *tolowerFn = cast<Function>(c);
#else #else
FunctionCallee tolowerFn = c; FunctionCallee tolowerFn = c;
#endif #endif
/* iterate over all functions, bbs and instruction and add suitable calls to strcmp/memcmp/strncmp/strcasecmp/strncasecmp */ /* iterate over all functions, bbs and instruction and add suitable calls to
* strcmp/memcmp/strncmp/strcasecmp/strncasecmp */
for (auto &F : M) { for (auto &F : M) {
for (auto &BB : F) { for (auto &BB : F) {
for(auto &IN: BB) {
CallInst* callInst = nullptr; for (auto &IN : BB) {
CallInst *callInst = nullptr;
if ((callInst = dyn_cast<CallInst>(&IN))) { if ((callInst = dyn_cast<CallInst>(&IN))) {
bool isStrcmp = processStrcmp; bool isStrcmp = processStrcmp;
bool isMemcmp = processMemcmp; bool isMemcmp = processMemcmp;
bool isStrncmp = processStrncmp; bool isStrncmp = processStrncmp;
bool isStrcasecmp = processStrcasecmp; bool isStrcasecmp = processStrcasecmp;
bool isStrncasecmp = processStrncasecmp; bool isStrncasecmp = processStrncasecmp;
Function *Callee = callInst->getCalledFunction(); Function *Callee = callInst->getCalledFunction();
if (!Callee) if (!Callee) continue;
continue; if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
if (callInst->getCallingConv() != llvm::CallingConv::C)
continue;
StringRef FuncName = Callee->getName(); StringRef FuncName = Callee->getName();
isStrcmp &= !FuncName.compare(StringRef("strcmp")); isStrcmp &= !FuncName.compare(StringRef("strcmp"));
isMemcmp &= !FuncName.compare(StringRef("memcmp")); isMemcmp &= !FuncName.compare(StringRef("memcmp"));
isStrncmp &= !FuncName.compare(StringRef("strncmp")); isStrncmp &= !FuncName.compare(StringRef("strncmp"));
isStrcasecmp &= !FuncName.compare(StringRef("strcasecmp")); isStrcasecmp &= !FuncName.compare(StringRef("strcasecmp"));
isStrncasecmp &= !FuncName.compare(StringRef("strncasecmp")); isStrncasecmp &= !FuncName.compare(StringRef("strncasecmp"));
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && !isStrncasecmp) if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
!isStrncasecmp)
continue; continue;
/* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function prototype */ /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
* prototype */
FunctionType *FT = Callee->getFunctionType(); FunctionType *FT = Callee->getFunctionType();
isStrcmp &=
isStrcmp &= FT->getNumParams() == 2 && FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) &&
FT->getReturnType()->isIntegerTy(32) && FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) == FT->getParamType(1) && FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext()); isStrcasecmp &=
isStrcasecmp &= FT->getNumParams() == 2 && FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) &&
FT->getReturnType()->isIntegerTy(32) && FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) == FT->getParamType(1) && FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext());
FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext()); isMemcmp &= FT->getNumParams() == 3 &&
isMemcmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) && FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0)->isPointerTy() && FT->getParamType(0)->isPointerTy() &&
FT->getParamType(1)->isPointerTy() && FT->getParamType(1)->isPointerTy() &&
FT->getParamType(2)->isIntegerTy(); FT->getParamType(2)->isIntegerTy();
isStrncmp &= FT->getNumParams() == 3 && isStrncmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) && FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) && FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext()) && FT->getParamType(0) ==
FT->getParamType(2)->isIntegerTy(); IntegerType::getInt8PtrTy(M.getContext()) &&
FT->getParamType(2)->isIntegerTy();
isStrncasecmp &= FT->getNumParams() == 3 && isStrncasecmp &= FT->getNumParams() == 3 &&
FT->getReturnType()->isIntegerTy(32) && FT->getReturnType()->isIntegerTy(32) &&
FT->getParamType(0) == FT->getParamType(1) && FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) == IntegerType::getInt8PtrTy(M.getContext()) && FT->getParamType(0) ==
FT->getParamType(2)->isIntegerTy(); IntegerType::getInt8PtrTy(M.getContext()) &&
FT->getParamType(2)->isIntegerTy();
if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && !isStrncasecmp) if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
!isStrncasecmp)
continue; continue;
/* is a str{n,}{case,}cmp/memcmp, check if we have /* is a str{n,}{case,}cmp/memcmp, check if we have
* str{case,}cmp(x, "const") or str{case,}cmp("const", x) * str{case,}cmp(x, "const") or str{case,}cmp("const", x)
* strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..) * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..)
* memcmp(x, "const", ..) or memcmp("const", x, ..) */ * memcmp(x, "const", ..) or memcmp("const", x, ..) */
Value *Str1P = callInst->getArgOperand(0), *Str2P = callInst->getArgOperand(1); Value *Str1P = callInst->getArgOperand(0),
*Str2P = callInst->getArgOperand(1);
StringRef Str1, Str2; StringRef Str1, Str2;
bool HasStr1 = getConstantStringInfo(Str1P, Str1); bool HasStr1 = getConstantStringInfo(Str1P, Str1);
bool HasStr2 = getConstantStringInfo(Str2P, Str2); bool HasStr2 = getConstantStringInfo(Str2P, Str2);
/* handle cases of one string is const, one string is variable */ /* handle cases of one string is const, one string is variable */
if (!(HasStr1 ^ HasStr2)) if (!(HasStr1 ^ HasStr2)) continue;
continue;
if (isMemcmp || isStrncmp || isStrncasecmp) { if (isMemcmp || isStrncmp || isStrncasecmp) {
/* check if third operand is a constant integer /* check if third operand is a constant integer
* strlen("constStr") and sizeof() are treated as constant */ * strlen("constStr") and sizeof() are treated as constant */
Value *op2 = callInst->getArgOperand(2); Value * op2 = callInst->getArgOperand(2);
ConstantInt* ilen = dyn_cast<ConstantInt>(op2); ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (!ilen) if (!ilen) continue;
continue; /* final precaution: if size of compare is larger than constant
/* final precaution: if size of compare is larger than constant string skip it*/ * string skip it*/
uint64_t literalLength = HasStr1 ? GetStringLength(Str1P) : GetStringLength(Str2P); uint64_t literalLength =
if (literalLength < ilen->getZExtValue()) HasStr1 ? GetStringLength(Str1P) : GetStringLength(Str2P);
continue; if (literalLength < ilen->getZExtValue()) continue;
} }
calls.push_back(callInst); calls.push_back(callInst);
} }
} }
} }
} }
if (!calls.size()) if (!calls.size()) return false;
return false; errs() << "Replacing " << calls.size()
errs() << "Replacing " << calls.size() << " calls to strcmp/memcmp/strncmp/strcasecmp/strncasecmp\n"; << " calls to strcmp/memcmp/strncmp/strcasecmp/strncasecmp\n";
for (auto &callInst: calls) { for (auto &callInst : calls) {
Value *Str1P = callInst->getArgOperand(0), *Str2P = callInst->getArgOperand(1); Value *Str1P = callInst->getArgOperand(0),
StringRef Str1, Str2, ConstStr; *Str2P = callInst->getArgOperand(1);
StringRef Str1, Str2, ConstStr;
std::string TmpConstStr; std::string TmpConstStr;
Value *VarStr; Value * VarStr;
bool HasStr1 = getConstantStringInfo(Str1P, Str1); bool HasStr1 = getConstantStringInfo(Str1P, Str1);
getConstantStringInfo(Str2P, Str2); getConstantStringInfo(Str2P, Str2);
uint64_t constLen, sizedLen; uint64_t constLen, sizedLen;
bool isMemcmp = !callInst->getCalledFunction()->getName().compare(StringRef("memcmp")); bool isMemcmp =
bool isSizedcmp = isMemcmp !callInst->getCalledFunction()->getName().compare(StringRef("memcmp"));
|| !callInst->getCalledFunction()->getName().compare(StringRef("strncmp")) bool isSizedcmp = isMemcmp ||
|| !callInst->getCalledFunction()->getName().compare(StringRef("strncasecmp")); !callInst->getCalledFunction()->getName().compare(
bool isCaseInsensitive = !callInst->getCalledFunction()->getName().compare(StringRef("strcasecmp")) StringRef("strncmp")) ||
|| !callInst->getCalledFunction()->getName().compare(StringRef("strncasecmp")); !callInst->getCalledFunction()->getName().compare(
StringRef("strncasecmp"));
bool isCaseInsensitive = !callInst->getCalledFunction()->getName().compare(
StringRef("strcasecmp")) ||
!callInst->getCalledFunction()->getName().compare(
StringRef("strncasecmp"));
if (isSizedcmp) { if (isSizedcmp) {
Value *op2 = callInst->getArgOperand(2);
ConstantInt* ilen = dyn_cast<ConstantInt>(op2); Value * op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
sizedLen = ilen->getZExtValue(); sizedLen = ilen->getZExtValue();
} }
if (HasStr1) { if (HasStr1) {
TmpConstStr = Str1.str(); TmpConstStr = Str1.str();
VarStr = Str2P; VarStr = Str2P;
constLen = isMemcmp ? sizedLen : GetStringLength(Str1P); constLen = isMemcmp ? sizedLen : GetStringLength(Str1P);
}
else { } else {
TmpConstStr = Str2.str(); TmpConstStr = Str2.str();
VarStr = Str1P; VarStr = Str1P;
constLen = isMemcmp ? sizedLen : GetStringLength(Str2P); constLen = isMemcmp ? sizedLen : GetStringLength(Str2P);
} }
/* properly handle zero terminated C strings by adding the terminating 0 to /* properly handle zero terminated C strings by adding the terminating 0 to
* the StringRef (in comparison to std::string a StringRef has built-in * the StringRef (in comparison to std::string a StringRef has built-in
* runtime bounds checking, which makes debugging easier) */ * runtime bounds checking, which makes debugging easier) */
TmpConstStr.append("\0", 1); ConstStr = StringRef(TmpConstStr); TmpConstStr.append("\0", 1);
ConstStr = StringRef(TmpConstStr);
if (isSizedcmp && constLen > sizedLen) { if (isSizedcmp && constLen > sizedLen) { constLen = sizedLen; }
constLen = sizedLen;
}
errs() << callInst->getCalledFunction()->getName() << ": len " << constLen << ": " << ConstStr << "\n"; errs() << callInst->getCalledFunction()->getName() << ": len " << constLen
<< ": " << ConstStr << "\n";
/* split before the call instruction */ /* split before the call instruction */
BasicBlock *bb = callInst->getParent(); BasicBlock *bb = callInst->getParent();
BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(callInst)); BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(callInst));
BasicBlock *next_bb = BasicBlock::Create(C, "cmp_added", end_bb->getParent(), end_bb); BasicBlock *next_bb =
BasicBlock::Create(C, "cmp_added", end_bb->getParent(), end_bb);
BranchInst::Create(end_bb, next_bb); BranchInst::Create(end_bb, next_bb);
PHINode *PN = PHINode::Create(Int32Ty, constLen + 1, "cmp_phi"); PHINode *PN = PHINode::Create(Int32Ty, constLen + 1, "cmp_phi");
@ -249,71 +283,81 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, const
char c = isCaseInsensitive ? tolower(ConstStr[i]) : ConstStr[i]; char c = isCaseInsensitive ? tolower(ConstStr[i]) : ConstStr[i];
BasicBlock::iterator IP = next_bb->getFirstInsertionPt(); BasicBlock::iterator IP = next_bb->getFirstInsertionPt();
IRBuilder<> IRB(&*IP); IRBuilder<> IRB(&*IP);
Value* v = ConstantInt::get(Int64Ty, i); Value *v = ConstantInt::get(Int64Ty, i);
Value *ele = IRB.CreateInBoundsGEP(VarStr, v, "empty"); Value *ele = IRB.CreateInBoundsGEP(VarStr, v, "empty");
Value *load = IRB.CreateLoad(ele); Value *load = IRB.CreateLoad(ele);
if (isCaseInsensitive) { if (isCaseInsensitive) {
// load >= 'A' && load <= 'Z' ? load | 0x020 : load // load >= 'A' && load <= 'Z' ? load | 0x020 : load
std::vector<Value *> args; std::vector<Value *> args;
args.push_back(load); args.push_back(load);
load = IRB.CreateCall(tolowerFn, args, "tmp"); load = IRB.CreateCall(tolowerFn, args, "tmp");
load = IRB.CreateTrunc(load, Int8Ty); load = IRB.CreateTrunc(load, Int8Ty);
} }
Value *isub; Value *isub;
if (HasStr1) if (HasStr1)
isub = IRB.CreateSub(ConstantInt::get(Int8Ty, c), load); isub = IRB.CreateSub(ConstantInt::get(Int8Ty, c), load);
else else
isub = IRB.CreateSub(load, ConstantInt::get(Int8Ty, c)); isub = IRB.CreateSub(load, ConstantInt::get(Int8Ty, c));
Value *sext = IRB.CreateSExt(isub, Int32Ty); Value *sext = IRB.CreateSExt(isub, Int32Ty);
PN->addIncoming(sext, cur_bb); PN->addIncoming(sext, cur_bb);
if (i < constLen - 1) { if (i < constLen - 1) {
next_bb = BasicBlock::Create(C, "cmp_added", end_bb->getParent(), end_bb);
next_bb =
BasicBlock::Create(C, "cmp_added", end_bb->getParent(), end_bb);
BranchInst::Create(end_bb, next_bb); BranchInst::Create(end_bb, next_bb);
Value *icmp = IRB.CreateICmpEQ(isub, ConstantInt::get(Int8Ty, 0)); Value *icmp = IRB.CreateICmpEQ(isub, ConstantInt::get(Int8Ty, 0));
IRB.CreateCondBr(icmp, next_bb, end_bb); IRB.CreateCondBr(icmp, next_bb, end_bb);
cur_bb->getTerminator()->eraseFromParent(); cur_bb->getTerminator()->eraseFromParent();
} else { } else {
//IRB.CreateBr(end_bb);
// IRB.CreateBr(end_bb);
} }
//add offset to varstr // add offset to varstr
//create load // create load
//create signed isub // create signed isub
//create icmp // create icmp
//create jcc // create jcc
//create next_bb // create next_bb
} }
/* since the call is the first instruction of the bb it is safe to /* since the call is the first instruction of the bb it is safe to
* replace it with a phi instruction */ * replace it with a phi instruction */
BasicBlock::iterator ii(callInst); BasicBlock::iterator ii(callInst);
ReplaceInstWithInst(callInst->getParent()->getInstList(), ii, PN); ReplaceInstWithInst(callInst->getParent()->getInstList(), ii, PN);
} }
return true; return true;
} }
bool CompareTransform::runOnModule(Module &M) { bool CompareTransform::runOnModule(Module &M) {
if (getenv("AFL_QUIET") == NULL) if (getenv("AFL_QUIET") == NULL)
llvm::errs() << "Running compare-transform-pass by laf.intel@gmail.com, extended by heiko@hexco.de\n"; llvm::errs() << "Running compare-transform-pass by laf.intel@gmail.com, "
"extended by heiko@hexco.de\n";
transformCmps(M, true, true, true, true, true); transformCmps(M, true, true, true, true, true);
verifyModule(M); verifyModule(M);
return true; return true;
} }
static void registerCompTransPass(const PassManagerBuilder &, static void registerCompTransPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) { legacy::PassManagerBase &PM) {
auto p = new CompareTransform(); auto p = new CompareTransform();
PM.add(p); PM.add(p);

View File

@ -27,117 +27,126 @@
using namespace llvm; using namespace llvm;
namespace { namespace {
class SplitComparesTransform : public ModulePass {
public:
static char ID;
SplitComparesTransform() : ModulePass(ID) {}
bool runOnModule(Module &M) override; class SplitComparesTransform : public ModulePass {
public:
static char ID;
SplitComparesTransform() : ModulePass(ID) {
}
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR >= 4 #if LLVM_VERSION_MAJOR >= 4
StringRef getPassName() const override { StringRef getPassName() const override {
#else
const char * getPassName() const override {
#endif
return "simplifies and splits ICMP instructions";
}
private:
bool splitCompares(Module &M, unsigned bitw);
bool simplifyCompares(Module &M);
bool simplifySignedness(Module &M);
}; #else
} const char *getPassName() const override {
#endif
return "simplifies and splits ICMP instructions";
}
private:
bool splitCompares(Module &M, unsigned bitw);
bool simplifyCompares(Module &M);
bool simplifySignedness(Module &M);
};
} // namespace
char SplitComparesTransform::ID = 0; char SplitComparesTransform::ID = 0;
/* This function splits ICMP instructions with xGE or xLE predicates into two /* This function splits ICMP instructions with xGE or xLE predicates into two
* ICMP instructions with predicate xGT or xLT and EQ */ * ICMP instructions with predicate xGT or xLT and EQ */
bool SplitComparesTransform::simplifyCompares(Module &M) { bool SplitComparesTransform::simplifyCompares(Module &M) {
LLVMContext &C = M.getContext();
std::vector<Instruction*> icomps; LLVMContext & C = M.getContext();
IntegerType *Int1Ty = IntegerType::getInt1Ty(C); std::vector<Instruction *> icomps;
IntegerType * Int1Ty = IntegerType::getInt1Ty(C);
/* iterate over all functions, bbs and instruction and add /* iterate over all functions, bbs and instruction and add
* all integer comparisons with >= and <= predicates to the icomps vector */ * all integer comparisons with >= and <= predicates to the icomps vector */
for (auto &F : M) { for (auto &F : M) {
for (auto &BB : F) { for (auto &BB : F) {
for (auto &IN: BB) {
CmpInst* selectcmpInst = nullptr; for (auto &IN : BB) {
CmpInst *selectcmpInst = nullptr;
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) { if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
if (selectcmpInst->getPredicate() != CmpInst::ICMP_UGE && if (selectcmpInst->getPredicate() != CmpInst::ICMP_UGE &&
selectcmpInst->getPredicate() != CmpInst::ICMP_SGE && selectcmpInst->getPredicate() != CmpInst::ICMP_SGE &&
selectcmpInst->getPredicate() != CmpInst::ICMP_ULE && selectcmpInst->getPredicate() != CmpInst::ICMP_ULE &&
selectcmpInst->getPredicate() != CmpInst::ICMP_SLE ) { selectcmpInst->getPredicate() != CmpInst::ICMP_SLE) {
continue; continue;
} }
auto op0 = selectcmpInst->getOperand(0); auto op0 = selectcmpInst->getOperand(0);
auto op1 = selectcmpInst->getOperand(1); auto op1 = selectcmpInst->getOperand(1);
IntegerType* intTyOp0 = dyn_cast<IntegerType>(op0->getType()); IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
IntegerType* intTyOp1 = dyn_cast<IntegerType>(op1->getType()); IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
/* this is probably not needed but we do it anyway */ /* this is probably not needed but we do it anyway */
if (!intTyOp0 || !intTyOp1) { if (!intTyOp0 || !intTyOp1) { continue; }
continue;
}
icomps.push_back(selectcmpInst); icomps.push_back(selectcmpInst);
} }
} }
} }
} }
if (!icomps.size()) { if (!icomps.size()) { return false; }
return false;
}
for (auto &IcmpInst : icomps) {
for (auto &IcmpInst: icomps) { BasicBlock *bb = IcmpInst->getParent();
BasicBlock* bb = IcmpInst->getParent();
auto op0 = IcmpInst->getOperand(0); auto op0 = IcmpInst->getOperand(0);
auto op1 = IcmpInst->getOperand(1); auto op1 = IcmpInst->getOperand(1);
/* find out what the new predicate is going to be */ /* find out what the new predicate is going to be */
auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate(); auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate();
CmpInst::Predicate new_pred; CmpInst::Predicate new_pred;
switch(pred) { switch (pred) {
case CmpInst::ICMP_UGE:
new_pred = CmpInst::ICMP_UGT; case CmpInst::ICMP_UGE: new_pred = CmpInst::ICMP_UGT; break;
break; case CmpInst::ICMP_SGE: new_pred = CmpInst::ICMP_SGT; break;
case CmpInst::ICMP_SGE: case CmpInst::ICMP_ULE: new_pred = CmpInst::ICMP_ULT; break;
new_pred = CmpInst::ICMP_SGT; case CmpInst::ICMP_SLE: new_pred = CmpInst::ICMP_SLT; break;
break; default: // keep the compiler happy
case CmpInst::ICMP_ULE:
new_pred = CmpInst::ICMP_ULT;
break;
case CmpInst::ICMP_SLE:
new_pred = CmpInst::ICMP_SLT;
break;
default: // keep the compiler happy
continue; continue;
} }
/* split before the icmp instruction */ /* split before the icmp instruction */
BasicBlock* end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst));
/* the old bb now contains a unconditional jump to the new one (end_bb) /* the old bb now contains a unconditional jump to the new one (end_bb)
* we need to delete it later */ * we need to delete it later */
/* create the ICMP instruction with new_pred and add it to the old basic /* create the ICMP instruction with new_pred and add it to the old basic
* block bb it is now at the position where the old IcmpInst was */ * block bb it is now at the position where the old IcmpInst was */
Instruction* icmp_np; Instruction *icmp_np;
icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1); icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1);
bb->getInstList().insert(bb->getTerminator()->getIterator(), icmp_np); bb->getInstList().insert(bb->getTerminator()->getIterator(), icmp_np);
/* create a new basic block which holds the new EQ icmp */ /* create a new basic block which holds the new EQ icmp */
Instruction *icmp_eq; Instruction *icmp_eq;
/* insert middle_bb before end_bb */ /* insert middle_bb before end_bb */
BasicBlock* middle_bb = BasicBlock::Create(C, "injected", BasicBlock *middle_bb =
end_bb->getParent(), end_bb); BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1); icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1);
middle_bb->getInstList().push_back(icmp_eq); middle_bb->getInstList().push_back(icmp_eq);
/* add an unconditional branch to the end of middle_bb with destination /* add an unconditional branch to the end of middle_bb with destination
@ -150,7 +159,6 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
BranchInst::Create(end_bb, middle_bb, icmp_np, bb); BranchInst::Create(end_bb, middle_bb, icmp_np, bb);
term->eraseFromParent(); term->eraseFromParent();
/* replace the old IcmpInst (which is the first inst in end_bb) with a PHI /* replace the old IcmpInst (which is the first inst in end_bb) with a PHI
* inst to wire up the loose ends */ * inst to wire up the loose ends */
PHINode *PN = PHINode::Create(Int1Ty, 2, ""); PHINode *PN = PHINode::Create(Int1Ty, 2, "");
@ -162,118 +170,139 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
/* replace the old IcmpInst with our new and shiny PHI inst */ /* replace the old IcmpInst with our new and shiny PHI inst */
BasicBlock::iterator ii(IcmpInst); BasicBlock::iterator ii(IcmpInst);
ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
} }
return true; return true;
} }
/* this function transforms signed compares to equivalent unsigned compares */ /* this function transforms signed compares to equivalent unsigned compares */
bool SplitComparesTransform::simplifySignedness(Module &M) { bool SplitComparesTransform::simplifySignedness(Module &M) {
LLVMContext &C = M.getContext();
std::vector<Instruction*> icomps; LLVMContext & C = M.getContext();
IntegerType *Int1Ty = IntegerType::getInt1Ty(C); std::vector<Instruction *> icomps;
IntegerType * Int1Ty = IntegerType::getInt1Ty(C);
/* iterate over all functions, bbs and instruction and add /* iterate over all functions, bbs and instruction and add
* all signed compares to icomps vector */ * all signed compares to icomps vector */
for (auto &F : M) { for (auto &F : M) {
for (auto &BB : F) { for (auto &BB : F) {
for(auto &IN: BB) {
CmpInst* selectcmpInst = nullptr; for (auto &IN : BB) {
CmpInst *selectcmpInst = nullptr;
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) { if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
if (selectcmpInst->getPredicate() != CmpInst::ICMP_SGT && if (selectcmpInst->getPredicate() != CmpInst::ICMP_SGT &&
selectcmpInst->getPredicate() != CmpInst::ICMP_SLT selectcmpInst->getPredicate() != CmpInst::ICMP_SLT) {
) {
continue; continue;
} }
auto op0 = selectcmpInst->getOperand(0); auto op0 = selectcmpInst->getOperand(0);
auto op1 = selectcmpInst->getOperand(1); auto op1 = selectcmpInst->getOperand(1);
IntegerType* intTyOp0 = dyn_cast<IntegerType>(op0->getType()); IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
IntegerType* intTyOp1 = dyn_cast<IntegerType>(op1->getType()); IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
/* see above */ /* see above */
if (!intTyOp0 || !intTyOp1) { if (!intTyOp0 || !intTyOp1) { continue; }
continue;
}
/* i think this is not possible but to lazy to look it up */ /* i think this is not possible but to lazy to look it up */
if (intTyOp0->getBitWidth() != intTyOp1->getBitWidth()) { if (intTyOp0->getBitWidth() != intTyOp1->getBitWidth()) { continue; }
continue;
}
icomps.push_back(selectcmpInst); icomps.push_back(selectcmpInst);
} }
} }
} }
} }
if (!icomps.size()) { if (!icomps.size()) { return false; }
return false;
}
for (auto &IcmpInst: icomps) { for (auto &IcmpInst : icomps) {
BasicBlock* bb = IcmpInst->getParent();
BasicBlock *bb = IcmpInst->getParent();
auto op0 = IcmpInst->getOperand(0); auto op0 = IcmpInst->getOperand(0);
auto op1 = IcmpInst->getOperand(1); auto op1 = IcmpInst->getOperand(1);
IntegerType* intTyOp0 = dyn_cast<IntegerType>(op0->getType()); IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
unsigned bitw = intTyOp0->getBitWidth(); unsigned bitw = intTyOp0->getBitWidth();
IntegerType *IntType = IntegerType::get(C, bitw); IntegerType *IntType = IntegerType::get(C, bitw);
/* get the new predicate */ /* get the new predicate */
auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate(); auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate();
CmpInst::Predicate new_pred; CmpInst::Predicate new_pred;
if (pred == CmpInst::ICMP_SGT) { if (pred == CmpInst::ICMP_SGT) {
new_pred = CmpInst::ICMP_UGT; new_pred = CmpInst::ICMP_UGT;
} else { } else {
new_pred = CmpInst::ICMP_ULT; new_pred = CmpInst::ICMP_ULT;
} }
BasicBlock* end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst));
/* create a 1 bit compare for the sign bit. to do this shift and trunc /* create a 1 bit compare for the sign bit. to do this shift and trunc
* the original operands so only the first bit remains.*/ * the original operands so only the first bit remains.*/
Instruction *s_op0, *t_op0, *s_op1, *t_op1, *icmp_sign_bit; Instruction *s_op0, *t_op0, *s_op1, *t_op1, *icmp_sign_bit;
s_op0 = BinaryOperator::Create(Instruction::LShr, op0, ConstantInt::get(IntType, bitw - 1)); s_op0 = BinaryOperator::Create(Instruction::LShr, op0,
ConstantInt::get(IntType, bitw - 1));
bb->getInstList().insert(bb->getTerminator()->getIterator(), s_op0); bb->getInstList().insert(bb->getTerminator()->getIterator(), s_op0);
t_op0 = new TruncInst(s_op0, Int1Ty); t_op0 = new TruncInst(s_op0, Int1Ty);
bb->getInstList().insert(bb->getTerminator()->getIterator(), t_op0); bb->getInstList().insert(bb->getTerminator()->getIterator(), t_op0);
s_op1 = BinaryOperator::Create(Instruction::LShr, op1, ConstantInt::get(IntType, bitw - 1)); s_op1 = BinaryOperator::Create(Instruction::LShr, op1,
ConstantInt::get(IntType, bitw - 1));
bb->getInstList().insert(bb->getTerminator()->getIterator(), s_op1); bb->getInstList().insert(bb->getTerminator()->getIterator(), s_op1);
t_op1 = new TruncInst(s_op1, Int1Ty); t_op1 = new TruncInst(s_op1, Int1Ty);
bb->getInstList().insert(bb->getTerminator()->getIterator(), t_op1); bb->getInstList().insert(bb->getTerminator()->getIterator(), t_op1);
/* compare of the sign bits */ /* compare of the sign bits */
icmp_sign_bit = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_op0, t_op1); icmp_sign_bit =
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_op0, t_op1);
bb->getInstList().insert(bb->getTerminator()->getIterator(), icmp_sign_bit); bb->getInstList().insert(bb->getTerminator()->getIterator(), icmp_sign_bit);
/* create a new basic block which is executed if the signedness bit is /* create a new basic block which is executed if the signedness bit is
* different */ * different */
Instruction *icmp_inv_sig_cmp; Instruction *icmp_inv_sig_cmp;
BasicBlock* sign_bb = BasicBlock::Create(C, "sign", end_bb->getParent(), end_bb); BasicBlock * sign_bb =
BasicBlock::Create(C, "sign", end_bb->getParent(), end_bb);
if (pred == CmpInst::ICMP_SGT) { if (pred == CmpInst::ICMP_SGT) {
/* if we check for > and the op0 positive and op1 negative then the final /* if we check for > and the op0 positive and op1 negative then the final
* result is true. if op0 negative and op1 pos, the cmp must result * result is true. if op0 negative and op1 pos, the cmp must result
* in false * in false
*/ */
icmp_inv_sig_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_op0, t_op1); icmp_inv_sig_cmp =
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_op0, t_op1);
} else { } else {
/* just the inverse of the above statement */ /* just the inverse of the above statement */
icmp_inv_sig_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_op0, t_op1); icmp_inv_sig_cmp =
CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_op0, t_op1);
} }
sign_bb->getInstList().push_back(icmp_inv_sig_cmp); sign_bb->getInstList().push_back(icmp_inv_sig_cmp);
BranchInst::Create(end_bb, sign_bb); BranchInst::Create(end_bb, sign_bb);
/* create a new bb which is executed if signedness is equal */ /* create a new bb which is executed if signedness is equal */
Instruction *icmp_usign_cmp; Instruction *icmp_usign_cmp;
BasicBlock* middle_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); BasicBlock * middle_bb =
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
/* we can do a normal unsigned compare now */ /* we can do a normal unsigned compare now */
icmp_usign_cmp = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1); icmp_usign_cmp = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1);
middle_bb->getInstList().push_back(icmp_usign_cmp); middle_bb->getInstList().push_back(icmp_usign_cmp);
@ -285,7 +314,6 @@ bool SplitComparesTransform::simplifySignedness(Module &M) {
BranchInst::Create(middle_bb, sign_bb, icmp_sign_bit, bb); BranchInst::Create(middle_bb, sign_bb, icmp_sign_bit, bb);
term->eraseFromParent(); term->eraseFromParent();
PHINode *PN = PHINode::Create(Int1Ty, 2, ""); PHINode *PN = PHINode::Create(Int1Ty, 2, "");
PN->addIncoming(icmp_usign_cmp, middle_bb); PN->addIncoming(icmp_usign_cmp, middle_bb);
@ -293,91 +321,100 @@ bool SplitComparesTransform::simplifySignedness(Module &M) {
BasicBlock::iterator ii(IcmpInst); BasicBlock::iterator ii(IcmpInst);
ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
} }
return true; return true;
} }
/* splits icmps of size bitw into two nested icmps with bitw/2 size each */ /* splits icmps of size bitw into two nested icmps with bitw/2 size each */
bool SplitComparesTransform::splitCompares(Module &M, unsigned bitw) { bool SplitComparesTransform::splitCompares(Module &M, unsigned bitw) {
LLVMContext &C = M.getContext(); LLVMContext &C = M.getContext();
IntegerType *Int1Ty = IntegerType::getInt1Ty(C); IntegerType *Int1Ty = IntegerType::getInt1Ty(C);
IntegerType *OldIntType = IntegerType::get(C, bitw); IntegerType *OldIntType = IntegerType::get(C, bitw);
IntegerType *NewIntType = IntegerType::get(C, bitw / 2); IntegerType *NewIntType = IntegerType::get(C, bitw / 2);
std::vector<Instruction*> icomps; std::vector<Instruction *> icomps;
if (bitw % 2) { if (bitw % 2) { return false; }
return false;
}
/* not supported yet */ /* not supported yet */
if (bitw > 64) { if (bitw > 64) { return false; }
return false;
}
/* get all EQ, NE, UGT, and ULT icmps of width bitw. if the other two /* get all EQ, NE, UGT, and ULT icmps of width bitw. if the other two
* unctions were executed only these four predicates should exist */ * unctions were executed only these four predicates should exist */
for (auto &F : M) { for (auto &F : M) {
for (auto &BB : F) { for (auto &BB : F) {
for(auto &IN: BB) {
CmpInst* selectcmpInst = nullptr; for (auto &IN : BB) {
CmpInst *selectcmpInst = nullptr;
if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) { if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
if(selectcmpInst->getPredicate() != CmpInst::ICMP_EQ && if (selectcmpInst->getPredicate() != CmpInst::ICMP_EQ &&
selectcmpInst->getPredicate() != CmpInst::ICMP_NE && selectcmpInst->getPredicate() != CmpInst::ICMP_NE &&
selectcmpInst->getPredicate() != CmpInst::ICMP_UGT && selectcmpInst->getPredicate() != CmpInst::ICMP_UGT &&
selectcmpInst->getPredicate() != CmpInst::ICMP_ULT selectcmpInst->getPredicate() != CmpInst::ICMP_ULT) {
) {
continue; continue;
} }
auto op0 = selectcmpInst->getOperand(0); auto op0 = selectcmpInst->getOperand(0);
auto op1 = selectcmpInst->getOperand(1); auto op1 = selectcmpInst->getOperand(1);
IntegerType* intTyOp0 = dyn_cast<IntegerType>(op0->getType()); IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
IntegerType* intTyOp1 = dyn_cast<IntegerType>(op1->getType()); IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
if (!intTyOp0 || !intTyOp1) { if (!intTyOp0 || !intTyOp1) { continue; }
continue;
}
/* check if the bitwidths are the one we are looking for */ /* check if the bitwidths are the one we are looking for */
if (intTyOp0->getBitWidth() != bitw || intTyOp1->getBitWidth() != bitw) { if (intTyOp0->getBitWidth() != bitw ||
intTyOp1->getBitWidth() != bitw) {
continue; continue;
} }
icomps.push_back(selectcmpInst); icomps.push_back(selectcmpInst);
} }
} }
} }
} }
if (!icomps.size()) { if (!icomps.size()) { return false; }
return false;
}
for (auto &IcmpInst: icomps) { for (auto &IcmpInst : icomps) {
BasicBlock* bb = IcmpInst->getParent();
BasicBlock *bb = IcmpInst->getParent();
auto op0 = IcmpInst->getOperand(0); auto op0 = IcmpInst->getOperand(0);
auto op1 = IcmpInst->getOperand(1); auto op1 = IcmpInst->getOperand(1);
auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate(); auto pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate();
BasicBlock* end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst));
/* create the comparison of the top halves of the original operands */ /* create the comparison of the top halves of the original operands */
Instruction *s_op0, *op0_high, *s_op1, *op1_high, *icmp_high; Instruction *s_op0, *op0_high, *s_op1, *op1_high, *icmp_high;
s_op0 = BinaryOperator::Create(Instruction::LShr, op0, ConstantInt::get(OldIntType, bitw / 2)); s_op0 = BinaryOperator::Create(Instruction::LShr, op0,
ConstantInt::get(OldIntType, bitw / 2));
bb->getInstList().insert(bb->getTerminator()->getIterator(), s_op0); bb->getInstList().insert(bb->getTerminator()->getIterator(), s_op0);
op0_high = new TruncInst(s_op0, NewIntType); op0_high = new TruncInst(s_op0, NewIntType);
bb->getInstList().insert(bb->getTerminator()->getIterator(), op0_high); bb->getInstList().insert(bb->getTerminator()->getIterator(), op0_high);
s_op1 = BinaryOperator::Create(Instruction::LShr, op1, ConstantInt::get(OldIntType, bitw / 2)); s_op1 = BinaryOperator::Create(Instruction::LShr, op1,
ConstantInt::get(OldIntType, bitw / 2));
bb->getInstList().insert(bb->getTerminator()->getIterator(), s_op1); bb->getInstList().insert(bb->getTerminator()->getIterator(), s_op1);
op1_high = new TruncInst(s_op1, NewIntType); op1_high = new TruncInst(s_op1, NewIntType);
bb->getInstList().insert(bb->getTerminator()->getIterator(), op1_high); bb->getInstList().insert(bb->getTerminator()->getIterator(), op1_high);
@ -387,11 +424,13 @@ bool SplitComparesTransform::splitCompares(Module &M, unsigned bitw) {
/* now we have to destinguish between == != and > < */ /* now we have to destinguish between == != and > < */
if (pred == CmpInst::ICMP_EQ || pred == CmpInst::ICMP_NE) { if (pred == CmpInst::ICMP_EQ || pred == CmpInst::ICMP_NE) {
/* transformation for == and != icmps */ /* transformation for == and != icmps */
/* create a compare for the lower half of the original operands */ /* create a compare for the lower half of the original operands */
Instruction *op0_low, *op1_low, *icmp_low; Instruction *op0_low, *op1_low, *icmp_low;
BasicBlock* cmp_low_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); BasicBlock * cmp_low_bb =
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
op0_low = new TruncInst(op0, NewIntType); op0_low = new TruncInst(op0, NewIntType);
cmp_low_bb->getInstList().push_back(op0_low); cmp_low_bb->getInstList().push_back(op0_low);
@ -407,21 +446,30 @@ bool SplitComparesTransform::splitCompares(Module &M, unsigned bitw) {
* the comparison */ * the comparison */
auto term = bb->getTerminator(); auto term = bb->getTerminator();
if (pred == CmpInst::ICMP_EQ) { if (pred == CmpInst::ICMP_EQ) {
BranchInst::Create(cmp_low_bb, end_bb, icmp_high, bb); BranchInst::Create(cmp_low_bb, end_bb, icmp_high, bb);
} else { } else {
/* CmpInst::ICMP_NE */ /* CmpInst::ICMP_NE */
BranchInst::Create(end_bb, cmp_low_bb, icmp_high, bb); BranchInst::Create(end_bb, cmp_low_bb, icmp_high, bb);
} }
term->eraseFromParent(); term->eraseFromParent();
/* create the PHI and connect the edges accordingly */ /* create the PHI and connect the edges accordingly */
PHINode *PN = PHINode::Create(Int1Ty, 2, ""); PHINode *PN = PHINode::Create(Int1Ty, 2, "");
PN->addIncoming(icmp_low, cmp_low_bb); PN->addIncoming(icmp_low, cmp_low_bb);
if (pred == CmpInst::ICMP_EQ) { if (pred == CmpInst::ICMP_EQ) {
PN->addIncoming(ConstantInt::get(Int1Ty, 0), bb); PN->addIncoming(ConstantInt::get(Int1Ty, 0), bb);
} else { } else {
/* CmpInst::ICMP_NE */ /* CmpInst::ICMP_NE */
PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
} }
/* replace the old icmp with the new PHI */ /* replace the old icmp with the new PHI */
@ -429,19 +477,28 @@ bool SplitComparesTransform::splitCompares(Module &M, unsigned bitw) {
ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
} else { } else {
/* CmpInst::ICMP_UGT and CmpInst::ICMP_ULT */ /* CmpInst::ICMP_UGT and CmpInst::ICMP_ULT */
/* transformations for < and > */ /* transformations for < and > */
/* create a basic block which checks for the inverse predicate. /* create a basic block which checks for the inverse predicate.
* if this is true we can go to the end if not we have to got to the * if this is true we can go to the end if not we have to got to the
* bb which checks the lower half of the operands */ * bb which checks the lower half of the operands */
Instruction *icmp_inv_cmp, *op0_low, *op1_low, *icmp_low; Instruction *icmp_inv_cmp, *op0_low, *op1_low, *icmp_low;
BasicBlock* inv_cmp_bb = BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb); BasicBlock * inv_cmp_bb =
BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb);
if (pred == CmpInst::ICMP_UGT) { if (pred == CmpInst::ICMP_UGT) {
icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, op0_high, op1_high);
icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT,
op0_high, op1_high);
} else { } else {
icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, op0_high, op1_high);
icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT,
op0_high, op1_high);
} }
inv_cmp_bb->getInstList().push_back(icmp_inv_cmp); inv_cmp_bb->getInstList().push_back(icmp_inv_cmp);
auto term = bb->getTerminator(); auto term = bb->getTerminator();
@ -449,7 +506,8 @@ bool SplitComparesTransform::splitCompares(Module &M, unsigned bitw) {
BranchInst::Create(end_bb, inv_cmp_bb, icmp_high, bb); BranchInst::Create(end_bb, inv_cmp_bb, icmp_high, bb);
/* create a bb which handles the cmp of the lower halves */ /* create a bb which handles the cmp of the lower halves */
BasicBlock* cmp_low_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); BasicBlock *cmp_low_bb =
BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
op0_low = new TruncInst(op0, NewIntType); op0_low = new TruncInst(op0, NewIntType);
cmp_low_bb->getInstList().push_back(op0_low); cmp_low_bb->getInstList().push_back(op0_low);
op1_low = new TruncInst(op1, NewIntType); op1_low = new TruncInst(op1, NewIntType);
@ -468,57 +526,64 @@ bool SplitComparesTransform::splitCompares(Module &M, unsigned bitw) {
BasicBlock::iterator ii(IcmpInst); BasicBlock::iterator ii(IcmpInst);
ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
} }
} }
return true;
return true;
} }
bool SplitComparesTransform::runOnModule(Module &M) { bool SplitComparesTransform::runOnModule(Module &M) {
int bitw = 64; int bitw = 64;
char* bitw_env = getenv("LAF_SPLIT_COMPARES_BITW"); char *bitw_env = getenv("LAF_SPLIT_COMPARES_BITW");
if (!bitw_env) if (!bitw_env) bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW");
bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW"); if (bitw_env) { bitw = atoi(bitw_env); }
if (bitw_env) {
bitw = atoi(bitw_env);
}
simplifyCompares(M); simplifyCompares(M);
simplifySignedness(M); simplifySignedness(M);
if (getenv("AFL_QUIET") == NULL) if (getenv("AFL_QUIET") == NULL)
errs() << "Split-compare-pass by laf.intel@gmail.com\n"; errs() << "Split-compare-pass by laf.intel@gmail.com\n";
switch (bitw) { switch (bitw) {
case 64: case 64:
errs() << "Running split-compare-pass " << 64 << "\n"; errs() << "Running split-compare-pass " << 64 << "\n";
splitCompares(M, 64); splitCompares(M, 64);
[[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */ [[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */
case 32: case 32:
errs() << "Running split-compare-pass " << 32 << "\n"; errs() << "Running split-compare-pass " << 32 << "\n";
splitCompares(M, 32); splitCompares(M, 32);
[[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */ [[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */
case 16: case 16:
errs() << "Running split-compare-pass " << 16 << "\n"; errs() << "Running split-compare-pass " << 16 << "\n";
splitCompares(M, 16); splitCompares(M, 16);
break; break;
default: default:
errs() << "NOT Running split-compare-pass \n"; errs() << "NOT Running split-compare-pass \n";
return false; return false;
break; break;
} }
verifyModule(M); verifyModule(M);
return true; return true;
} }
static void registerSplitComparesPass(const PassManagerBuilder &, static void registerSplitComparesPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) { legacy::PassManagerBase &PM) {
PM.add(new SplitComparesTransform()); PM.add(new SplitComparesTransform());
} }
static RegisterStandardPasses RegisterSplitComparesPass( static RegisterStandardPasses RegisterSplitComparesPass(
@ -526,3 +591,4 @@ static RegisterStandardPasses RegisterSplitComparesPass(
static RegisterStandardPasses RegisterSplitComparesTransPass0( static RegisterStandardPasses RegisterSplitComparesTransPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitComparesPass); PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitComparesPass);

View File

@ -36,54 +36,65 @@ using namespace llvm;
namespace { namespace {
class SplitSwitchesTransform : public ModulePass { class SplitSwitchesTransform : public ModulePass {
public: public:
static char ID; static char ID;
SplitSwitchesTransform() : ModulePass(ID) { SplitSwitchesTransform() : ModulePass(ID) {
}
bool runOnModule(Module &M) override; }
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR >= 4 #if LLVM_VERSION_MAJOR >= 4
StringRef getPassName() const override { StringRef getPassName() const override {
#else #else
const char * getPassName() const override { const char *getPassName() const override {
#endif #endif
return "splits switch constructs"; return "splits switch constructs";
}
struct CaseExpr {
ConstantInt* Val;
BasicBlock* BB;
CaseExpr(ConstantInt *val = nullptr, BasicBlock *bb = nullptr) : }
Val(val), BB(bb) { }
};
typedef std::vector<CaseExpr> CaseVector; struct CaseExpr {
ConstantInt *Val;
BasicBlock * BB;
CaseExpr(ConstantInt *val = nullptr, BasicBlock *bb = nullptr)
: Val(val), BB(bb) {
}
private:
bool splitSwitches(Module &M);
bool transformCmps(Module &M, const bool processStrcmp, const bool processMemcmp);
BasicBlock* switchConvert(CaseVector Cases, std::vector<bool> bytesChecked,
BasicBlock* OrigBlock, BasicBlock* NewDefault,
Value* Val, unsigned level);
}; };
} typedef std::vector<CaseExpr> CaseVector;
private:
bool splitSwitches(Module &M);
bool transformCmps(Module &M, const bool processStrcmp,
const bool processMemcmp);
BasicBlock *switchConvert(CaseVector Cases, std::vector<bool> bytesChecked,
BasicBlock *OrigBlock, BasicBlock *NewDefault,
Value *Val, unsigned level);
};
} // namespace
char SplitSwitchesTransform::ID = 0; char SplitSwitchesTransform::ID = 0;
/* switchConvert - Transform simple list of Cases into list of CaseRange's */ /* switchConvert - Transform simple list of Cases into list of CaseRange's */
BasicBlock* SplitSwitchesTransform::switchConvert(CaseVector Cases, std::vector<bool> bytesChecked, BasicBlock *SplitSwitchesTransform::switchConvert(
BasicBlock* OrigBlock, BasicBlock* NewDefault, CaseVector Cases, std::vector<bool> bytesChecked, BasicBlock *OrigBlock,
Value* Val, unsigned level) { BasicBlock *NewDefault, Value *Val, unsigned level) {
unsigned ValTypeBitWidth = Cases[0].Val->getBitWidth(); unsigned ValTypeBitWidth = Cases[0].Val->getBitWidth();
IntegerType *ValType = IntegerType::get(OrigBlock->getContext(), ValTypeBitWidth); IntegerType *ValType =
IntegerType *ByteType = IntegerType::get(OrigBlock->getContext(), 8); IntegerType::get(OrigBlock->getContext(), ValTypeBitWidth);
unsigned BytesInValue = bytesChecked.size(); IntegerType * ByteType = IntegerType::get(OrigBlock->getContext(), 8);
unsigned BytesInValue = bytesChecked.size();
std::vector<uint8_t> setSizes; std::vector<uint8_t> setSizes;
std::vector<std::set<uint8_t>> byteSets(BytesInValue, std::set<uint8_t>()); std::vector<std::set<uint8_t>> byteSets(BytesInValue, std::set<uint8_t>());
@ -91,43 +102,54 @@ BasicBlock* SplitSwitchesTransform::switchConvert(CaseVector Cases, std::vector<
/* for each of the possible cases we iterate over all bytes of the values /* for each of the possible cases we iterate over all bytes of the values
* build a set of possible values at each byte position in byteSets */ * build a set of possible values at each byte position in byteSets */
for (CaseExpr& Case: Cases) { for (CaseExpr &Case : Cases) {
for (unsigned i = 0; i < BytesInValue; i++) { for (unsigned i = 0; i < BytesInValue; i++) {
uint8_t byte = (Case.Val->getZExtValue() >> (i*8)) & 0xFF; uint8_t byte = (Case.Val->getZExtValue() >> (i * 8)) & 0xFF;
byteSets[i].insert(byte); byteSets[i].insert(byte);
} }
} }
/* find the index of the first byte position that was not yet checked. then /* find the index of the first byte position that was not yet checked. then
* save the number of possible values at that byte position */ * save the number of possible values at that byte position */
unsigned smallestIndex = 0; unsigned smallestIndex = 0;
unsigned smallestSize = 257; unsigned smallestSize = 257;
for(unsigned i = 0; i < byteSets.size(); i++) { for (unsigned i = 0; i < byteSets.size(); i++) {
if (bytesChecked[i])
continue; if (bytesChecked[i]) continue;
if (byteSets[i].size() < smallestSize) { if (byteSets[i].size() < smallestSize) {
smallestIndex = i; smallestIndex = i;
smallestSize = byteSets[i].size(); smallestSize = byteSets[i].size();
} }
} }
assert(bytesChecked[smallestIndex] == false); assert(bytesChecked[smallestIndex] == false);
/* there are only smallestSize different bytes at index smallestIndex */ /* there are only smallestSize different bytes at index smallestIndex */
Instruction *Shift, *Trunc; Instruction *Shift, *Trunc;
Function* F = OrigBlock->getParent(); Function * F = OrigBlock->getParent();
BasicBlock* NewNode = BasicBlock::Create(Val->getContext(), "NodeBlock", F); BasicBlock * NewNode = BasicBlock::Create(Val->getContext(), "NodeBlock", F);
Shift = BinaryOperator::Create(Instruction::LShr, Val, ConstantInt::get(ValType, smallestIndex * 8)); Shift = BinaryOperator::Create(Instruction::LShr, Val,
ConstantInt::get(ValType, smallestIndex * 8));
NewNode->getInstList().push_back(Shift); NewNode->getInstList().push_back(Shift);
if (ValTypeBitWidth > 8) { if (ValTypeBitWidth > 8) {
Trunc = new TruncInst(Shift, ByteType); Trunc = new TruncInst(Shift, ByteType);
NewNode->getInstList().push_back(Trunc); NewNode->getInstList().push_back(Trunc);
}
else { } else {
/* not necessary to trunc */ /* not necessary to trunc */
Trunc = Shift; Trunc = Shift;
} }
/* this is a trivial case, we can directly check for the byte, /* this is a trivial case, we can directly check for the byte,
@ -135,118 +157,155 @@ BasicBlock* SplitSwitchesTransform::switchConvert(CaseVector Cases, std::vector<
* mark the byte as checked. if this was the last byte to check * mark the byte as checked. if this was the last byte to check
* we can finally execute the block belonging to this case */ * we can finally execute the block belonging to this case */
if (smallestSize == 1) { if (smallestSize == 1) {
uint8_t byte = *(byteSets[smallestIndex].begin()); uint8_t byte = *(byteSets[smallestIndex].begin());
/* insert instructions to check whether the value we are switching on is equal to byte */ /* insert instructions to check whether the value we are switching on is
ICmpInst* Comp = new ICmpInst(ICmpInst::ICMP_EQ, Trunc, ConstantInt::get(ByteType, byte), "byteMatch"); * equal to byte */
ICmpInst *Comp =
new ICmpInst(ICmpInst::ICMP_EQ, Trunc, ConstantInt::get(ByteType, byte),
"byteMatch");
NewNode->getInstList().push_back(Comp); NewNode->getInstList().push_back(Comp);
bytesChecked[smallestIndex] = true; bytesChecked[smallestIndex] = true;
if (std::all_of(bytesChecked.begin(), bytesChecked.end(), [](bool b){return b;} )) { if (std::all_of(bytesChecked.begin(), bytesChecked.end(),
[](bool b) { return b; })) {
assert(Cases.size() == 1); assert(Cases.size() == 1);
BranchInst::Create(Cases[0].BB, NewDefault, Comp, NewNode); BranchInst::Create(Cases[0].BB, NewDefault, Comp, NewNode);
/* we have to update the phi nodes! */ /* we have to update the phi nodes! */
for (BasicBlock::iterator I = Cases[0].BB->begin(); I != Cases[0].BB->end(); ++I) { for (BasicBlock::iterator I = Cases[0].BB->begin();
if (!isa<PHINode>(&*I)) { I != Cases[0].BB->end(); ++I) {
continue;
} if (!isa<PHINode>(&*I)) { continue; }
PHINode *PN = cast<PHINode>(I); PHINode *PN = cast<PHINode>(I);
/* Only update the first occurrence. */ /* Only update the first occurrence. */
unsigned Idx = 0, E = PN->getNumIncomingValues(); unsigned Idx = 0, E = PN->getNumIncomingValues();
for (; Idx != E; ++Idx) { for (; Idx != E; ++Idx) {
if (PN->getIncomingBlock(Idx) == OrigBlock) { if (PN->getIncomingBlock(Idx) == OrigBlock) {
PN->setIncomingBlock(Idx, NewNode); PN->setIncomingBlock(Idx, NewNode);
break; break;
} }
} }
} }
}
else { } else {
BasicBlock* BB = switchConvert(Cases, bytesChecked, OrigBlock, NewDefault, Val, level + 1);
BasicBlock *BB = switchConvert(Cases, bytesChecked, OrigBlock, NewDefault,
Val, level + 1);
BranchInst::Create(BB, NewDefault, Comp, NewNode); BranchInst::Create(BB, NewDefault, Comp, NewNode);
} }
} }
/* there is no byte which we can directly check on, split the tree */ /* there is no byte which we can directly check on, split the tree */
else { else {
std::vector<uint8_t> byteVector; std::vector<uint8_t> byteVector;
std::copy(byteSets[smallestIndex].begin(), byteSets[smallestIndex].end(), std::back_inserter(byteVector)); std::copy(byteSets[smallestIndex].begin(), byteSets[smallestIndex].end(),
std::back_inserter(byteVector));
std::sort(byteVector.begin(), byteVector.end()); std::sort(byteVector.begin(), byteVector.end());
uint8_t pivot = byteVector[byteVector.size() / 2]; uint8_t pivot = byteVector[byteVector.size() / 2];
/* we already chose to divide the cases based on the value of byte at index smallestIndex /* we already chose to divide the cases based on the value of byte at index
* the pivot value determines the threshold for the decicion; if a case value * smallestIndex the pivot value determines the threshold for the decicion;
* is smaller at this byte index move it to the LHS vector, otherwise to the RHS vector */ * if a case value
* is smaller at this byte index move it to the LHS vector, otherwise to the
* RHS vector */
CaseVector LHSCases, RHSCases; CaseVector LHSCases, RHSCases;
for (CaseExpr& Case: Cases) { for (CaseExpr &Case : Cases) {
uint8_t byte = (Case.Val->getZExtValue() >> (smallestIndex*8)) & 0xFF;
uint8_t byte = (Case.Val->getZExtValue() >> (smallestIndex * 8)) & 0xFF;
if (byte < pivot) { if (byte < pivot) {
LHSCases.push_back(Case);
}
else {
RHSCases.push_back(Case);
}
}
BasicBlock *LBB, *RBB;
LBB = switchConvert(LHSCases, bytesChecked, OrigBlock, NewDefault, Val, level + 1);
RBB = switchConvert(RHSCases, bytesChecked, OrigBlock, NewDefault, Val, level + 1);
/* insert instructions to check whether the value we are switching on is equal to byte */ LHSCases.push_back(Case);
ICmpInst* Comp = new ICmpInst(ICmpInst::ICMP_ULT, Trunc, ConstantInt::get(ByteType, pivot), "byteMatch");
} else {
RHSCases.push_back(Case);
}
}
BasicBlock *LBB, *RBB;
LBB = switchConvert(LHSCases, bytesChecked, OrigBlock, NewDefault, Val,
level + 1);
RBB = switchConvert(RHSCases, bytesChecked, OrigBlock, NewDefault, Val,
level + 1);
/* insert instructions to check whether the value we are switching on is
* equal to byte */
ICmpInst *Comp =
new ICmpInst(ICmpInst::ICMP_ULT, Trunc,
ConstantInt::get(ByteType, pivot), "byteMatch");
NewNode->getInstList().push_back(Comp); NewNode->getInstList().push_back(Comp);
BranchInst::Create(LBB, RBB, Comp, NewNode); BranchInst::Create(LBB, RBB, Comp, NewNode);
} }
return NewNode; return NewNode;
} }
bool SplitSwitchesTransform::splitSwitches(Module &M) { bool SplitSwitchesTransform::splitSwitches(Module &M) {
std::vector<SwitchInst*> switches; std::vector<SwitchInst *> switches;
/* iterate over all functions, bbs and instruction and add /* iterate over all functions, bbs and instruction and add
* all switches to switches vector for later processing */ * all switches to switches vector for later processing */
for (auto &F : M) { for (auto &F : M) {
for (auto &BB : F) { for (auto &BB : F) {
SwitchInst* switchInst = nullptr;
SwitchInst *switchInst = nullptr;
if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) { if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) {
if (switchInst->getNumCases() < 1)
continue; if (switchInst->getNumCases() < 1) continue;
switches.push_back(switchInst); switches.push_back(switchInst);
} }
} }
} }
if (!switches.size()) if (!switches.size()) return false;
return false; errs() << "Rewriting " << switches.size() << " switch statements "
errs() << "Rewriting " << switches.size() << " switch statements " << "\n"; << "\n";
for (auto &SI: switches) { for (auto &SI : switches) {
BasicBlock *CurBlock = SI->getParent(); BasicBlock *CurBlock = SI->getParent();
BasicBlock *OrigBlock = CurBlock; BasicBlock *OrigBlock = CurBlock;
Function *F = CurBlock->getParent(); Function * F = CurBlock->getParent();
/* this is the value we are switching on */ /* this is the value we are switching on */
Value *Val = SI->getCondition(); Value * Val = SI->getCondition();
BasicBlock* Default = SI->getDefaultDest(); BasicBlock *Default = SI->getDefaultDest();
unsigned bitw = Val->getType()->getIntegerBitWidth(); unsigned bitw = Val->getType()->getIntegerBitWidth();
errs() << "switch: " << SI->getNumCases() << " cases " << bitw << " bit\n"; errs() << "switch: " << SI->getNumCases() << " cases " << bitw << " bit\n";
/* If there is only the default destination or the condition checks 8 bit or less, don't bother with the code below. */ /* If there is only the default destination or the condition checks 8 bit or
* less, don't bother with the code below. */
if (!SI->getNumCases() || bitw <= 8) { if (!SI->getNumCases() || bitw <= 8) {
if (getenv("AFL_QUIET") == NULL)
errs() << "skip trivial switch..\n"; if (getenv("AFL_QUIET") == NULL) errs() << "skip trivial switch..\n";
continue; continue;
} }
/* Create a new, empty default block so that the new hierarchy of /* Create a new, empty default block so that the new hierarchy of
@ -258,10 +317,10 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
NewDefault->insertInto(F, Default); NewDefault->insertInto(F, Default);
BranchInst::Create(Default, NewDefault); BranchInst::Create(Default, NewDefault);
/* Prepare cases vector. */ /* Prepare cases vector. */
CaseVector Cases; CaseVector Cases;
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e; ++i) for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e;
++i)
#if LLVM_VERSION_MAJOR < 5 #if LLVM_VERSION_MAJOR < 5
Cases.push_back(CaseExpr(i.getCaseValue(), i.getCaseSuccessor())); Cases.push_back(CaseExpr(i.getCaseValue(), i.getCaseSuccessor()));
#else #else
@ -269,8 +328,10 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
#endif #endif
/* bugfix thanks to pbst /* bugfix thanks to pbst
* round up bytesChecked (in case getBitWidth() % 8 != 0) */ * round up bytesChecked (in case getBitWidth() % 8 != 0) */
std::vector<bool> bytesChecked((7 + Cases[0].Val->getBitWidth()) / 8, false); std::vector<bool> bytesChecked((7 + Cases[0].Val->getBitWidth()) / 8,
BasicBlock* SwitchBlock = switchConvert(Cases, bytesChecked, OrigBlock, NewDefault, Val, 0); false);
BasicBlock * SwitchBlock =
switchConvert(Cases, bytesChecked, OrigBlock, NewDefault, Val, 0);
/* Branch to our shiny new if-then stuff... */ /* Branch to our shiny new if-then stuff... */
BranchInst::Create(SwitchBlock, OrigBlock); BranchInst::Create(SwitchBlock, OrigBlock);
@ -278,41 +339,47 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) {
/* We are now done with the switch instruction, delete it. */ /* We are now done with the switch instruction, delete it. */
CurBlock->getInstList().erase(SI); CurBlock->getInstList().erase(SI);
/* we have to update the phi nodes! */
for (BasicBlock::iterator I = Default->begin(); I != Default->end(); ++I) {
/* we have to update the phi nodes! */ if (!isa<PHINode>(&*I)) { continue; }
for (BasicBlock::iterator I = Default->begin(); I != Default->end(); ++I) { PHINode *PN = cast<PHINode>(I);
if (!isa<PHINode>(&*I)) {
continue;
}
PHINode *PN = cast<PHINode>(I);
/* Only update the first occurrence. */ /* Only update the first occurrence. */
unsigned Idx = 0, E = PN->getNumIncomingValues(); unsigned Idx = 0, E = PN->getNumIncomingValues();
for (; Idx != E; ++Idx) { for (; Idx != E; ++Idx) {
if (PN->getIncomingBlock(Idx) == OrigBlock) {
PN->setIncomingBlock(Idx, NewDefault); if (PN->getIncomingBlock(Idx) == OrigBlock) {
break;
} PN->setIncomingBlock(Idx, NewDefault);
} break;
}
} }
}
}
}
verifyModule(M);
return true;
verifyModule(M);
return true;
} }
bool SplitSwitchesTransform::runOnModule(Module &M) { bool SplitSwitchesTransform::runOnModule(Module &M) {
if (getenv("AFL_QUIET") == NULL) if (getenv("AFL_QUIET") == NULL)
llvm::errs() << "Running split-switches-pass by laf.intel@gmail.com\n"; llvm::errs() << "Running split-switches-pass by laf.intel@gmail.com\n";
splitSwitches(M); splitSwitches(M);
verifyModule(M); verifyModule(M);
return true; return true;
} }
static void registerSplitSwitchesTransPass(const PassManagerBuilder &, static void registerSplitSwitchesTransPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) { legacy::PassManagerBase &PM) {
auto p = new SplitSwitchesTransform(); auto p = new SplitSwitchesTransform();
PM.add(p); PM.add(p);
@ -324,3 +391,4 @@ static RegisterStandardPasses RegisterSplitSwitchesTransPass(
static RegisterStandardPasses RegisterSplitSwitchesTransPass0( static RegisterStandardPasses RegisterSplitSwitchesTransPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitSwitchesTransPass); PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitSwitchesTransPass);

View File

@ -3,13 +3,13 @@
// Author: Mateusz Jurczyk (mjurczyk@google.com) // Author: Mateusz Jurczyk (mjurczyk@google.com)
// //
// Copyright 2019 Google LLC // Copyright 2019 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -17,7 +17,8 @@
// limitations under the License. // limitations under the License.
// //
// solution: echo -ne 'The quick brown fox jumps over the lazy dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest // solution: echo -ne 'The quick brown fox jumps over the lazy
// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
@ -25,39 +26,40 @@
#include <cstring> #include <cstring>
int main() { int main() {
char buffer[44] = { /* zero padding */ };
char buffer[44] = {/* zero padding */};
fread(buffer, 1, sizeof(buffer) - 1, stdin); fread(buffer, 1, sizeof(buffer) - 1, stdin);
if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 || if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 ||
strncmp(&buffer[20], "jumps over ", 11) != 0 || strncmp(&buffer[20], "jumps over ", 11) != 0 ||
strcmp(&buffer[31], "the lazy dog") != 0) { strcmp(&buffer[31], "the lazy dog") != 0) {
return 1; return 1;
} }
uint64_t x = 0; uint64_t x = 0;
fread(&x, sizeof(x), 1, stdin); fread(&x, sizeof(x), 1, stdin);
if (x != 0xCAFEBABECAFEBABE) { if (x != 0xCAFEBABECAFEBABE) { return 2; }
return 2;
}
uint32_t y = 0; uint32_t y = 0;
fread(&y, sizeof(y), 1, stdin); fread(&y, sizeof(y), 1, stdin);
if (y != 0xDEADC0DE) { if (y != 0xDEADC0DE) { return 3; }
return 3;
}
uint16_t z = 0; uint16_t z = 0;
fread(&z, sizeof(z), 1, stdin); fread(&z, sizeof(z), 1, stdin);
switch (z) { switch (z) {
case 0xBEEF:
break; case 0xBEEF: break;
default: default: return 4;
return 4;
} }
printf("Puzzle solved, congrats!\n"); printf("Puzzle solved, congrats!\n");
abort(); abort();
return 0; return 0;
} }

View File

@ -40,10 +40,9 @@
#define MAX_CMP_LENGTH 32 #define MAX_CMP_LENGTH 32
static void *__compcov_code_start, static void *__compcov_code_start, *__compcov_code_end;
*__compcov_code_end;
static u8 *__compcov_afl_map; static u8* __compcov_afl_map;
static u32 __compcov_level; static u32 __compcov_level;
@ -55,15 +54,11 @@ static int (*__libc_memcmp)(const void*, const void*, size_t);
static int debug_fd = -1; static int debug_fd = -1;
#define MAX_MAPPINGS 1024 #define MAX_MAPPINGS 1024
static struct mapping { static struct mapping { void *st, *en; } __compcov_ro[MAX_MAPPINGS];
void *st, *en;
} __compcov_ro[MAX_MAPPINGS];
static u32 __compcov_ro_cnt;
static u32 __compcov_ro_cnt;
/* Check an address against the list of read-only mappings. */ /* Check an address against the list of read-only mappings. */
@ -71,42 +66,42 @@ static u8 __compcov_is_ro(const void* ptr) {
u32 i; u32 i;
for (i = 0; i < __compcov_ro_cnt; i++) for (i = 0; i < __compcov_ro_cnt; i++)
if (ptr >= __compcov_ro[i].st && ptr <= __compcov_ro[i].en) return 1; if (ptr >= __compcov_ro[i].st && ptr <= __compcov_ro[i].en) return 1;
return 0; return 0;
} }
static size_t __strlen2(const char* s1, const char* s2, size_t max_length) {
static size_t __strlen2(const char *s1, const char *s2, size_t max_length) {
// from https://github.com/googleprojectzero/CompareCoverage // from https://github.com/googleprojectzero/CompareCoverage
size_t len = 0; size_t len = 0;
for (; len < max_length && s1[len] != '\0' && s2[len] != '\0'; len++) { } for (; len < max_length && s1[len] != '\0' && s2[len] != '\0'; len++) {}
return len; return len;
} }
/* Identify the binary boundaries in the memory mapping */ /* Identify the binary boundaries in the memory mapping */
static void __compcov_load(void) { static void __compcov_load(void) {
__libc_strcmp = dlsym(RTLD_NEXT, "strcmp"); __libc_strcmp = dlsym(RTLD_NEXT, "strcmp");
__libc_strncmp = dlsym(RTLD_NEXT, "strncmp"); __libc_strncmp = dlsym(RTLD_NEXT, "strncmp");
__libc_strcasecmp = dlsym(RTLD_NEXT, "strcasecmp"); __libc_strcasecmp = dlsym(RTLD_NEXT, "strcasecmp");
__libc_strncasecmp = dlsym(RTLD_NEXT, "strncasecmp"); __libc_strncasecmp = dlsym(RTLD_NEXT, "strncasecmp");
__libc_memcmp = dlsym(RTLD_NEXT, "memcmp"); __libc_memcmp = dlsym(RTLD_NEXT, "memcmp");
if (getenv("AFL_QEMU_COMPCOV")) { if (getenv("AFL_QEMU_COMPCOV")) { __compcov_level = 1; }
__compcov_level = 1;
}
if (getenv("AFL_COMPCOV_LEVEL")) { if (getenv("AFL_COMPCOV_LEVEL")) {
__compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL")); __compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL"));
} }
char *id_str = getenv(SHM_ENV_VAR); char* id_str = getenv(SHM_ENV_VAR);
int shm_id; int shm_id;
if (id_str) { if (id_str) {
@ -114,61 +109,72 @@ static void __compcov_load(void) {
__compcov_afl_map = shmat(shm_id, NULL, 0); __compcov_afl_map = shmat(shm_id, NULL, 0);
if (__compcov_afl_map == (void*)-1) exit(1); if (__compcov_afl_map == (void*)-1) exit(1);
} else { } else {
__compcov_afl_map = calloc(1, MAP_SIZE); __compcov_afl_map = calloc(1, MAP_SIZE);
} }
if (getenv("AFL_INST_LIBS")) { if (getenv("AFL_INST_LIBS")) {
__compcov_code_start = (void*)0; __compcov_code_start = (void*)0;
__compcov_code_end = (void*)-1; __compcov_code_end = (void*)-1;
return; return;
} }
char* bin_name = getenv("AFL_COMPCOV_BINNAME"); char* bin_name = getenv("AFL_COMPCOV_BINNAME");
procmaps_iterator* maps = pmparser_parse(-1); procmaps_iterator* maps = pmparser_parse(-1);
procmaps_struct* maps_tmp = NULL; procmaps_struct* maps_tmp = NULL;
while ((maps_tmp = pmparser_next(maps)) != NULL) { while ((maps_tmp = pmparser_next(maps)) != NULL) {
/* If AFL_COMPCOV_BINNAME is not set pick the first executable segment */ /* If AFL_COMPCOV_BINNAME is not set pick the first executable segment */
if (!bin_name || strstr(maps_tmp->pathname, bin_name) != NULL) { if (!bin_name || strstr(maps_tmp->pathname, bin_name) != NULL) {
if (maps_tmp->is_x) { if (maps_tmp->is_x) {
if (!__compcov_code_start)
__compcov_code_start = maps_tmp->addr_start; if (!__compcov_code_start) __compcov_code_start = maps_tmp->addr_start;
if (!__compcov_code_end) if (!__compcov_code_end) __compcov_code_end = maps_tmp->addr_end;
__compcov_code_end = maps_tmp->addr_end;
} }
} }
if ((maps_tmp->is_w && !maps_tmp->is_r) || __compcov_ro_cnt == MAX_MAPPINGS) if ((maps_tmp->is_w && !maps_tmp->is_r) || __compcov_ro_cnt == MAX_MAPPINGS)
continue; continue;
__compcov_ro[__compcov_ro_cnt].st = maps_tmp->addr_start; __compcov_ro[__compcov_ro_cnt].st = maps_tmp->addr_start;
__compcov_ro[__compcov_ro_cnt].en = maps_tmp->addr_end; __compcov_ro[__compcov_ro_cnt].en = maps_tmp->addr_end;
} }
pmparser_free(maps); pmparser_free(maps);
}
}
static void __compcov_trace(u64 cur_loc, const u8* v0, const u8* v1, size_t n) { static void __compcov_trace(u64 cur_loc, const u8* v0, const u8* v1, size_t n) {
size_t i; size_t i;
if (debug_fd != 1) { if (debug_fd != 1) {
char debugbuf[4096]; char debugbuf[4096];
snprintf(debugbuf, sizeof(debugbuf), "0x%llx %s %s %lu\n", cur_loc, v0 == NULL ? "(null)" : (char*)v0, v1 == NULL ? "(null)" : (char*)v1, n); snprintf(debugbuf, sizeof(debugbuf), "0x%llx %s %s %lu\n", cur_loc,
v0 == NULL ? "(null)" : (char*)v0,
v1 == NULL ? "(null)" : (char*)v1, n);
write(debug_fd, debugbuf, strlen(debugbuf)); write(debug_fd, debugbuf, strlen(debugbuf));
} }
for (i = 0; i < n && v0[i] == v1[i]; ++i) { for (i = 0; i < n && v0[i] == v1[i]; ++i) {
__compcov_afl_map[cur_loc +i]++; __compcov_afl_map[cur_loc + i]++;
} }
} }
/* Check an address against the list of read-only mappings. */ /* Check an address against the list of read-only mappings. */
@ -176,8 +182,8 @@ static void __compcov_trace(u64 cur_loc, const u8* v0, const u8* v1, size_t n) {
static u8 __compcov_is_in_bound(const void* ptr) { static u8 __compcov_is_in_bound(const void* ptr) {
return ptr >= __compcov_code_start && ptr < __compcov_code_end; return ptr >= __compcov_code_start && ptr < __compcov_code_end;
}
}
/* Replacements for strcmp(), memcmp(), and so on. Note that these will be used /* Replacements for strcmp(), memcmp(), and so on. Note that these will be used
only if the target is compiled with -fno-builtins and linked dynamically. */ only if the target is compiled with -fno-builtins and linked dynamically. */
@ -187,127 +193,145 @@ static u8 __compcov_is_in_bound(const void* ptr) {
int strcmp(const char* str1, const char* str2) { int strcmp(const char* str1, const char* str2) {
void* retaddr = __builtin_return_address(0); void* retaddr = __builtin_return_address(0);
if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 &&
!__compcov_is_ro(str1) && !__compcov_is_ro(str2))) {
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1); if (__compcov_is_in_bound(retaddr) &&
!(__compcov_level < 2 && !__compcov_is_ro(str1) &&
!__compcov_is_ro(str2))) {
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH + 1);
if (n <= MAX_CMP_LENGTH) { if (n <= MAX_CMP_LENGTH) {
u64 cur_loc = (u64)retaddr; u64 cur_loc = (u64)retaddr;
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 1; cur_loc &= MAP_SIZE - 1;
__compcov_trace(cur_loc, str1, str2, n); __compcov_trace(cur_loc, str1, str2, n);
} }
} }
return __libc_strcmp(str1, str2); return __libc_strcmp(str1, str2);
}
}
#undef strncmp #undef strncmp
int strncmp(const char* str1, const char* str2, size_t len) { int strncmp(const char* str1, const char* str2, size_t len) {
void* retaddr = __builtin_return_address(0); void* retaddr = __builtin_return_address(0);
if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 &&
!__compcov_is_ro(str1) && !__compcov_is_ro(str2))) {
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1); if (__compcov_is_in_bound(retaddr) &&
!(__compcov_level < 2 && !__compcov_is_ro(str1) &&
!__compcov_is_ro(str2))) {
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH + 1);
n = MIN(n, len); n = MIN(n, len);
if (n <= MAX_CMP_LENGTH) {
u64 cur_loc = (u64)retaddr;
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 1;
__compcov_trace(cur_loc, str1, str2, n);
}
}
return __libc_strncmp(str1, str2, len);
}
if (n <= MAX_CMP_LENGTH) {
u64 cur_loc = (u64)retaddr;
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 1;
__compcov_trace(cur_loc, str1, str2, n);
}
}
return __libc_strncmp(str1, str2, len);
}
#undef strcasecmp #undef strcasecmp
int strcasecmp(const char* str1, const char* str2) { int strcasecmp(const char* str1, const char* str2) {
void* retaddr = __builtin_return_address(0); void* retaddr = __builtin_return_address(0);
if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 && if (__compcov_is_in_bound(retaddr) &&
!__compcov_is_ro(str1) && !__compcov_is_ro(str2))) { !(__compcov_level < 2 && !__compcov_is_ro(str1) &&
!__compcov_is_ro(str2))) {
/* Fallback to strcmp, maybe improve in future */ /* Fallback to strcmp, maybe improve in future */
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1); size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH + 1);
if (n <= MAX_CMP_LENGTH) { if (n <= MAX_CMP_LENGTH) {
u64 cur_loc = (u64)retaddr; u64 cur_loc = (u64)retaddr;
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 1; cur_loc &= MAP_SIZE - 1;
__compcov_trace(cur_loc, str1, str2, n); __compcov_trace(cur_loc, str1, str2, n);
} }
} }
return __libc_strcasecmp(str1, str2); return __libc_strcasecmp(str1, str2);
}
}
#undef strncasecmp #undef strncasecmp
int strncasecmp(const char* str1, const char* str2, size_t len) { int strncasecmp(const char* str1, const char* str2, size_t len) {
void* retaddr = __builtin_return_address(0); void* retaddr = __builtin_return_address(0);
if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 && if (__compcov_is_in_bound(retaddr) &&
!__compcov_is_ro(str1) && !__compcov_is_ro(str2))) { !(__compcov_level < 2 && !__compcov_is_ro(str1) &&
!__compcov_is_ro(str2))) {
/* Fallback to strncmp, maybe improve in future */ /* Fallback to strncmp, maybe improve in future */
size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1); size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH + 1);
n = MIN(n, len); n = MIN(n, len);
if (n <= MAX_CMP_LENGTH) { if (n <= MAX_CMP_LENGTH) {
u64 cur_loc = (u64)retaddr; u64 cur_loc = (u64)retaddr;
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 1; cur_loc &= MAP_SIZE - 1;
__compcov_trace(cur_loc, str1, str2, n); __compcov_trace(cur_loc, str1, str2, n);
} }
} }
return __libc_strncasecmp(str1, str2, len); return __libc_strncasecmp(str1, str2, len);
}
}
#undef memcmp #undef memcmp
int memcmp(const void* mem1, const void* mem2, size_t len) { int memcmp(const void* mem1, const void* mem2, size_t len) {
void* retaddr = __builtin_return_address(0); void* retaddr = __builtin_return_address(0);
if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 && if (__compcov_is_in_bound(retaddr) &&
!__compcov_is_ro(mem1) && !__compcov_is_ro(mem2))) { !(__compcov_level < 2 && !__compcov_is_ro(mem1) &&
!__compcov_is_ro(mem2))) {
size_t n = len; size_t n = len;
if (n <= MAX_CMP_LENGTH) { if (n <= MAX_CMP_LENGTH) {
u64 cur_loc = (u64)retaddr; u64 cur_loc = (u64)retaddr;
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 1; cur_loc &= MAP_SIZE - 1;
__compcov_trace(cur_loc, mem1, mem2, n); __compcov_trace(cur_loc, mem1, mem2, n);
} }
} }
return __libc_memcmp(mem1, mem2, len); return __libc_memcmp(mem1, mem2, len);
} }
/* Init code to open init the library. */ /* Init code to open init the library. */
@ -315,9 +339,10 @@ int memcmp(const void* mem1, const void* mem2, size_t len) {
__attribute__((constructor)) void __compcov_init(void) { __attribute__((constructor)) void __compcov_init(void) {
if (getenv("AFL_QEMU_COMPCOV_DEBUG") != NULL) if (getenv("AFL_QEMU_COMPCOV_DEBUG") != NULL)
debug_fd = open("compcov.debug", O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, 0644); debug_fd =
open("compcov.debug", O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, 0644);
__compcov_load(); __compcov_load();
} }

View File

@ -13,54 +13,60 @@ implied warranty.
*/ */
#ifndef H_PMPARSER #ifndef H_PMPARSER
#define H_PMPARSER # define H_PMPARSER
#include <stdio.h> # include <stdio.h>
#include <stdlib.h> # include <stdlib.h>
#include <unistd.h> # include <unistd.h>
#include <string.h> # include <string.h>
#include <sys/types.h> # include <sys/types.h>
#include <sys/stat.h> # include <sys/stat.h>
#include <fcntl.h> # include <fcntl.h>
#include <errno.h> # include <errno.h>
#include <linux/limits.h> # include <linux/limits.h>
//maximum line length in a procmaps file // maximum line length in a procmaps file
#define PROCMAPS_LINE_MAX_LENGTH (PATH_MAX + 100) # define PROCMAPS_LINE_MAX_LENGTH (PATH_MAX + 100)
/** /**
* procmaps_struct * procmaps_struct
* @desc hold all the information about an area in the process's VM * @desc hold all the information about an area in the process's VM
*/ */
typedef struct procmaps_struct{ typedef struct procmaps_struct {
void* addr_start; //< start address of the area
void* addr_end; //< end address
unsigned long length; //< size of the range
char perm[5]; //< permissions rwxp void* addr_start; //< start address of the area
short is_r; //< rewrote of perm with short flags void* addr_end; //< end address
short is_w; unsigned long length; //< size of the range
short is_x;
short is_p;
long offset; //< offset char perm[5]; //< permissions rwxp
char dev[12]; //< dev major:minor short is_r; //< rewrote of perm with short flags
int inode; //< inode of the file that backs the area short is_w;
short is_x;
short is_p;
long offset; //< offset
char dev[12]; //< dev major:minor
int inode; //< inode of the file that backs the area
char pathname[600]; //< the path of the file that backs the area
// chained list
struct procmaps_struct* next; //<handler of the chinaed list
char pathname[600]; //< the path of the file that backs the area
//chained list
struct procmaps_struct* next; //<handler of the chinaed list
} procmaps_struct; } procmaps_struct;
/** /**
* procmaps_iterator * procmaps_iterator
* @desc holds iterating information * @desc holds iterating information
*/ */
typedef struct procmaps_iterator{ typedef struct procmaps_iterator {
procmaps_struct* head;
procmaps_struct* current; procmaps_struct* head;
procmaps_struct* current;
} procmaps_iterator; } procmaps_iterator;
/** /**
* pmparser_parse * pmparser_parse
* @param pid the process id whose memory map to be parser. the current process if pid<0 * @param pid the process id whose memory map to be parser. the current process
* if pid<0
* @return an iterator over all the nodes * @return an iterator over all the nodes
*/ */
procmaps_iterator* pmparser_parse(int pid); procmaps_iterator* pmparser_parse(int pid);
@ -83,198 +89,238 @@ void pmparser_free(procmaps_iterator* p_procmaps_it);
* _pmparser_split_line * _pmparser_split_line
* @description internal usage * @description internal usage
*/ */
void _pmparser_split_line(char*buf,char*addr1,char*addr2,char*perm, char* offset, char* device,char*inode,char* pathname); void _pmparser_split_line(char* buf, char* addr1, char* addr2, char* perm,
char* offset, char* device, char* inode,
char* pathname);
/** /**
* pmparser_print * pmparser_print
* @param map the head of the list * @param map the head of the list
* @order the order of the area to print, -1 to print everything * @order the order of the area to print, -1 to print everything
*/ */
void pmparser_print(procmaps_struct* map,int order); void pmparser_print(procmaps_struct* map, int order);
/** /**
* gobal variables * gobal variables
*/ */
//procmaps_struct* g_last_head=NULL; // procmaps_struct* g_last_head=NULL;
//procmaps_struct* g_current=NULL; // procmaps_struct* g_current=NULL;
procmaps_iterator* pmparser_parse(int pid) {
procmaps_iterator* pmparser_parse(int pid){ procmaps_iterator* maps_it = malloc(sizeof(procmaps_iterator));
procmaps_iterator* maps_it = malloc(sizeof(procmaps_iterator)); char maps_path[500];
char maps_path[500]; if (pid >= 0) {
if(pid>=0 ){
sprintf(maps_path,"/proc/%d/maps",pid);
}else{
sprintf(maps_path,"/proc/self/maps");
}
FILE* file=fopen(maps_path,"r");
if(!file){
fprintf(stderr,"pmparser : cannot open the memory maps, %s\n",strerror(errno));
return NULL;
}
int ind=0;char buf[PROCMAPS_LINE_MAX_LENGTH];
//int c;
procmaps_struct* list_maps=NULL;
procmaps_struct* tmp;
procmaps_struct* current_node=list_maps;
char addr1[20],addr2[20], perm[8], offset[20], dev[10],inode[30],pathname[PATH_MAX];
while( !feof(file) ){
fgets(buf,PROCMAPS_LINE_MAX_LENGTH,file);
//allocate a node
tmp=(procmaps_struct*)malloc(sizeof(procmaps_struct));
//fill the node
_pmparser_split_line(buf,addr1,addr2,perm,offset, dev,inode,pathname);
//printf("#%s",buf);
//printf("%s-%s %s %s %s %s\t%s\n",addr1,addr2,perm,offset,dev,inode,pathname);
//addr_start & addr_end
//unsigned long l_addr_start;
sscanf(addr1,"%lx",(long unsigned *)&tmp->addr_start );
sscanf(addr2,"%lx",(long unsigned *)&tmp->addr_end );
//size
tmp->length=(unsigned long)(tmp->addr_end-tmp->addr_start);
//perm
strcpy(tmp->perm,perm);
tmp->is_r=(perm[0]=='r');
tmp->is_w=(perm[1]=='w');
tmp->is_x=(perm[2]=='x');
tmp->is_p=(perm[3]=='p');
//offset sprintf(maps_path, "/proc/%d/maps", pid);
sscanf(offset,"%lx",&tmp->offset );
//device
strcpy(tmp->dev,dev);
//inode
tmp->inode=atoi(inode);
//pathname
strcpy(tmp->pathname,pathname);
tmp->next=NULL;
//attach the node
if(ind==0){
list_maps=tmp;
list_maps->next=NULL;
current_node=list_maps;
}
current_node->next=tmp;
current_node=tmp;
ind++;
//printf("%s",buf);
}
//close file } else {
fclose(file);
sprintf(maps_path, "/proc/self/maps");
//g_last_head=list_maps; }
maps_it->head = list_maps;
maps_it->current = list_maps;
return maps_it;
}
FILE* file = fopen(maps_path, "r");
if (!file) {
procmaps_struct* pmparser_next(procmaps_iterator* p_procmaps_it){ fprintf(stderr, "pmparser : cannot open the memory maps, %s\n",
if(p_procmaps_it->current == NULL) strerror(errno));
return NULL; return NULL;
procmaps_struct* p_current = p_procmaps_it->current;
p_procmaps_it->current = p_procmaps_it->current->next;
return p_current;
/*
if(g_current==NULL){
g_current=g_last_head;
}else
g_current=g_current->next;
return g_current; }
*/
}
int ind = 0;
char buf[PROCMAPS_LINE_MAX_LENGTH];
// int c;
procmaps_struct* list_maps = NULL;
procmaps_struct* tmp;
procmaps_struct* current_node = list_maps;
char addr1[20], addr2[20], perm[8], offset[20], dev[10], inode[30],
pathname[PATH_MAX];
while (!feof(file)) {
fgets(buf, PROCMAPS_LINE_MAX_LENGTH, file);
// allocate a node
tmp = (procmaps_struct*)malloc(sizeof(procmaps_struct));
// fill the node
_pmparser_split_line(buf, addr1, addr2, perm, offset, dev, inode, pathname);
// printf("#%s",buf);
// printf("%s-%s %s %s %s
// %s\t%s\n",addr1,addr2,perm,offset,dev,inode,pathname); addr_start &
// addr_end unsigned long l_addr_start;
sscanf(addr1, "%lx", (long unsigned*)&tmp->addr_start);
sscanf(addr2, "%lx", (long unsigned*)&tmp->addr_end);
// size
tmp->length = (unsigned long)(tmp->addr_end - tmp->addr_start);
// perm
strcpy(tmp->perm, perm);
tmp->is_r = (perm[0] == 'r');
tmp->is_w = (perm[1] == 'w');
tmp->is_x = (perm[2] == 'x');
tmp->is_p = (perm[3] == 'p');
void pmparser_free(procmaps_iterator* p_procmaps_it){ // offset
procmaps_struct* maps_list = p_procmaps_it->head; sscanf(offset, "%lx", &tmp->offset);
if(maps_list==NULL) return ; // device
procmaps_struct* act=maps_list; strcpy(tmp->dev, dev);
procmaps_struct* nxt=act->next; // inode
while(act!=NULL){ tmp->inode = atoi(inode);
free(act); // pathname
act=nxt; strcpy(tmp->pathname, pathname);
if(nxt!=NULL) tmp->next = NULL;
nxt=nxt->next; // attach the node
} if (ind == 0) {
list_maps = tmp;
list_maps->next = NULL;
current_node = list_maps;
}
current_node->next = tmp;
current_node = tmp;
ind++;
// printf("%s",buf);
}
// close file
fclose(file);
// g_last_head=list_maps;
maps_it->head = list_maps;
maps_it->current = list_maps;
return maps_it;
} }
procmaps_struct* pmparser_next(procmaps_iterator* p_procmaps_it) {
void _pmparser_split_line( if (p_procmaps_it->current == NULL) return NULL;
char*buf,char*addr1,char*addr2, procmaps_struct* p_current = p_procmaps_it->current;
char*perm,char* offset,char* device,char*inode, p_procmaps_it->current = p_procmaps_it->current->next;
char* pathname){ return p_current;
// /*
int orig=0; if(g_current==NULL){
int i=0;
//addr1
while(buf[i]!='-'){
addr1[i-orig]=buf[i];
i++;
}
addr1[i]='\0';
i++;
//addr2
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
addr2[i-orig]=buf[i];
i++;
}
addr2[i-orig]='\0';
//perm g_current=g_last_head;
while(buf[i]=='\t' || buf[i]==' ')
i++; }else
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){ g_current=g_current->next;
perm[i-orig]=buf[i];
i++; return g_current;
} */
perm[i-orig]='\0';
//offset
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
offset[i-orig]=buf[i];
i++;
}
offset[i-orig]='\0';
//dev
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
device[i-orig]=buf[i];
i++;
}
device[i-orig]='\0';
//inode
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
inode[i-orig]=buf[i];
i++;
}
inode[i-orig]='\0';
//pathname
pathname[0]='\0';
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' ' && buf[i]!='\n'){
pathname[i-orig]=buf[i];
i++;
}
pathname[i-orig]='\0';
} }
void pmparser_free(procmaps_iterator* p_procmaps_it) {
procmaps_struct* maps_list = p_procmaps_it->head;
if (maps_list == NULL) return;
procmaps_struct* act = maps_list;
procmaps_struct* nxt = act->next;
while (act != NULL) {
free(act);
act = nxt;
if (nxt != NULL) nxt = nxt->next;
}
}
void _pmparser_split_line(char* buf, char* addr1, char* addr2, char* perm,
char* offset, char* device, char* inode,
char* pathname) {
//
int orig = 0;
int i = 0;
// addr1
while (buf[i] != '-') {
addr1[i - orig] = buf[i];
i++;
}
addr1[i] = '\0';
i++;
// addr2
orig = i;
while (buf[i] != '\t' && buf[i] != ' ') {
addr2[i - orig] = buf[i];
i++;
}
addr2[i - orig] = '\0';
// perm
while (buf[i] == '\t' || buf[i] == ' ')
i++;
orig = i;
while (buf[i] != '\t' && buf[i] != ' ') {
perm[i - orig] = buf[i];
i++;
}
perm[i - orig] = '\0';
// offset
while (buf[i] == '\t' || buf[i] == ' ')
i++;
orig = i;
while (buf[i] != '\t' && buf[i] != ' ') {
offset[i - orig] = buf[i];
i++;
}
offset[i - orig] = '\0';
// dev
while (buf[i] == '\t' || buf[i] == ' ')
i++;
orig = i;
while (buf[i] != '\t' && buf[i] != ' ') {
device[i - orig] = buf[i];
i++;
}
device[i - orig] = '\0';
// inode
while (buf[i] == '\t' || buf[i] == ' ')
i++;
orig = i;
while (buf[i] != '\t' && buf[i] != ' ') {
inode[i - orig] = buf[i];
i++;
}
inode[i - orig] = '\0';
// pathname
pathname[0] = '\0';
while (buf[i] == '\t' || buf[i] == ' ')
i++;
orig = i;
while (buf[i] != '\t' && buf[i] != ' ' && buf[i] != '\n') {
pathname[i - orig] = buf[i];
i++;
}
pathname[i - orig] = '\0';
}
#endif #endif

View File

@ -33,19 +33,17 @@
#include "../../config.h" #include "../../config.h"
/* NeverZero */ /* NeverZero */
#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO)
# define INC_AFL_AREA(loc) \ # define INC_AFL_AREA(loc) \
asm volatile ( \ asm volatile( \
"incb (%0, %1, 1)\n" \ "incb (%0, %1, 1)\n" \
"adcb $0, (%0, %1, 1)\n" \ "adcb $0, (%0, %1, 1)\n" \
: /* no out */ \ : /* no out */ \
: "r" (afl_area_ptr), "r" (loc) \ : "r"(afl_area_ptr), "r"(loc) \
: "memory", "eax" \ : "memory", "eax")
)
#else #else
# define INC_AFL_AREA(loc) \ # define INC_AFL_AREA(loc) afl_area_ptr[loc]++
afl_area_ptr[loc]++
#endif #endif

View File

@ -42,11 +42,16 @@
_start and does the usual forkserver stuff, not very different from _start and does the usual forkserver stuff, not very different from
regular instrumentation injected via afl-as.h. */ regular instrumentation injected via afl-as.h. */
#define AFL_QEMU_CPU_SNIPPET2 do { \ #define AFL_QEMU_CPU_SNIPPET2 \
if(itb->pc == afl_entry_point) { \ do { \
afl_setup(); \ \
afl_forkserver(cpu); \ if (itb->pc == afl_entry_point) { \
} \ \
afl_setup(); \
afl_forkserver(cpu); \
\
} \
\
} while (0) } while (0)
/* We use one additional file descriptor to relay "needs translation" /* We use one additional file descriptor to relay "needs translation"
@ -56,60 +61,71 @@
/* This is equivalent to afl-as.h: */ /* This is equivalent to afl-as.h: */
static unsigned char dummy[MAP_SIZE]; /* costs MAP_SIZE but saves a few instructions */ static unsigned char
unsigned char *afl_area_ptr = dummy; /* Exported for afl_gen_trace */ dummy[MAP_SIZE]; /* costs MAP_SIZE but saves a few instructions */
unsigned char *afl_area_ptr = dummy; /* Exported for afl_gen_trace */
/* Exported variables populated by the code patched into elfload.c: */ /* Exported variables populated by the code patched into elfload.c: */
abi_ulong afl_entry_point, /* ELF entry point (_start) */ abi_ulong afl_entry_point, /* ELF entry point (_start) */
afl_start_code, /* .text start pointer */ afl_start_code, /* .text start pointer */
afl_end_code; /* .text end pointer */ afl_end_code; /* .text end pointer */
u8 afl_compcov_level; u8 afl_compcov_level;
/* Set in the child process in forkserver mode: */ /* Set in the child process in forkserver mode: */
static int forkserver_installed = 0; static int forkserver_installed = 0;
static unsigned char afl_fork_child; static unsigned char afl_fork_child;
unsigned int afl_forksrv_pid; unsigned int afl_forksrv_pid;
/* Instrumentation ratio: */ /* Instrumentation ratio: */
unsigned int afl_inst_rms = MAP_SIZE; /* Exported for afl_gen_trace */ unsigned int afl_inst_rms = MAP_SIZE; /* Exported for afl_gen_trace */
/* Function declarations. */ /* Function declarations. */
static void afl_setup(void); static void afl_setup(void);
static void afl_forkserver(CPUState*); static void afl_forkserver(CPUState *);
static void afl_wait_tsl(CPUState*, int); static void afl_wait_tsl(CPUState *, int);
static void afl_request_tsl(target_ulong, target_ulong, uint32_t, uint32_t, TranslationBlock*, int); static void afl_request_tsl(target_ulong, target_ulong, uint32_t, uint32_t,
TranslationBlock *, int);
/* Data structures passed around by the translate handlers: */ /* Data structures passed around by the translate handlers: */
struct afl_tb { struct afl_tb {
target_ulong pc; target_ulong pc;
target_ulong cs_base; target_ulong cs_base;
uint32_t flags; uint32_t flags;
uint32_t cf_mask; uint32_t cf_mask;
}; };
struct afl_tsl { struct afl_tsl {
struct afl_tb tb; struct afl_tb tb;
char is_chain; char is_chain;
}; };
struct afl_chain { struct afl_chain {
struct afl_tb last_tb; struct afl_tb last_tb;
uint32_t cf_mask; uint32_t cf_mask;
int tb_exit; int tb_exit;
}; };
/* Some forward decls: */ /* Some forward decls: */
TranslationBlock *tb_htable_lookup(CPUState*, target_ulong, target_ulong, uint32_t, uint32_t); TranslationBlock *tb_htable_lookup(CPUState *, target_ulong, target_ulong,
static inline TranslationBlock *tb_find(CPUState*, TranslationBlock*, int, uint32_t); uint32_t, uint32_t);
static inline void tb_add_jump(TranslationBlock *tb, int n, TranslationBlock *tb_next); static inline TranslationBlock *tb_find(CPUState *, TranslationBlock *, int,
uint32_t);
static inline void tb_add_jump(TranslationBlock *tb, int n,
TranslationBlock *tb_next);
/************************* /*************************
* ACTUAL IMPLEMENTATION * * ACTUAL IMPLEMENTATION *
@ -119,8 +135,7 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, TranslationBlock *tb
static void afl_setup(void) { static void afl_setup(void) {
char *id_str = getenv(SHM_ENV_VAR), char *id_str = getenv(SHM_ENV_VAR), *inst_r = getenv("AFL_INST_RATIO");
*inst_r = getenv("AFL_INST_RATIO");
int shm_id; int shm_id;
@ -142,7 +157,7 @@ static void afl_setup(void) {
shm_id = atoi(id_str); shm_id = atoi(id_str);
afl_area_ptr = shmat(shm_id, NULL, 0); afl_area_ptr = shmat(shm_id, NULL, 0);
if (afl_area_ptr == (void*)-1) exit(1); if (afl_area_ptr == (void *)-1) exit(1);
/* With AFL_INST_RATIO set to a low value, we want to touch the bitmap /* With AFL_INST_RATIO set to a low value, we want to touch the bitmap
so that the parent doesn't give up on us. */ so that the parent doesn't give up on us. */
@ -154,18 +169,16 @@ static void afl_setup(void) {
if (getenv("AFL_INST_LIBS")) { if (getenv("AFL_INST_LIBS")) {
afl_start_code = 0; afl_start_code = 0;
afl_end_code = (abi_ulong)-1; afl_end_code = (abi_ulong)-1;
} }
/* Maintain for compatibility */ /* Maintain for compatibility */
if (getenv("AFL_QEMU_COMPCOV")) { if (getenv("AFL_QEMU_COMPCOV")) { afl_compcov_level = 1; }
afl_compcov_level = 1;
}
if (getenv("AFL_COMPCOV_LEVEL")) { if (getenv("AFL_COMPCOV_LEVEL")) {
afl_compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL")); afl_compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL"));
} }
/* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm /* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm
@ -176,17 +189,15 @@ static void afl_setup(void) {
} }
/* Fork server logic, invoked once we hit _start. */ /* Fork server logic, invoked once we hit _start. */
static void afl_forkserver(CPUState *cpu) { static void afl_forkserver(CPUState *cpu) {
static unsigned char tmp[4]; static unsigned char tmp[4];
if (forkserver_installed == 1) if (forkserver_installed == 1) return;
return;
forkserver_installed = 1; forkserver_installed = 1;
//if (!afl_area_ptr) return; // not necessary because of fixed dummy buffer // if (!afl_area_ptr) return; // not necessary because of fixed dummy buffer
/* Tell the parent that we're alive. If the parent doesn't want /* Tell the parent that we're alive. If the parent doesn't want
to talk, assume that we're not running in forkserver mode. */ to talk, assume that we're not running in forkserver mode. */
@ -200,7 +211,7 @@ static void afl_forkserver(CPUState *cpu) {
while (1) { while (1) {
pid_t child_pid; pid_t child_pid;
int status, t_fd[2]; int status, t_fd[2];
/* Whoops, parent dead? */ /* Whoops, parent dead? */
@ -246,59 +257,60 @@ static void afl_forkserver(CPUState *cpu) {
} }
/* This code is invoked whenever QEMU decides that it doesn't have a /* This code is invoked whenever QEMU decides that it doesn't have a
translation of a particular block and needs to compute it, or when it translation of a particular block and needs to compute it, or when it
decides to chain two TBs together. When this happens, we tell the parent to decides to chain two TBs together. When this happens, we tell the parent to
mirror the operation, so that the next fork() has a cached copy. */ mirror the operation, so that the next fork() has a cached copy. */
static void afl_request_tsl(target_ulong pc, target_ulong cb, uint32_t flags, uint32_t cf_mask, static void afl_request_tsl(target_ulong pc, target_ulong cb, uint32_t flags,
TranslationBlock *last_tb, int tb_exit) { uint32_t cf_mask, TranslationBlock *last_tb,
int tb_exit) {
struct afl_tsl t; struct afl_tsl t;
struct afl_chain c; struct afl_chain c;
if (!afl_fork_child) return; if (!afl_fork_child) return;
t.tb.pc = pc; t.tb.pc = pc;
t.tb.cs_base = cb; t.tb.cs_base = cb;
t.tb.flags = flags; t.tb.flags = flags;
t.tb.cf_mask = cf_mask; t.tb.cf_mask = cf_mask;
t.is_chain = (last_tb != NULL); t.is_chain = (last_tb != NULL);
if (write(TSL_FD, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) if (write(TSL_FD, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl))
return; return;
if (t.is_chain) { if (t.is_chain) {
c.last_tb.pc = last_tb->pc;
c.last_tb.pc = last_tb->pc;
c.last_tb.cs_base = last_tb->cs_base; c.last_tb.cs_base = last_tb->cs_base;
c.last_tb.flags = last_tb->flags; c.last_tb.flags = last_tb->flags;
c.cf_mask = cf_mask; c.cf_mask = cf_mask;
c.tb_exit = tb_exit; c.tb_exit = tb_exit;
if (write(TSL_FD, &c, sizeof(struct afl_chain)) != sizeof(struct afl_chain)) if (write(TSL_FD, &c, sizeof(struct afl_chain)) != sizeof(struct afl_chain))
return; return;
} }
} }
/* Check if an address is valid in the current mapping */ /* Check if an address is valid in the current mapping */
static inline int is_valid_addr(target_ulong addr) { static inline int is_valid_addr(target_ulong addr) {
int l, flags; int l, flags;
target_ulong page; target_ulong page;
void * p; void * p;
page = addr & TARGET_PAGE_MASK; page = addr & TARGET_PAGE_MASK;
l = (page + TARGET_PAGE_SIZE) - addr; l = (page + TARGET_PAGE_SIZE) - addr;
flags = page_get_flags(page); flags = page_get_flags(page);
if (!(flags & PAGE_VALID) || !(flags & PAGE_READ)) if (!(flags & PAGE_VALID) || !(flags & PAGE_READ)) return 0;
return 0;
return 1;
return 1;
} }
/* This is the other side of the same channel. Since timeouts are handled by /* This is the other side of the same channel. Since timeouts are handled by
@ -306,8 +318,8 @@ static inline int is_valid_addr(target_ulong addr) {
static void afl_wait_tsl(CPUState *cpu, int fd) { static void afl_wait_tsl(CPUState *cpu, int fd) {
struct afl_tsl t; struct afl_tsl t;
struct afl_chain c; struct afl_chain c;
TranslationBlock *tb, *last_tb; TranslationBlock *tb, *last_tb;
while (1) { while (1) {
@ -316,30 +328,33 @@ static void afl_wait_tsl(CPUState *cpu, int fd) {
/* Broken pipe means it's time to return to the fork server routine. */ /* Broken pipe means it's time to return to the fork server routine. */
if (read(fd, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) if (read(fd, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) break;
break;
tb = tb_htable_lookup(cpu, t.tb.pc, t.tb.cs_base, t.tb.flags, t.tb.cf_mask); tb = tb_htable_lookup(cpu, t.tb.pc, t.tb.cs_base, t.tb.flags, t.tb.cf_mask);
if(!tb) { if (!tb) {
/* The child may request to transate a block of memory that is not /* The child may request to transate a block of memory that is not
mapped in the parent (e.g. jitted code or dlopened code). mapped in the parent (e.g. jitted code or dlopened code).
This causes a SIGSEV in gen_intermediate_code() and associated This causes a SIGSEV in gen_intermediate_code() and associated
subroutines. We simply avoid caching of such blocks. */ subroutines. We simply avoid caching of such blocks. */
if (is_valid_addr(t.tb.pc)) { if (is_valid_addr(t.tb.pc)) {
mmap_lock(); mmap_lock();
tb = tb_gen_code(cpu, t.tb.pc, t.tb.cs_base, t.tb.flags, t.tb.cf_mask); tb = tb_gen_code(cpu, t.tb.pc, t.tb.cs_base, t.tb.flags, t.tb.cf_mask);
mmap_unlock(); mmap_unlock();
} else { } else {
invalid_pc = 1; invalid_pc = 1;
} }
} }
if (t.is_chain) { if (t.is_chain) {
if (read(fd, &c, sizeof(struct afl_chain)) != sizeof(struct afl_chain)) if (read(fd, &c, sizeof(struct afl_chain)) != sizeof(struct afl_chain))
break; break;
@ -347,10 +362,10 @@ static void afl_wait_tsl(CPUState *cpu, int fd) {
last_tb = tb_htable_lookup(cpu, c.last_tb.pc, c.last_tb.cs_base, last_tb = tb_htable_lookup(cpu, c.last_tb.pc, c.last_tb.cs_base,
c.last_tb.flags, c.cf_mask); c.last_tb.flags, c.cf_mask);
if (last_tb) { if (last_tb) { tb_add_jump(last_tb, c.tb_exit, tb); }
tb_add_jump(last_tb, c.tb_exit, tb);
}
} }
} }
} }
@ -358,3 +373,4 @@ static void afl_wait_tsl(CPUState *cpu, int fd) {
close(fd); close(fd);
} }

View File

@ -37,9 +37,9 @@
/* Declared in afl-qemu-cpu-inl.h */ /* Declared in afl-qemu-cpu-inl.h */
extern unsigned char *afl_area_ptr; extern unsigned char *afl_area_ptr;
extern unsigned int afl_inst_rms; extern unsigned int afl_inst_rms;
extern abi_ulong afl_start_code, afl_end_code; extern abi_ulong afl_start_code, afl_end_code;
extern u8 afl_compcov_level; extern u8 afl_compcov_level;
void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc, void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc,
TCGv_i64 arg1, TCGv_i64 arg2); TCGv_i64 arg1, TCGv_i64 arg2);
@ -47,81 +47,93 @@ void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc,
static void afl_compcov_log_16(target_ulong cur_loc, target_ulong arg1, static void afl_compcov_log_16(target_ulong cur_loc, target_ulong arg1,
target_ulong arg2) { target_ulong arg2) {
if ((arg1 & 0xff) == (arg2 & 0xff)) { if ((arg1 & 0xff) == (arg2 & 0xff)) { INC_AFL_AREA(cur_loc); }
INC_AFL_AREA(cur_loc);
}
} }
static void afl_compcov_log_32(target_ulong cur_loc, target_ulong arg1, static void afl_compcov_log_32(target_ulong cur_loc, target_ulong arg1,
target_ulong arg2) { target_ulong arg2) {
if ((arg1 & 0xff) == (arg2 & 0xff)) { if ((arg1 & 0xff) == (arg2 & 0xff)) {
INC_AFL_AREA(cur_loc); INC_AFL_AREA(cur_loc);
if ((arg1 & 0xffff) == (arg2 & 0xffff)) { if ((arg1 & 0xffff) == (arg2 & 0xffff)) {
INC_AFL_AREA(cur_loc +1);
if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { INC_AFL_AREA(cur_loc + 1);
INC_AFL_AREA(cur_loc +2); if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { INC_AFL_AREA(cur_loc + 2); }
}
} }
} }
} }
static void afl_compcov_log_64(target_ulong cur_loc, target_ulong arg1, static void afl_compcov_log_64(target_ulong cur_loc, target_ulong arg1,
target_ulong arg2) { target_ulong arg2) {
if ((arg1 & 0xff) == (arg2 & 0xff)) { if ((arg1 & 0xff) == (arg2 & 0xff)) {
INC_AFL_AREA(cur_loc); INC_AFL_AREA(cur_loc);
if ((arg1 & 0xffff) == (arg2 & 0xffff)) { if ((arg1 & 0xffff) == (arg2 & 0xffff)) {
INC_AFL_AREA(cur_loc +1);
if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) {
INC_AFL_AREA(cur_loc +2);
if ((arg1 & 0xffffffff) == (arg2 & 0xffffffff)) {
INC_AFL_AREA(cur_loc +3);
if ((arg1 & 0xffffffffff) == (arg2 & 0xffffffffff)) {
INC_AFL_AREA(cur_loc +4);
if ((arg1 & 0xffffffffffff) == (arg2 & 0xffffffffffff)) {
INC_AFL_AREA(cur_loc +5);
if ((arg1 & 0xffffffffffffff) == (arg2 & 0xffffffffffffff)) {
INC_AFL_AREA(cur_loc +6);
}
}
}
}
}
}
}
}
INC_AFL_AREA(cur_loc + 1);
if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) {
INC_AFL_AREA(cur_loc + 2);
if ((arg1 & 0xffffffff) == (arg2 & 0xffffffff)) {
INC_AFL_AREA(cur_loc + 3);
if ((arg1 & 0xffffffffff) == (arg2 & 0xffffffffff)) {
INC_AFL_AREA(cur_loc + 4);
if ((arg1 & 0xffffffffffff) == (arg2 & 0xffffffffffff)) {
INC_AFL_AREA(cur_loc + 5);
if ((arg1 & 0xffffffffffffff) == (arg2 & 0xffffffffffffff)) {
INC_AFL_AREA(cur_loc + 6);
}
}
}
}
}
}
}
}
static void afl_gen_compcov(target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2, static void afl_gen_compcov(target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2,
TCGMemOp ot, int is_imm) { TCGMemOp ot, int is_imm) {
void *func; void *func;
if (!afl_compcov_level || cur_loc > afl_end_code || cur_loc < afl_start_code) if (!afl_compcov_level || cur_loc > afl_end_code || cur_loc < afl_start_code)
return; return;
if (!is_imm && afl_compcov_level < 2) if (!is_imm && afl_compcov_level < 2) return;
return;
switch (ot) { switch (ot) {
case MO_64:
func = &afl_compcov_log_64; case MO_64: func = &afl_compcov_log_64; break;
break; case MO_32: func = &afl_compcov_log_32; break;
case MO_32: case MO_16: func = &afl_compcov_log_16; break;
func = &afl_compcov_log_32; default: return;
break;
case MO_16:
func = &afl_compcov_log_16;
break;
default:
return;
} }
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 7; cur_loc &= MAP_SIZE - 7;
if (cur_loc >= afl_inst_rms) return; if (cur_loc >= afl_inst_rms) return;
tcg_gen_afl_compcov_log_call(func, cur_loc, arg1, arg2); tcg_gen_afl_compcov_log_call(func, cur_loc, arg1, arg2);
} }

View File

@ -31,275 +31,343 @@
*/ */
void afl_maybe_log(void* cur_loc); void afl_maybe_log(void *cur_loc);
/* Note: we convert the 64 bit args to 32 bit and do some alignment /* Note: we convert the 64 bit args to 32 bit and do some alignment
and endian swap. Maybe it would be better to do the alignment and endian swap. Maybe it would be better to do the alignment
and endian swap in tcg_reg_alloc_call(). */ and endian swap in tcg_reg_alloc_call(). */
void tcg_gen_afl_maybe_log_call(target_ulong cur_loc) void tcg_gen_afl_maybe_log_call(target_ulong cur_loc) {
{
int real_args, pi;
unsigned sizemask, flags;
TCGOp *op;
TCGTemp *arg = tcgv_i64_temp( tcg_const_tl(cur_loc) ); int real_args, pi;
unsigned sizemask, flags;
TCGOp * op;
flags = 0; TCGTemp *arg = tcgv_i64_temp(tcg_const_tl(cur_loc));
sizemask = dh_sizemask(void, 0) | dh_sizemask(i64, 1);
#if defined(__sparc__) && !defined(__arch64__) \ flags = 0;
&& !defined(CONFIG_TCG_INTERPRETER) sizemask = dh_sizemask(void, 0) | dh_sizemask(i64, 1);
/* We have 64-bit values in one register, but need to pass as two
separate parameters. Split them. */
int orig_sizemask = sizemask;
TCGv_i64 retl, reth;
TCGTemp *split_args[MAX_OPC_PARAM];
retl = NULL; #if defined(__sparc__) && !defined(__arch64__) && \
reth = NULL; !defined(CONFIG_TCG_INTERPRETER)
if (sizemask != 0) { /* We have 64-bit values in one register, but need to pass as two
real_args = 0; separate parameters. Split them. */
int is_64bit = sizemask & (1 << 2); int orig_sizemask = sizemask;
if (is_64bit) { TCGv_i64 retl, reth;
TCGv_i64 orig = temp_tcgv_i64(arg); TCGTemp *split_args[MAX_OPC_PARAM];
TCGv_i32 h = tcg_temp_new_i32();
TCGv_i32 l = tcg_temp_new_i32();
tcg_gen_extr_i64_i32(l, h, orig);
split_args[real_args++] = tcgv_i32_temp(h);
split_args[real_args++] = tcgv_i32_temp(l);
} else {
split_args[real_args++] = arg;
}
nargs = real_args;
args = split_args;
sizemask = 0;
}
#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
int is_64bit = sizemask & (1 << 2);
int is_signed = sizemask & (2 << 2);
if (!is_64bit) {
TCGv_i64 temp = tcg_temp_new_i64();
TCGv_i64 orig = temp_tcgv_i64(arg);
if (is_signed) {
tcg_gen_ext32s_i64(temp, orig);
} else {
tcg_gen_ext32u_i64(temp, orig);
}
arg = tcgv_i64_temp(temp);
}
#endif /* TCG_TARGET_EXTEND_ARGS */
op = tcg_emit_op(INDEX_op_call); retl = NULL;
reth = NULL;
pi = 0; if (sizemask != 0) {
TCGOP_CALLO(op) = 0;
real_args = 0; real_args = 0;
int is_64bit = sizemask & (1 << 2); int is_64bit = sizemask & (1 << 2);
if (TCG_TARGET_REG_BITS < 64 && is_64bit) { if (is_64bit) {
#ifdef TCG_TARGET_CALL_ALIGN_ARGS
/* some targets want aligned 64 bit args */ TCGv_i64 orig = temp_tcgv_i64(arg);
if (real_args & 1) { TCGv_i32 h = tcg_temp_new_i32();
op->args[pi++] = TCG_CALL_DUMMY_ARG; TCGv_i32 l = tcg_temp_new_i32();
real_args++; tcg_gen_extr_i64_i32(l, h, orig);
} split_args[real_args++] = tcgv_i32_temp(h);
#endif split_args[real_args++] = tcgv_i32_temp(l);
/* If stack grows up, then we will be placing successive
arguments at lower addresses, which means we need to } else {
reverse the order compared to how we would normally
treat either big or little-endian. For those arguments split_args[real_args++] = arg;
that will wind up in registers, this still works for
HPPA (the only current STACK_GROWSUP target) since the
argument registers are *also* allocated in decreasing
order. If another such target is added, this logic may
have to get more complicated to differentiate between
stack arguments and register arguments. */
#if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
op->args[pi++] = temp_arg(arg + 1);
op->args[pi++] = temp_arg(arg);
#else
op->args[pi++] = temp_arg(arg);
op->args[pi++] = temp_arg(arg + 1);
#endif
real_args += 2;
} }
nargs = real_args;
args = split_args;
sizemask = 0;
}
#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
int is_64bit = sizemask & (1 << 2);
int is_signed = sizemask & (2 << 2);
if (!is_64bit) {
TCGv_i64 temp = tcg_temp_new_i64();
TCGv_i64 orig = temp_tcgv_i64(arg);
if (is_signed) {
tcg_gen_ext32s_i64(temp, orig);
} else {
tcg_gen_ext32u_i64(temp, orig);
}
arg = tcgv_i64_temp(temp);
}
#endif /* TCG_TARGET_EXTEND_ARGS */
op = tcg_emit_op(INDEX_op_call);
pi = 0;
TCGOP_CALLO(op) = 0;
real_args = 0;
int is_64bit = sizemask & (1 << 2);
if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
#ifdef TCG_TARGET_CALL_ALIGN_ARGS
/* some targets want aligned 64 bit args */
if (real_args & 1) {
op->args[pi++] = TCG_CALL_DUMMY_ARG;
real_args++;
}
#endif
/* If stack grows up, then we will be placing successive
arguments at lower addresses, which means we need to
reverse the order compared to how we would normally
treat either big or little-endian. For those arguments
that will wind up in registers, this still works for
HPPA (the only current STACK_GROWSUP target) since the
argument registers are *also* allocated in decreasing
order. If another such target is added, this logic may
have to get more complicated to differentiate between
stack arguments and register arguments. */
#if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
op->args[pi++] = temp_arg(arg + 1);
op->args[pi++] = temp_arg(arg); op->args[pi++] = temp_arg(arg);
#else
op->args[pi++] = temp_arg(arg);
op->args[pi++] = temp_arg(arg + 1);
#endif
real_args += 2;
}
op->args[pi++] = temp_arg(arg);
real_args++;
op->args[pi++] = (uintptr_t)&afl_maybe_log;
op->args[pi++] = flags;
TCGOP_CALLI(op) = real_args;
/* Make sure the fields didn't overflow. */
tcg_debug_assert(TCGOP_CALLI(op) == real_args);
tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
#if defined(__sparc__) && !defined(__arch64__) && \
!defined(CONFIG_TCG_INTERPRETER)
/* Free all of the parts we allocated above. */
real_args = 0;
int is_64bit = orig_sizemask & (1 << 2);
if (is_64bit) {
tcg_temp_free_internal(args[real_args++]);
tcg_temp_free_internal(args[real_args++]);
} else {
real_args++; real_args++;
op->args[pi++] = (uintptr_t)&afl_maybe_log; }
op->args[pi++] = flags;
TCGOP_CALLI(op) = real_args;
/* Make sure the fields didn't overflow. */ if (orig_sizemask & 1) {
tcg_debug_assert(TCGOP_CALLI(op) == real_args);
tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); /* The 32-bit ABI returned two 32-bit pieces. Re-assemble them.
Note that describing these as TCGv_i64 eliminates an unnecessary
zero-extension that tcg_gen_concat_i32_i64 would create. */
tcg_gen_concat32_i64(temp_tcgv_i64(NULL), retl, reth);
tcg_temp_free_i64(retl);
tcg_temp_free_i64(reth);
}
#if defined(__sparc__) && !defined(__arch64__) \
&& !defined(CONFIG_TCG_INTERPRETER)
/* Free all of the parts we allocated above. */
real_args = 0;
int is_64bit = orig_sizemask & (1 << 2);
if (is_64bit) {
tcg_temp_free_internal(args[real_args++]);
tcg_temp_free_internal(args[real_args++]);
} else {
real_args++;
}
if (orig_sizemask & 1) {
/* The 32-bit ABI returned two 32-bit pieces. Re-assemble them.
Note that describing these as TCGv_i64 eliminates an unnecessary
zero-extension that tcg_gen_concat_i32_i64 would create. */
tcg_gen_concat32_i64(temp_tcgv_i64(NULL), retl, reth);
tcg_temp_free_i64(retl);
tcg_temp_free_i64(reth);
}
#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
int is_64bit = sizemask & (1 << 2); int is_64bit = sizemask & (1 << 2);
if (!is_64bit) { tcg_temp_free_internal(arg); }
#endif /* TCG_TARGET_EXTEND_ARGS */
}
void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc,
TCGv_i64 arg1, TCGv_i64 arg2) {
int i, real_args, nb_rets, pi;
unsigned sizemask, flags;
TCGOp * op;
const int nargs = 3;
TCGTemp *args[3] = {tcgv_i64_temp(tcg_const_tl(cur_loc)), tcgv_i64_temp(arg1),
tcgv_i64_temp(arg2)};
flags = 0;
sizemask = dh_sizemask(void, 0) | dh_sizemask(i64, 1) | dh_sizemask(i64, 2) |
dh_sizemask(i64, 3);
#if defined(__sparc__) && !defined(__arch64__) && \
!defined(CONFIG_TCG_INTERPRETER)
/* We have 64-bit values in one register, but need to pass as two
separate parameters. Split them. */
int orig_sizemask = sizemask;
int orig_nargs = nargs;
TCGv_i64 retl, reth;
TCGTemp *split_args[MAX_OPC_PARAM];
retl = NULL;
reth = NULL;
if (sizemask != 0) {
for (i = real_args = 0; i < nargs; ++i) {
int is_64bit = sizemask & (1 << (i + 1) * 2);
if (is_64bit) {
TCGv_i64 orig = temp_tcgv_i64(args[i]);
TCGv_i32 h = tcg_temp_new_i32();
TCGv_i32 l = tcg_temp_new_i32();
tcg_gen_extr_i64_i32(l, h, orig);
split_args[real_args++] = tcgv_i32_temp(h);
split_args[real_args++] = tcgv_i32_temp(l);
} else {
split_args[real_args++] = args[i];
}
}
nargs = real_args;
args = split_args;
sizemask = 0;
}
#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
for (i = 0; i < nargs; ++i) {
int is_64bit = sizemask & (1 << (i + 1) * 2);
int is_signed = sizemask & (2 << (i + 1) * 2);
if (!is_64bit) { if (!is_64bit) {
tcg_temp_free_internal(arg);
TCGv_i64 temp = tcg_temp_new_i64();
TCGv_i64 orig = temp_tcgv_i64(args[i]);
if (is_signed) {
tcg_gen_ext32s_i64(temp, orig);
} else {
tcg_gen_ext32u_i64(temp, orig);
}
args[i] = tcgv_i64_temp(temp);
} }
#endif /* TCG_TARGET_EXTEND_ARGS */
}
void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2) }
{
int i, real_args, nb_rets, pi;
unsigned sizemask, flags;
TCGOp *op;
const int nargs = 3;
TCGTemp *args[3] = { tcgv_i64_temp( tcg_const_tl(cur_loc) ),
tcgv_i64_temp(arg1),
tcgv_i64_temp(arg2) };
flags = 0;
sizemask = dh_sizemask(void, 0) | dh_sizemask(i64, 1) |
dh_sizemask(i64, 2) | dh_sizemask(i64, 3);
#if defined(__sparc__) && !defined(__arch64__) \
&& !defined(CONFIG_TCG_INTERPRETER)
/* We have 64-bit values in one register, but need to pass as two
separate parameters. Split them. */
int orig_sizemask = sizemask;
int orig_nargs = nargs;
TCGv_i64 retl, reth;
TCGTemp *split_args[MAX_OPC_PARAM];
retl = NULL;
reth = NULL;
if (sizemask != 0) {
for (i = real_args = 0; i < nargs; ++i) {
int is_64bit = sizemask & (1 << (i+1)*2);
if (is_64bit) {
TCGv_i64 orig = temp_tcgv_i64(args[i]);
TCGv_i32 h = tcg_temp_new_i32();
TCGv_i32 l = tcg_temp_new_i32();
tcg_gen_extr_i64_i32(l, h, orig);
split_args[real_args++] = tcgv_i32_temp(h);
split_args[real_args++] = tcgv_i32_temp(l);
} else {
split_args[real_args++] = args[i];
}
}
nargs = real_args;
args = split_args;
sizemask = 0;
}
#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
for (i = 0; i < nargs; ++i) {
int is_64bit = sizemask & (1 << (i+1)*2);
int is_signed = sizemask & (2 << (i+1)*2);
if (!is_64bit) {
TCGv_i64 temp = tcg_temp_new_i64();
TCGv_i64 orig = temp_tcgv_i64(args[i]);
if (is_signed) {
tcg_gen_ext32s_i64(temp, orig);
} else {
tcg_gen_ext32u_i64(temp, orig);
}
args[i] = tcgv_i64_temp(temp);
}
}
#endif /* TCG_TARGET_EXTEND_ARGS */ #endif /* TCG_TARGET_EXTEND_ARGS */
op = tcg_emit_op(INDEX_op_call); op = tcg_emit_op(INDEX_op_call);
pi = 0; pi = 0;
nb_rets = 0; nb_rets = 0;
TCGOP_CALLO(op) = nb_rets; TCGOP_CALLO(op) = nb_rets;
real_args = 0;
for (i = 0; i < nargs; i++) {
int is_64bit = sizemask & (1 << (i + 1) * 2);
if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
real_args = 0;
for (i = 0; i < nargs; i++) {
int is_64bit = sizemask & (1 << (i+1)*2);
if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
#ifdef TCG_TARGET_CALL_ALIGN_ARGS #ifdef TCG_TARGET_CALL_ALIGN_ARGS
/* some targets want aligned 64 bit args */ /* some targets want aligned 64 bit args */
if (real_args & 1) { if (real_args & 1) {
op->args[pi++] = TCG_CALL_DUMMY_ARG;
real_args++;
}
#endif
/* If stack grows up, then we will be placing successive
arguments at lower addresses, which means we need to
reverse the order compared to how we would normally
treat either big or little-endian. For those arguments
that will wind up in registers, this still works for
HPPA (the only current STACK_GROWSUP target) since the
argument registers are *also* allocated in decreasing
order. If another such target is added, this logic may
have to get more complicated to differentiate between
stack arguments and register arguments. */
#if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
op->args[pi++] = temp_arg(args[i] + 1);
op->args[pi++] = temp_arg(args[i]);
#else
op->args[pi++] = temp_arg(args[i]);
op->args[pi++] = temp_arg(args[i] + 1);
#endif
real_args += 2;
continue;
}
op->args[pi++] = temp_arg(args[i]); op->args[pi++] = TCG_CALL_DUMMY_ARG;
real_args++; real_args++;
}
op->args[pi++] = (uintptr_t)func;
op->args[pi++] = flags;
TCGOP_CALLI(op) = real_args;
/* Make sure the fields didn't overflow. */ }
tcg_debug_assert(TCGOP_CALLI(op) == real_args);
tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); #endif
/* If stack grows up, then we will be placing successive
arguments at lower addresses, which means we need to
reverse the order compared to how we would normally
treat either big or little-endian. For those arguments
that will wind up in registers, this still works for
HPPA (the only current STACK_GROWSUP target) since the
argument registers are *also* allocated in decreasing
order. If another such target is added, this logic may
have to get more complicated to differentiate between
stack arguments and register arguments. */
#if defined(HOST_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP)
op->args[pi++] = temp_arg(args[i] + 1);
op->args[pi++] = temp_arg(args[i]);
#else
op->args[pi++] = temp_arg(args[i]);
op->args[pi++] = temp_arg(args[i] + 1);
#endif
real_args += 2;
continue;
#if defined(__sparc__) && !defined(__arch64__) \
&& !defined(CONFIG_TCG_INTERPRETER)
/* Free all of the parts we allocated above. */
for (i = real_args = 0; i < orig_nargs; ++i) {
int is_64bit = orig_sizemask & (1 << (i+1)*2);
if (is_64bit) {
tcg_temp_free_internal(args[real_args++]);
tcg_temp_free_internal(args[real_args++]);
} else {
real_args++;
}
} }
if (orig_sizemask & 1) {
/* The 32-bit ABI returned two 32-bit pieces. Re-assemble them. op->args[pi++] = temp_arg(args[i]);
Note that describing these as TCGv_i64 eliminates an unnecessary real_args++;
zero-extension that tcg_gen_concat_i32_i64 would create. */
tcg_gen_concat32_i64(temp_tcgv_i64(NULL), retl, reth); }
tcg_temp_free_i64(retl);
tcg_temp_free_i64(reth); op->args[pi++] = (uintptr_t)func;
op->args[pi++] = flags;
TCGOP_CALLI(op) = real_args;
/* Make sure the fields didn't overflow. */
tcg_debug_assert(TCGOP_CALLI(op) == real_args);
tcg_debug_assert(pi <= ARRAY_SIZE(op->args));
#if defined(__sparc__) && !defined(__arch64__) && \
!defined(CONFIG_TCG_INTERPRETER)
/* Free all of the parts we allocated above. */
for (i = real_args = 0; i < orig_nargs; ++i) {
int is_64bit = orig_sizemask & (1 << (i + 1) * 2);
if (is_64bit) {
tcg_temp_free_internal(args[real_args++]);
tcg_temp_free_internal(args[real_args++]);
} else {
real_args++;
} }
}
if (orig_sizemask & 1) {
/* The 32-bit ABI returned two 32-bit pieces. Re-assemble them.
Note that describing these as TCGv_i64 eliminates an unnecessary
zero-extension that tcg_gen_concat_i32_i64 would create. */
tcg_gen_concat32_i64(temp_tcgv_i64(NULL), retl, reth);
tcg_temp_free_i64(retl);
tcg_temp_free_i64(reth);
}
#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 #elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
for (i = 0; i < nargs; ++i) { for (i = 0; i < nargs; ++i) {
int is_64bit = sizemask & (1 << (i+1)*2);
if (!is_64bit) { int is_64bit = sizemask & (1 << (i + 1) * 2);
tcg_temp_free_internal(args[i]); if (!is_64bit) { tcg_temp_free_internal(args[i]); }
}
} }
#endif /* TCG_TARGET_EXTEND_ARGS */ #endif /* TCG_TARGET_EXTEND_ARGS */
} }

View File

@ -36,8 +36,8 @@
/* Declared in afl-qemu-cpu-inl.h */ /* Declared in afl-qemu-cpu-inl.h */
extern unsigned char *afl_area_ptr; extern unsigned char *afl_area_ptr;
extern unsigned int afl_inst_rms; extern unsigned int afl_inst_rms;
extern abi_ulong afl_start_code, afl_end_code; extern abi_ulong afl_start_code, afl_end_code;
void tcg_gen_afl_maybe_log_call(target_ulong cur_loc); void tcg_gen_afl_maybe_log_call(target_ulong cur_loc);
@ -59,14 +59,16 @@ static void afl_gen_trace(target_ulong cur_loc) {
/* Optimize for cur_loc > afl_end_code, which is the most likely case on /* Optimize for cur_loc > afl_end_code, which is the most likely case on
Linux systems. */ Linux systems. */
if (cur_loc > afl_end_code || cur_loc < afl_start_code /*|| !afl_area_ptr*/) // not needed because of static dummy buffer if (cur_loc > afl_end_code ||
cur_loc < afl_start_code /*|| !afl_area_ptr*/) // not needed because of
// static dummy buffer
return; return;
/* Looks like QEMU always maps to fixed locations, so ASLR is not a /* Looks like QEMU always maps to fixed locations, so ASLR is not a
concern. Phew. But instruction addresses may be aligned. Let's mangle concern. Phew. But instruction addresses may be aligned. Let's mangle
the value to get something quasi-uniform. */ the value to get something quasi-uniform. */
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 1; cur_loc &= MAP_SIZE - 1;
/* Implement probabilistic instrumentation by looking at scrambled block /* Implement probabilistic instrumentation by looking at scrambled block
@ -75,5 +77,6 @@ static void afl_gen_trace(target_ulong cur_loc) {
if (cur_loc >= afl_inst_rms) return; if (cur_loc >= afl_inst_rms) return;
tcg_gen_afl_maybe_log_call(cur_loc); tcg_gen_afl_maybe_log_call(cur_loc);
} }

View File

@ -22,7 +22,7 @@
#define AFL_MAIN #define AFL_MAIN
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "android-ashmem.h" # include "android-ashmem.h"
#endif #endif
#include "config.h" #include "config.h"
#include "types.h" #include "types.h"
@ -50,61 +50,59 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/resource.h> #include <sys/resource.h>
static s32 child_pid; /* PID of the tested program */ static s32 child_pid; /* PID of the tested program */
u8* trace_bits; /* SHM with instrumentation bitmap */ u8* trace_bits; /* SHM with instrumentation bitmap */
static u8 *in_file, /* Analyzer input test case */ static u8 *in_file, /* Analyzer input test case */
*prog_in, /* Targeted program input file */ *prog_in, /* Targeted program input file */
*target_path, /* Path to target binary */ *target_path, /* Path to target binary */
*doc_path; /* Path to docs */ *doc_path; /* Path to docs */
static u8 *in_data; /* Input data for analysis */ static u8* in_data; /* Input data for analysis */
static u32 in_len, /* Input data length */ static u32 in_len, /* Input data length */
orig_cksum, /* Original checksum */ orig_cksum, /* Original checksum */
total_execs, /* Total number of execs */ total_execs, /* Total number of execs */
exec_hangs, /* Total number of hangs */ exec_hangs, /* Total number of hangs */
exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */ exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */
static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
static s32 dev_null_fd = -1; /* FD to /dev/null */ static s32 dev_null_fd = -1; /* FD to /dev/null */
static u8 edges_only, /* Ignore hit counts? */ static u8 edges_only, /* Ignore hit counts? */
use_hex_offsets, /* Show hex offsets? */ use_hex_offsets, /* Show hex offsets? */
use_stdin = 1; /* Use stdin for program input? */ use_stdin = 1; /* Use stdin for program input? */
static volatile u8
stop_soon, /* Ctrl-C pressed? */
child_timed_out; /* Child timed out? */
static volatile u8 stop_soon, /* Ctrl-C pressed? */
child_timed_out; /* Child timed out? */
/* Constants used for describing byte behavior. */ /* Constants used for describing byte behavior. */
#define RESP_NONE 0x00 /* Changing byte is a no-op. */ #define RESP_NONE 0x00 /* Changing byte is a no-op. */
#define RESP_MINOR 0x01 /* Some changes have no effect. */ #define RESP_MINOR 0x01 /* Some changes have no effect. */
#define RESP_VARIABLE 0x02 /* Changes produce variable paths. */ #define RESP_VARIABLE 0x02 /* Changes produce variable paths. */
#define RESP_FIXED 0x03 /* Changes produce fixed patterns. */ #define RESP_FIXED 0x03 /* Changes produce fixed patterns. */
#define RESP_LEN 0x04 /* Potential length field */ #define RESP_LEN 0x04 /* Potential length field */
#define RESP_CKSUM 0x05 /* Potential checksum */ #define RESP_CKSUM 0x05 /* Potential checksum */
#define RESP_SUSPECT 0x06 /* Potential "suspect" blob */ #define RESP_SUSPECT 0x06 /* Potential "suspect" blob */
/* Classify tuple counts. This is a slow & naive version, but good enough here.
/* Classify tuple counts. This is a slow & naive version, but good enough here. */ */
static u8 count_class_lookup[256] = { static u8 count_class_lookup[256] = {
[0] = 0, [0] = 0,
[1] = 1, [1] = 1,
[2] = 2, [2] = 2,
[3] = 4, [3] = 4,
[4 ... 7] = 8, [4 ... 7] = 8,
[8 ... 15] = 16, [8 ... 15] = 16,
[16 ... 31] = 32, [16 ... 31] = 32,
[32 ... 127] = 64, [32 ... 127] = 64,
[128 ... 255] = 128 [128 ... 255] = 128
}; };
@ -115,61 +113,62 @@ static void classify_counts(u8* mem) {
if (edges_only) { if (edges_only) {
while (i--) { while (i--) {
if (*mem) *mem = 1; if (*mem) *mem = 1;
mem++; mem++;
} }
} else { } else {
while (i--) { while (i--) {
*mem = count_class_lookup[*mem]; *mem = count_class_lookup[*mem];
mem++; mem++;
} }
} }
} }
/* See if any bytes are set in the bitmap. */ /* See if any bytes are set in the bitmap. */
static inline u8 anything_set(void) { static inline u8 anything_set(void) {
u32* ptr = (u32*)trace_bits; u32* ptr = (u32*)trace_bits;
u32 i = (MAP_SIZE >> 2); u32 i = (MAP_SIZE >> 2);
while (i--) if (*(ptr++)) return 1; while (i--)
if (*(ptr++)) return 1;
return 0; return 0;
} }
/* Get rid of temp files (atexit handler). */ /* Get rid of temp files (atexit handler). */
static void at_exit_handler(void) { static void at_exit_handler(void) {
unlink(prog_in); /* Ignore errors */ unlink(prog_in); /* Ignore errors */
} }
/* Read initial file. */ /* Read initial file. */
static void read_initial_file(void) { static void read_initial_file(void) {
struct stat st; struct stat st;
s32 fd = open(in_file, O_RDONLY); s32 fd = open(in_file, O_RDONLY);
if (fd < 0) PFATAL("Unable to open '%s'", in_file); if (fd < 0) PFATAL("Unable to open '%s'", in_file);
if (fstat(fd, &st) || !st.st_size) if (fstat(fd, &st) || !st.st_size) FATAL("Zero-sized input file.");
FATAL("Zero-sized input file.");
if (st.st_size >= TMIN_MAX_FILE) if (st.st_size >= TMIN_MAX_FILE)
FATAL("Input file is too large (%u MB max)", TMIN_MAX_FILE / 1024 / 1024); FATAL("Input file is too large (%u MB max)", TMIN_MAX_FILE / 1024 / 1024);
in_len = st.st_size; in_len = st.st_size;
in_data = ck_alloc_nozero(in_len); in_data = ck_alloc_nozero(in_len);
ck_read(fd, in_data, in_len, in_file); ck_read(fd, in_data, in_len, in_file);
@ -180,14 +179,13 @@ static void read_initial_file(void) {
} }
/* Write output file. */ /* Write output file. */
static s32 write_to_file(u8* path, u8* mem, u32 len) { static s32 write_to_file(u8* path, u8* mem, u32 len) {
s32 ret; s32 ret;
unlink(path); /* Ignore errors */ unlink(path); /* Ignore errors */
ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600); ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
@ -201,7 +199,6 @@ static s32 write_to_file(u8* path, u8* mem, u32 len) {
} }
/* Handle timeout signal. */ /* Handle timeout signal. */
static void handle_timeout(int sig) { static void handle_timeout(int sig) {
@ -211,14 +208,13 @@ static void handle_timeout(int sig) {
} }
/* Execute target application. Returns exec checksum, or 0 if program /* Execute target application. Returns exec checksum, or 0 if program
times out. */ times out. */
static u32 run_target(char** argv, u8* mem, u32 len, u8 first_run) { static u32 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
static struct itimerval it; static struct itimerval it;
int status = 0; int status = 0;
s32 prog_in_fd; s32 prog_in_fd;
u32 cksum; u32 cksum;
@ -237,8 +233,7 @@ static u32 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
struct rlimit r; struct rlimit r;
if (dup2(use_stdin ? prog_in_fd : dev_null_fd, 0) < 0 || if (dup2(use_stdin ? prog_in_fd : dev_null_fd, 0) < 0 ||
dup2(dev_null_fd, 1) < 0 || dup2(dev_null_fd, 1) < 0 || dup2(dev_null_fd, 2) < 0) {
dup2(dev_null_fd, 2) < 0) {
*(u32*)trace_bits = EXEC_FAIL_SIG; *(u32*)trace_bits = EXEC_FAIL_SIG;
PFATAL("dup2() failed"); PFATAL("dup2() failed");
@ -254,18 +249,18 @@ static u32 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
#ifdef RLIMIT_AS #ifdef RLIMIT_AS
setrlimit(RLIMIT_AS, &r); /* Ignore errors */ setrlimit(RLIMIT_AS, &r); /* Ignore errors */
#else #else
setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
#endif /* ^RLIMIT_AS */ #endif /* ^RLIMIT_AS */
} }
r.rlim_max = r.rlim_cur = 0; r.rlim_max = r.rlim_cur = 0;
setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
execv(target_path, argv); execv(target_path, argv);
@ -303,8 +298,10 @@ static u32 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
total_execs++; total_execs++;
if (stop_soon) { if (stop_soon) {
SAYF(cRST cLRD "\n+++ Analysis aborted by user +++\n" cRST); SAYF(cRST cLRD "\n+++ Analysis aborted by user +++\n" cRST);
exit(1); exit(1);
} }
/* Always discard inputs that time out. */ /* Always discard inputs that time out. */
@ -335,7 +332,6 @@ static u32 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
} }
#ifdef USE_COLOR #ifdef USE_COLOR
/* Helper function to display a human-readable character. */ /* Helper function to display a human-readable character. */
@ -353,24 +349,25 @@ static void show_char(u8 val) {
} }
/* Show the legend */ /* Show the legend */
static void show_legend(void) { static void show_legend(void) {
SAYF(" " cLGR bgGRA " 01 " cRST " - no-op block " SAYF(" " cLGR bgGRA " 01 " cRST " - no-op block " cBLK bgLGN
cBLK bgLGN " 01 " cRST " - suspected length field\n" " 01 " cRST
" " cBRI bgGRA " 01 " cRST " - superficial content " " - suspected length field\n"
cBLK bgYEL " 01 " cRST " - suspected cksum or magic int\n" " " cBRI bgGRA " 01 " cRST " - superficial content " cBLK bgYEL
" " cBLK bgCYA " 01 " cRST " - critical stream " " 01 " cRST
cBLK bgLRD " 01 " cRST " - suspected checksummed block\n" " - suspected cksum or magic int\n"
" " cBLK bgCYA " 01 " cRST " - critical stream " cBLK bgLRD
" 01 " cRST
" - suspected checksummed block\n"
" " cBLK bgMGN " 01 " cRST " - \"magic value\" section\n\n"); " " cBLK bgMGN " 01 " cRST " - \"magic value\" section\n\n");
} }
#endif /* USE_COLOR */ #endif /* USE_COLOR */
/* Interpret and report a pattern in the input file. */ /* Interpret and report a pattern in the input file. */
static void dump_hex(u8* buf, u32 len, u8* b_data) { static void dump_hex(u8* buf, u32 len, u8* b_data) {
@ -385,7 +382,7 @@ static void dump_hex(u8* buf, u32 len, u8* b_data) {
u32 rlen = 1; u32 rlen = 1;
#endif /* ^USE_COLOR */ #endif /* ^USE_COLOR */
u8 rtype = b_data[i] & 0x0f; u8 rtype = b_data[i] & 0x0f;
/* Look ahead to determine the length of run. */ /* Look ahead to determine the length of run. */
@ -404,51 +401,61 @@ static void dump_hex(u8* buf, u32 len, u8* b_data) {
case 2: { case 2: {
u16 val = *(u16*)(in_data + i); u16 val = *(u16*)(in_data + i);
/* Small integers may be length fields. */ /* Small integers may be length fields. */
if (val && (val <= in_len || SWAP16(val) <= in_len)) { if (val && (val <= in_len || SWAP16(val) <= in_len)) {
rtype = RESP_LEN;
break;
}
/* Uniform integers may be checksums. */
if (val && abs(in_data[i] - in_data[i + 1]) > 32) {
rtype = RESP_CKSUM;
break;
}
rtype = RESP_LEN;
break; break;
} }
/* Uniform integers may be checksums. */
if (val && abs(in_data[i] - in_data[i + 1]) > 32) {
rtype = RESP_CKSUM;
break;
}
break;
}
case 4: { case 4: {
u32 val = *(u32*)(in_data + i); u32 val = *(u32*)(in_data + i);
/* Small integers may be length fields. */ /* Small integers may be length fields. */
if (val && (val <= in_len || SWAP32(val) <= in_len)) { if (val && (val <= in_len || SWAP32(val) <= in_len)) {
rtype = RESP_LEN;
break;
}
/* Uniform integers may be checksums. */
if (val && (in_data[i] >> 7 != in_data[i + 1] >> 7 ||
in_data[i] >> 7 != in_data[i + 2] >> 7 ||
in_data[i] >> 7 != in_data[i + 3] >> 7)) {
rtype = RESP_CKSUM;
break;
}
rtype = RESP_LEN;
break; break;
} }
case 1: case 3: case 5 ... MAX_AUTO_EXTRA - 1: break; /* Uniform integers may be checksums. */
if (val && (in_data[i] >> 7 != in_data[i + 1] >> 7 ||
in_data[i] >> 7 != in_data[i + 2] >> 7 ||
in_data[i] >> 7 != in_data[i + 3] >> 7)) {
rtype = RESP_CKSUM;
break;
}
break;
}
case 1:
case 3:
case 5 ... MAX_AUTO_EXTRA - 1: break;
default: rtype = RESP_SUSPECT; default: rtype = RESP_SUSPECT;
@ -477,19 +484,22 @@ static void dump_hex(u8* buf, u32 len, u8* b_data) {
switch (rtype) { switch (rtype) {
case RESP_NONE: SAYF(cLGR bgGRA); break; case RESP_NONE: SAYF(cLGR bgGRA); break;
case RESP_MINOR: SAYF(cBRI bgGRA); break; case RESP_MINOR: SAYF(cBRI bgGRA); break;
case RESP_VARIABLE: SAYF(cBLK bgCYA); break; case RESP_VARIABLE: SAYF(cBLK bgCYA); break;
case RESP_FIXED: SAYF(cBLK bgMGN); break; case RESP_FIXED: SAYF(cBLK bgMGN); break;
case RESP_LEN: SAYF(cBLK bgLGN); break; case RESP_LEN: SAYF(cBLK bgLGN); break;
case RESP_CKSUM: SAYF(cBLK bgYEL); break; case RESP_CKSUM: SAYF(cBLK bgYEL); break;
case RESP_SUSPECT: SAYF(cBLK bgLRD); break; case RESP_SUSPECT: SAYF(cBLK bgLRD); break;
} }
show_char(in_data[i + off]); show_char(in_data[i + off]);
if (off != rlen - 1 && (i + off + 1) % 16) SAYF(" "); else SAYF(cRST " "); if (off != rlen - 1 && (i + off + 1) % 16)
SAYF(" ");
else
SAYF(cRST " ");
} }
@ -502,13 +512,13 @@ static void dump_hex(u8* buf, u32 len, u8* b_data) {
switch (rtype) { switch (rtype) {
case RESP_NONE: SAYF("no-op block\n"); break; case RESP_NONE: SAYF("no-op block\n"); break;
case RESP_MINOR: SAYF("superficial content\n"); break; case RESP_MINOR: SAYF("superficial content\n"); break;
case RESP_VARIABLE: SAYF("critical stream\n"); break; case RESP_VARIABLE: SAYF("critical stream\n"); break;
case RESP_FIXED: SAYF("\"magic value\" section\n"); break; case RESP_FIXED: SAYF("\"magic value\" section\n"); break;
case RESP_LEN: SAYF("suspected length field\n"); break; case RESP_LEN: SAYF("suspected length field\n"); break;
case RESP_CKSUM: SAYF("suspected cksum or magic int\n"); break; case RESP_CKSUM: SAYF("suspected cksum or magic int\n"); break;
case RESP_SUSPECT: SAYF("suspected checksummed block\n"); break; case RESP_SUSPECT: SAYF("suspected checksummed block\n"); break;
} }
@ -524,8 +534,6 @@ static void dump_hex(u8* buf, u32 len, u8* b_data) {
} }
/* Actually analyze! */ /* Actually analyze! */
static void analyze(char** argv) { static void analyze(char** argv) {
@ -536,7 +544,7 @@ static void analyze(char** argv) {
u8* b_data = ck_alloc(in_len + 1); u8* b_data = ck_alloc(in_len + 1);
u8 seq_byte = 0; u8 seq_byte = 0;
b_data[in_len] = 0xff; /* Intentional terminator. */ b_data[in_len] = 0xff; /* Intentional terminator. */
ACTF("Analyzing input file (this may take a while)...\n"); ACTF("Analyzing input file (this may take a while)...\n");
@ -587,12 +595,15 @@ static void analyze(char** argv) {
b_data[i] = RESP_FIXED; b_data[i] = RESP_FIXED;
} else b_data[i] = RESP_VARIABLE; } else
b_data[i] = RESP_VARIABLE;
/* When all checksums change, flip most significant bit of b_data. */ /* When all checksums change, flip most significant bit of b_data. */
if (prev_xff != xor_ff && prev_x01 != xor_01 && if (prev_xff != xor_ff && prev_x01 != xor_01 && prev_s10 != sub_10 &&
prev_s10 != sub_10 && prev_a10 != add_10) seq_byte ^= 0x80; prev_a10 != add_10)
seq_byte ^= 0x80;
b_data[i] |= seq_byte; b_data[i] |= seq_byte;
@ -601,7 +612,7 @@ static void analyze(char** argv) {
prev_s10 = sub_10; prev_s10 = sub_10;
prev_a10 = add_10; prev_a10 = add_10;
} }
dump_hex(in_data, in_len, b_data); dump_hex(in_data, in_len, b_data);
@ -618,8 +629,6 @@ static void analyze(char** argv) {
} }
/* Handle Ctrl-C and the like. */ /* Handle Ctrl-C and the like. */
static void handle_stop_sig(int sig) { static void handle_stop_sig(int sig) {
@ -630,7 +639,6 @@ static void handle_stop_sig(int sig) {
} }
/* Do basic preparations - persistent fds, filenames, etc. */ /* Do basic preparations - persistent fds, filenames, etc. */
static void set_up_environment(void) { static void set_up_environment(void) {
@ -674,18 +682,20 @@ static void set_up_environment(void) {
if (x) { if (x) {
if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR)))
FATAL("Custom MSAN_OPTIONS set without exit_code=" FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
STRINGIFY(MSAN_ERROR) " - please fix!"); MSAN_ERROR) " - please fix!");
if (!strstr(x, "symbolize=0")) if (!strstr(x, "symbolize=0"))
FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
} }
setenv("ASAN_OPTIONS", "abort_on_error=1:" setenv("ASAN_OPTIONS",
"detect_leaks=0:" "abort_on_error=1:"
"symbolize=0:" "detect_leaks=0:"
"allocator_may_return_null=1", 0); "symbolize=0:"
"allocator_may_return_null=1",
0);
setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
"symbolize=0:" "symbolize=0:"
@ -694,21 +704,22 @@ static void set_up_environment(void) {
"msan_track_origins=0", 0); "msan_track_origins=0", 0);
if (getenv("AFL_PRELOAD")) { if (getenv("AFL_PRELOAD")) {
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
} }
} }
/* Setup signal handlers, duh. */ /* Setup signal handlers, duh. */
static void setup_signal_handlers(void) { static void setup_signal_handlers(void) {
struct sigaction sa; struct sigaction sa;
sa.sa_handler = NULL; sa.sa_handler = NULL;
sa.sa_flags = SA_RESTART; sa.sa_flags = SA_RESTART;
sa.sa_sigaction = NULL; sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
@ -727,43 +738,42 @@ static void setup_signal_handlers(void) {
} }
/* Display usage hints. */ /* Display usage hints. */
static void usage(u8* argv0) { static void usage(u8* argv0) {
SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" SAYF(
"\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
"Required parameters:\n\n" "Required parameters:\n\n"
" -i file - input test case to be analyzed by the tool\n" " -i file - input test case to be analyzed by the tool\n"
"Execution control settings:\n\n" "Execution control settings:\n\n"
" -f file - input file read by the tested program (stdin)\n" " -f file - input file read by the tested program (stdin)\n"
" -t msec - timeout for each run (%d ms)\n" " -t msec - timeout for each run (%d ms)\n"
" -m megs - memory limit for child process (%d MB)\n" " -m megs - memory limit for child process (%d MB)\n"
" -Q - use binary-only instrumentation (QEMU mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n"
" -U - use unicorn-based instrumentation (Unicorn mode)\n\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n\n"
"Analysis settings:\n\n" "Analysis settings:\n\n"
" -e - look for edge coverage only, ignore hit counts\n\n" " -e - look for edge coverage only, ignore hit counts\n\n"
"For additional tips, please consult %s/README.\n\n", "For additional tips, please consult %s/README.\n\n",
argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path); argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
exit(1); exit(1);
} }
/* Find binary. */ /* Find binary. */
static void find_binary(u8* fname) { static void find_binary(u8* fname) {
u8* env_path = 0; u8* env_path = 0;
struct stat st; struct stat st;
if (strchr(fname, '/') || !(env_path = getenv("PATH"))) { if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
@ -786,7 +796,9 @@ static void find_binary(u8* fname) {
memcpy(cur_elem, env_path, delim - env_path); memcpy(cur_elem, env_path, delim - env_path);
delim++; delim++;
} else cur_elem = ck_strdup(env_path); } else
cur_elem = ck_strdup(env_path);
env_path = delim; env_path = delim;
@ -798,7 +810,8 @@ static void find_binary(u8* fname) {
ck_free(cur_elem); ck_free(cur_elem);
if (!stat(target_path, &st) && S_ISREG(st.st_mode) && if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
(st.st_mode & 0111) && st.st_size >= 4) break; (st.st_mode & 0111) && st.st_size >= 4)
break;
ck_free(target_path); ck_free(target_path);
target_path = 0; target_path = 0;
@ -811,13 +824,12 @@ static void find_binary(u8* fname) {
} }
/* Fix up argv for QEMU. */ /* Fix up argv for QEMU. */
static char** get_qemu_argv(u8* own_loc, char** argv, int argc) { static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
u8 *tmp, *cp, *rsl, *own_copy; u8 * tmp, *cp, *rsl, *own_copy;
memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc); memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
@ -832,8 +844,7 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
cp = alloc_printf("%s/afl-qemu-trace", tmp); cp = alloc_printf("%s/afl-qemu-trace", tmp);
if (access(cp, X_OK)) if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
FATAL("Unable to find '%s'", tmp);
target_path = new_argv[0] = cp; target_path = new_argv[0] = cp;
return new_argv; return new_argv;
@ -857,7 +868,9 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
} }
} else ck_free(own_copy); } else
ck_free(own_copy);
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) { if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
@ -882,7 +895,7 @@ int main(int argc, char** argv) {
SAYF(cCYA "afl-analyze" VERSION cRST " by <lcamtuf@google.com>\n"); SAYF(cCYA "afl-analyze" VERSION cRST " by <lcamtuf@google.com>\n");
while ((opt = getopt(argc,argv,"+i:f:m:t:eQU")) > 0) while ((opt = getopt(argc, argv, "+i:f:m:t:eQU")) > 0)
switch (opt) { switch (opt) {
@ -896,7 +909,7 @@ int main(int argc, char** argv) {
if (prog_in) FATAL("Multiple -f options not supported"); if (prog_in) FATAL("Multiple -f options not supported");
use_stdin = 0; use_stdin = 0;
prog_in = optarg; prog_in = optarg;
break; break;
case 'e': case 'e':
@ -907,40 +920,41 @@ int main(int argc, char** argv) {
case 'm': { case 'm': {
u8 suffix = 'M'; u8 suffix = 'M';
if (mem_limit_given) FATAL("Multiple -m options not supported"); if (mem_limit_given) FATAL("Multiple -m options not supported");
mem_limit_given = 1; mem_limit_given = 1;
if (!strcmp(optarg, "none")) { if (!strcmp(optarg, "none")) {
mem_limit = 0; mem_limit = 0;
break; break;
}
if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
optarg[0] == '-') FATAL("Bad syntax used for -m");
switch (suffix) {
case 'T': mem_limit *= 1024 * 1024; break;
case 'G': mem_limit *= 1024; break;
case 'k': mem_limit /= 1024; break;
case 'M': break;
default: FATAL("Unsupported suffix or bad syntax for -m");
}
if (mem_limit < 5) FATAL("Dangerously low value of -m");
if (sizeof(rlim_t) == 4 && mem_limit > 2000)
FATAL("Value of -m out of range on 32-bit systems");
} }
break; if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
optarg[0] == '-')
FATAL("Bad syntax used for -m");
switch (suffix) {
case 'T': mem_limit *= 1024 * 1024; break;
case 'G': mem_limit *= 1024; break;
case 'k': mem_limit /= 1024; break;
case 'M': break;
default: FATAL("Unsupported suffix or bad syntax for -m");
}
if (mem_limit < 5) FATAL("Dangerously low value of -m");
if (sizeof(rlim_t) == 4 && mem_limit > 2000)
FATAL("Value of -m out of range on 32-bit systems");
}
break;
case 't': case 't':
@ -970,9 +984,7 @@ int main(int argc, char** argv) {
unicorn_mode = 1; unicorn_mode = 1;
break; break;
default: default: usage(argv[0]);
usage(argv[0]);
} }

View File

@ -48,39 +48,38 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/time.h> #include <sys/time.h>
static u8** as_params; /* Parameters passed to the real 'as' */ static u8** as_params; /* Parameters passed to the real 'as' */
static u8* input_file; /* Originally specified input file */ static u8* input_file; /* Originally specified input file */
static u8* modified_file; /* Instrumented file for the real 'as' */ static u8* modified_file; /* Instrumented file for the real 'as' */
static u8 be_quiet, /* Quiet mode (no stderr output) */ static u8 be_quiet, /* Quiet mode (no stderr output) */
clang_mode, /* Running in clang mode? */ clang_mode, /* Running in clang mode? */
pass_thru, /* Just pass data through? */ pass_thru, /* Just pass data through? */
just_version, /* Just show version? */ just_version, /* Just show version? */
sanitizer; /* Using ASAN / MSAN */ sanitizer; /* Using ASAN / MSAN */
static u32 inst_ratio = 100, /* Instrumentation probability (%) */ static u32 inst_ratio = 100, /* Instrumentation probability (%) */
as_par_cnt = 1; /* Number of params to 'as' */ as_par_cnt = 1; /* Number of params to 'as' */
/* If we don't find --32 or --64 in the command line, default to /* If we don't find --32 or --64 in the command line, default to
instrumentation for whichever mode we were compiled with. This is not instrumentation for whichever mode we were compiled with. This is not
perfect, but should do the trick for almost all use cases. */ perfect, but should do the trick for almost all use cases. */
#ifdef __x86_64__ #ifdef __x86_64__
static u8 use_64bit = 1; static u8 use_64bit = 1;
#else #else
static u8 use_64bit = 0; static u8 use_64bit = 0;
#ifdef __APPLE__ # ifdef __APPLE__
# error "Sorry, 32-bit Apple platforms are not supported." # error "Sorry, 32-bit Apple platforms are not supported."
#endif /* __APPLE__ */ # endif /* __APPLE__ */
#endif /* ^__x86_64__ */ #endif /* ^__x86_64__ */
/* Examine and modify parameters to pass to 'as'. Note that the file name /* Examine and modify parameters to pass to 'as'. Note that the file name
is always the last parameter passed by GCC, so we exploit this property is always the last parameter passed by GCC, so we exploit this property
to keep the code simple. */ to keep the code simple. */
@ -134,8 +133,10 @@ static void edit_params(int argc, char** argv) {
for (i = 1; i < argc - 1; i++) { for (i = 1; i < argc - 1; i++) {
if (!strcmp(argv[i], "--64")) use_64bit = 1; if (!strcmp(argv[i], "--64"))
else if (!strcmp(argv[i], "--32")) use_64bit = 0; use_64bit = 1;
else if (!strcmp(argv[i], "--32"))
use_64bit = 0;
#ifdef __APPLE__ #ifdef __APPLE__
@ -143,7 +144,8 @@ static void edit_params(int argc, char** argv) {
if (!strcmp(argv[i], "-arch") && i + 1 < argc) { if (!strcmp(argv[i], "-arch") && i + 1 < argc) {
if (!strcmp(argv[i + 1], "x86_64")) use_64bit = 1; if (!strcmp(argv[i + 1], "x86_64"))
use_64bit = 1;
else if (!strcmp(argv[i + 1], "i386")) else if (!strcmp(argv[i + 1], "i386"))
FATAL("Sorry, 32-bit Apple platforms are not supported."); FATAL("Sorry, 32-bit Apple platforms are not supported.");
@ -181,13 +183,17 @@ static void edit_params(int argc, char** argv) {
if (input_file[0] == '-') { if (input_file[0] == '-') {
if (!strcmp(input_file + 1, "-version")) { if (!strcmp(input_file + 1, "-version")) {
just_version = 1; just_version = 1;
modified_file = input_file; modified_file = input_file;
goto wrap_things_up; goto wrap_things_up;
} }
if (input_file[1]) FATAL("Incorrect use (not called through afl-gcc?)"); if (input_file[1])
else input_file = NULL; FATAL("Incorrect use (not called through afl-gcc?)");
else
input_file = NULL;
} else { } else {
@ -197,22 +203,21 @@ static void edit_params(int argc, char** argv) {
NSS. */ NSS. */
if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) && if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) &&
strncmp(input_file, "/var/tmp/", 9) && strncmp(input_file, "/var/tmp/", 9) && strncmp(input_file, "/tmp/", 5))
strncmp(input_file, "/tmp/", 5)) pass_thru = 1; pass_thru = 1;
} }
modified_file = alloc_printf("%s/.afl-%u-%u.s", tmp_dir, getpid(), modified_file =
(u32)time(NULL)); alloc_printf("%s/.afl-%u-%u.s", tmp_dir, getpid(), (u32)time(NULL));
wrap_things_up: wrap_things_up:
as_params[as_par_cnt++] = modified_file; as_params[as_par_cnt++] = modified_file;
as_params[as_par_cnt] = NULL; as_params[as_par_cnt] = NULL;
} }
/* Process input file, generate modified_file. Insert instrumentation in all /* Process input file, generate modified_file. Insert instrumentation in all
the appropriate places. */ the appropriate places. */
@ -222,11 +227,11 @@ static void add_instrumentation(void) {
FILE* inf; FILE* inf;
FILE* outf; FILE* outf;
s32 outfd; s32 outfd;
u32 ins_lines = 0; u32 ins_lines = 0;
u8 instr_ok = 0, skip_csect = 0, skip_next_label = 0, u8 instr_ok = 0, skip_csect = 0, skip_next_label = 0, skip_intel = 0,
skip_intel = 0, skip_app = 0, instrument_next = 0; skip_app = 0, instrument_next = 0;
#ifdef __APPLE__ #ifdef __APPLE__
@ -239,7 +244,9 @@ static void add_instrumentation(void) {
inf = fopen(input_file, "r"); inf = fopen(input_file, "r");
if (!inf) PFATAL("Unable to read '%s'", input_file); if (!inf) PFATAL("Unable to read '%s'", input_file);
} else inf = stdin; } else
inf = stdin;
outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, 0600); outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, 0600);
@ -247,7 +254,7 @@ static void add_instrumentation(void) {
outf = fdopen(outfd, "w"); outf = fdopen(outfd, "w");
if (!outf) PFATAL("fdopen() failed"); if (!outf) PFATAL("fdopen() failed");
while (fgets(line, MAX_LINE, inf)) { while (fgets(line, MAX_LINE, inf)) {
@ -284,22 +291,26 @@ static void add_instrumentation(void) {
around them, so we use that as a signal. */ around them, so we use that as a signal. */
if (!clang_mode && instr_ok && !strncmp(line + 2, "p2align ", 8) && if (!clang_mode && instr_ok && !strncmp(line + 2, "p2align ", 8) &&
isdigit(line[10]) && line[11] == '\n') skip_next_label = 1; isdigit(line[10]) && line[11] == '\n')
skip_next_label = 1;
if (!strncmp(line + 2, "text\n", 5) || if (!strncmp(line + 2, "text\n", 5) ||
!strncmp(line + 2, "section\t.text", 13) || !strncmp(line + 2, "section\t.text", 13) ||
!strncmp(line + 2, "section\t__TEXT,__text", 21) || !strncmp(line + 2, "section\t__TEXT,__text", 21) ||
!strncmp(line + 2, "section __TEXT,__text", 21)) { !strncmp(line + 2, "section __TEXT,__text", 21)) {
instr_ok = 1; instr_ok = 1;
continue; continue;
} }
if (!strncmp(line + 2, "section\t", 8) || if (!strncmp(line + 2, "section\t", 8) ||
!strncmp(line + 2, "section ", 8) || !strncmp(line + 2, "section ", 8) || !strncmp(line + 2, "bss\n", 4) ||
!strncmp(line + 2, "bss\n", 4) ||
!strncmp(line + 2, "data\n", 5)) { !strncmp(line + 2, "data\n", 5)) {
instr_ok = 0; instr_ok = 0;
continue; continue;
} }
} }
@ -354,8 +365,9 @@ static void add_instrumentation(void) {
*/ */
if (skip_intel || skip_app || skip_csect || !instr_ok || if (skip_intel || skip_app || skip_csect || !instr_ok || line[0] == '#' ||
line[0] == '#' || line[0] == ' ') continue; line[0] == ' ')
continue;
/* Conditional branch instruction (jnz, etc). We append the instrumentation /* Conditional branch instruction (jnz, etc). We append the instrumentation
right after the branch (to instrument the not-taken path) and at the right after the branch (to instrument the not-taken path) and at the
@ -404,15 +416,16 @@ static void add_instrumentation(void) {
/* Apple: L<num> / LBB<num> */ /* Apple: L<num> / LBB<num> */
if ((isdigit(line[1]) || (clang_mode && !strncmp(line, "LBB", 3))) if ((isdigit(line[1]) || (clang_mode && !strncmp(line, "LBB", 3))) &&
&& R(100) < inst_ratio) { R(100) < inst_ratio) {
#else #else
/* Apple: .L<num> / .LBB<num> */ /* Apple: .L<num> / .LBB<num> */
if ((isdigit(line[2]) || (clang_mode && !strncmp(line + 1, "LBB", 3))) if ((isdigit(line[2]) ||
&& R(100) < inst_ratio) { (clang_mode && !strncmp(line + 1, "LBB", 3))) &&
R(100) < inst_ratio) {
#endif /* __APPLE__ */ #endif /* __APPLE__ */
@ -427,7 +440,10 @@ static void add_instrumentation(void) {
.Lfunc_begin0-style exception handling calculations (a problem on .Lfunc_begin0-style exception handling calculations (a problem on
MacOS X). */ MacOS X). */
if (!skip_next_label) instrument_next = 1; else skip_next_label = 0; if (!skip_next_label)
instrument_next = 1;
else
skip_next_label = 0;
} }
@ -436,34 +452,34 @@ static void add_instrumentation(void) {
/* Function label (always instrumented, deferred mode). */ /* Function label (always instrumented, deferred mode). */
instrument_next = 1; instrument_next = 1;
} }
} }
} }
if (ins_lines) if (ins_lines) fputs(use_64bit ? main_payload_64 : main_payload_32, outf);
fputs(use_64bit ? main_payload_64 : main_payload_32, outf);
if (input_file) fclose(inf); if (input_file) fclose(inf);
fclose(outf); fclose(outf);
if (!be_quiet) { if (!be_quiet) {
if (!ins_lines) WARNF("No instrumentation targets found%s.", if (!ins_lines)
pass_thru ? " (pass-thru mode)" : ""); WARNF("No instrumentation targets found%s.",
else OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", pass_thru ? " (pass-thru mode)" : "");
ins_lines, use_64bit ? "64" : "32", else
getenv("AFL_HARDEN") ? "hardened" : OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", ins_lines,
(sanitizer ? "ASAN/MSAN" : "non-hardened"), use_64bit ? "64" : "32",
inst_ratio); getenv("AFL_HARDEN") ? "hardened"
: (sanitizer ? "ASAN/MSAN" : "non-hardened"),
inst_ratio);
} }
} }
/* Main entry point */ /* Main entry point */
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -473,7 +489,7 @@ int main(int argc, char** argv) {
int status; int status;
u8* inst_ratio_str = getenv("AFL_INST_RATIO"); u8* inst_ratio_str = getenv("AFL_INST_RATIO");
struct timeval tv; struct timeval tv;
struct timezone tz; struct timezone tz;
clang_mode = !!getenv(CLANG_ENV_VAR); clang_mode = !!getenv(CLANG_ENV_VAR);
@ -481,19 +497,26 @@ int main(int argc, char** argv) {
if (isatty(2) && !getenv("AFL_QUIET")) { if (isatty(2) && !getenv("AFL_QUIET")) {
SAYF(cCYA "afl-as" VERSION cRST " by <lcamtuf@google.com>\n"); SAYF(cCYA "afl-as" VERSION cRST " by <lcamtuf@google.com>\n");
} else be_quiet = 1; } else
be_quiet = 1;
if (argc < 2) { if (argc < 2) {
SAYF("\n" SAYF(
"This is a helper application for afl-fuzz. It is a wrapper around GNU 'as',\n" "\n"
"executed by the toolchain whenever using afl-gcc or afl-clang. You probably\n" "This is a helper application for afl-fuzz. It is a wrapper around GNU "
"don't want to run this program directly.\n\n" "'as',\n"
"executed by the toolchain whenever using afl-gcc or afl-clang. You "
"probably\n"
"don't want to run this program directly.\n\n"
"Rarely, when dealing with extremely complex projects, it may be advisable to\n" "Rarely, when dealing with extremely complex projects, it may be "
"set AFL_INST_RATIO to a value less than 100 in order to reduce the odds of\n" "advisable to\n"
"instrumenting every discovered branch.\n\n"); "set AFL_INST_RATIO to a value less than 100 in order to reduce the "
"odds of\n"
"instrumenting every discovered branch.\n\n");
exit(1); exit(1);
@ -509,7 +532,7 @@ int main(int argc, char** argv) {
if (inst_ratio_str) { if (inst_ratio_str) {
if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || inst_ratio > 100) if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || inst_ratio > 100)
FATAL("Bad value of AFL_INST_RATIO (must be between 0 and 100)"); FATAL("Bad value of AFL_INST_RATIO (must be between 0 and 100)");
} }
@ -524,9 +547,10 @@ int main(int argc, char** argv) {
that... */ that... */
if (getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) { if (getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) {
sanitizer = 1; sanitizer = 1;
if (!getenv("AFL_INST_RATIO")) if (!getenv("AFL_INST_RATIO")) inst_ratio /= 3;
inst_ratio /= 3;
} }
if (!just_version) add_instrumentation(); if (!just_version) add_instrumentation();

View File

@ -13,25 +13,29 @@
/* Detect @@ in args. */ /* Detect @@ in args. */
#ifndef __glibc__ #ifndef __glibc__
#include <unistd.h> # include <unistd.h>
#endif #endif
void detect_file_args(char** argv, u8* prog_in) { void detect_file_args(char** argv, u8* prog_in) {
u32 i = 0; u32 i = 0;
#ifdef __GLIBC__ #ifdef __GLIBC__
u8* cwd = getcwd(NULL, 0); /* non portable glibc extension */ u8* cwd = getcwd(NULL, 0); /* non portable glibc extension */
#else #else
u8* cwd; u8* cwd;
char *buf; char* buf;
long size = pathconf(".", _PC_PATH_MAX); long size = pathconf(".", _PC_PATH_MAX);
if ((buf = (char *)malloc((size_t)size)) != NULL) { if ((buf = (char*)malloc((size_t)size)) != NULL) {
cwd = getcwd(buf, (size_t)size); /* portable version */
cwd = getcwd(buf, (size_t)size); /* portable version */
} else { } else {
PFATAL("getcwd() failed"); PFATAL("getcwd() failed");
cwd = 0; /* for dumb compilers */ cwd = 0; /* for dumb compilers */
} }
#endif #endif
if (!cwd) PFATAL("getcwd() failed"); if (!cwd) PFATAL("getcwd() failed");
@ -48,8 +52,10 @@ void detect_file_args(char** argv, u8* prog_in) {
/* Be sure that we're always using fully-qualified paths. */ /* Be sure that we're always using fully-qualified paths. */
if (prog_in[0] == '/') aa_subst = prog_in; if (prog_in[0] == '/')
else aa_subst = alloc_printf("%s/%s", cwd, prog_in); aa_subst = prog_in;
else
aa_subst = alloc_printf("%s/%s", cwd, prog_in);
/* Construct a replacement argv value. */ /* Construct a replacement argv value. */
@ -66,7 +72,7 @@ void detect_file_args(char** argv, u8* prog_in) {
} }
free(cwd); /* not tracked */ free(cwd); /* not tracked */
} }

View File

@ -15,34 +15,39 @@
#include <sys/resource.h> #include <sys/resource.h>
/* a program that includes afl-forkserver needs to define these */ /* a program that includes afl-forkserver needs to define these */
extern u8 uses_asan; extern u8 uses_asan;
extern u8 *trace_bits; extern u8 *trace_bits;
extern s32 forksrv_pid, child_pid, fsrv_ctl_fd, fsrv_st_fd; extern s32 forksrv_pid, child_pid, fsrv_ctl_fd, fsrv_st_fd;
extern s32 out_fd, out_dir_fd, dev_urandom_fd, dev_null_fd; /* initialize these with -1 */ extern s32 out_fd, out_dir_fd, dev_urandom_fd,
extern u32 exec_tmout; dev_null_fd; /* initialize these with -1 */
extern u64 mem_limit; extern u32 exec_tmout;
extern u8 *out_file, *target_path, *doc_path; extern u64 mem_limit;
extern u8 * out_file, *target_path, *doc_path;
extern FILE *plot_file; extern FILE *plot_file;
/* we need this internally but can be defined and read extern in the main source */ /* we need this internally but can be defined and read extern in the main source
*/
u8 child_timed_out; u8 child_timed_out;
/* Describe integer as memory size. */ /* Describe integer as memory size. */
u8* forkserver_DMS(u64 val) { u8 *forkserver_DMS(u64 val) {
static u8 tmp[12][16]; static u8 tmp[12][16];
static u8 cur; static u8 cur;
#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) do { \ #define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \
if (val < (_divisor) * (_limit_mult)) { \ do { \
\
if (val < (_divisor) * (_limit_mult)) { \
\
sprintf(tmp[cur], _fmt, ((_cast)val) / (_divisor)); \ sprintf(tmp[cur], _fmt, ((_cast)val) / (_divisor)); \
return tmp[cur]; \ return tmp[cur]; \
} \ \
} \
\
} while (0) } while (0)
cur = (cur + 1) % 12; cur = (cur + 1) % 12;
/* 0-9999 */ /* 0-9999 */
@ -86,20 +91,23 @@ u8* forkserver_DMS(u64 val) {
} }
/* the timeout handler */ /* the timeout handler */
void handle_timeout(int sig) { void handle_timeout(int sig) {
if (child_pid > 0) {
child_timed_out = 1;
kill(child_pid, SIGKILL);
} else if (child_pid == -1 && forksrv_pid > 0) {
child_timed_out = 1;
kill(forksrv_pid, SIGKILL);
}
}
if (child_pid > 0) {
child_timed_out = 1;
kill(child_pid, SIGKILL);
} else if (child_pid == -1 && forksrv_pid > 0) {
child_timed_out = 1;
kill(forksrv_pid, SIGKILL);
}
}
/* Spin up fork server (instrumented mode only). The idea is explained here: /* Spin up fork server (instrumented mode only). The idea is explained here:
@ -112,20 +120,18 @@ void handle_timeout(int sig) {
void init_forkserver(char **argv) { void init_forkserver(char **argv) {
static struct itimerval it; static struct itimerval it;
int st_pipe[2], ctl_pipe[2]; int st_pipe[2], ctl_pipe[2];
int status; int status;
s32 rlen; s32 rlen;
ACTF("Spinning up the fork server..."); ACTF("Spinning up the fork server...");
if (pipe(st_pipe) || pipe(ctl_pipe)) if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed");
PFATAL("pipe() failed");
child_timed_out = 0; child_timed_out = 0;
forksrv_pid = fork(); forksrv_pid = fork();
if (forksrv_pid < 0) if (forksrv_pid < 0) PFATAL("fork() failed");
PFATAL("fork() failed");
if (!forksrv_pid) { if (!forksrv_pid) {
@ -137,29 +143,33 @@ void init_forkserver(char **argv) {
soft 128. Let's try to fix that... */ soft 128. Let's try to fix that... */
if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) { if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) {
r.rlim_cur = FORKSRV_FD + 2; r.rlim_cur = FORKSRV_FD + 2;
setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */ setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */
} }
if (mem_limit) { if (mem_limit) {
r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20;
#ifdef RLIMIT_AS #ifdef RLIMIT_AS
setrlimit(RLIMIT_AS, &r); /* Ignore errors */ setrlimit(RLIMIT_AS, &r); /* Ignore errors */
#else #else
/* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but
according to reliable sources, RLIMIT_DATA covers anonymous according to reliable sources, RLIMIT_DATA covers anonymous
maps - so we should be getting good protection against OOM bugs. */ maps - so we should be getting good protection against OOM bugs. */
setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
#endif /* ^RLIMIT_AS */ #endif /* ^RLIMIT_AS */
} }
/* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered
before the dump is complete. */ before the dump is complete. */
// r.rlim_max = r.rlim_cur = 0; // r.rlim_max = r.rlim_cur = 0;
// setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
/* Isolate the process and configure standard descriptors. If out_file is /* Isolate the process and configure standard descriptors. If out_file is
specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */
@ -167,23 +177,27 @@ void init_forkserver(char **argv) {
setsid(); setsid();
if (!getenv("AFL_DEBUG_CHILD_OUTPUT")) { if (!getenv("AFL_DEBUG_CHILD_OUTPUT")) {
dup2(dev_null_fd, 1); dup2(dev_null_fd, 1);
dup2(dev_null_fd, 2); dup2(dev_null_fd, 2);
} }
if (out_file) { if (out_file) {
dup2(dev_null_fd, 0); dup2(dev_null_fd, 0);
} else { } else {
dup2(out_fd, 0); dup2(out_fd, 0);
close(out_fd); close(out_fd);
} }
/* Set up control and status pipes, close the unneeded original fds. */ /* Set up control and status pipes, close the unneeded original fds. */
if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed");
PFATAL("dup2() failed"); if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed");
if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0)
PFATAL("dup2() failed");
close(ctl_pipe[0]); close(ctl_pipe[0]);
close(ctl_pipe[1]); close(ctl_pipe[1]);
@ -198,8 +212,7 @@ void init_forkserver(char **argv) {
/* This should improve performance a bit, since it stops the linker from /* This should improve performance a bit, since it stops the linker from
doing extra work post-fork(). */ doing extra work post-fork(). */
if (!getenv("LD_BIND_LAZY")) if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0);
setenv("LD_BIND_NOW", "1", 0);
/* Set sane defaults for ASAN if nothing else specified. */ /* Set sane defaults for ASAN if nothing else specified. */
@ -228,6 +241,7 @@ void init_forkserver(char **argv) {
*(u32 *)trace_bits = EXEC_FAIL_SIG; *(u32 *)trace_bits = EXEC_FAIL_SIG;
exit(0); exit(0);
} }
/* PARENT PROCESS */ /* PARENT PROCESS */
@ -243,8 +257,10 @@ void init_forkserver(char **argv) {
/* Wait for the fork server to come up, but don't wait too long. */ /* Wait for the fork server to come up, but don't wait too long. */
if (exec_tmout) { if (exec_tmout) {
it.it_value.tv_sec = ((exec_tmout * FORK_WAIT_MULT) / 1000); it.it_value.tv_sec = ((exec_tmout * FORK_WAIT_MULT) / 1000);
it.it_value.tv_usec = ((exec_tmout * FORK_WAIT_MULT) % 1000) * 1000; it.it_value.tv_usec = ((exec_tmout * FORK_WAIT_MULT) % 1000) * 1000;
} }
setitimer(ITIMER_REAL, &it, NULL); setitimer(ITIMER_REAL, &it, NULL);
@ -260,22 +276,24 @@ void init_forkserver(char **argv) {
Otherwise, try to figure out what went wrong. */ Otherwise, try to figure out what went wrong. */
if (rlen == 4) { if (rlen == 4) {
OKF("All right - fork server is up."); OKF("All right - fork server is up.");
return; return;
} }
if (child_timed_out) if (child_timed_out)
FATAL("Timeout while initializing fork server (adjusting -t may help)"); FATAL("Timeout while initializing fork server (adjusting -t may help)");
if (waitpid(forksrv_pid, &status, 0) <= 0) if (waitpid(forksrv_pid, &status, 0) <= 0) PFATAL("waitpid() failed");
PFATAL("waitpid() failed");
if (WIFSIGNALED(status)) { if (WIFSIGNALED(status)) {
if (mem_limit && mem_limit < 500 && uses_asan) { if (mem_limit && mem_limit < 500 && uses_asan) {
SAYF("\n" cLRD "[-] " cRST "Whoops, the target binary crashed suddenly, " SAYF("\n" cLRD "[-] " cRST
"before receiving any input\n" "Whoops, the target binary crashed suddenly, "
"before receiving any input\n"
" from the fuzzer! Since it seems to be built with ASAN and you " " from the fuzzer! Since it seems to be built with ASAN and you "
"have a\n" "have a\n"
" restrictive memory limit configured, this is expected; please " " restrictive memory limit configured, this is expected; please "
@ -285,8 +303,9 @@ void init_forkserver(char **argv) {
} else if (!mem_limit) { } else if (!mem_limit) {
SAYF("\n" cLRD "[-] " cRST "Whoops, the target binary crashed suddenly, " SAYF("\n" cLRD "[-] " cRST
"before receiving any input\n" "Whoops, the target binary crashed suddenly, "
"before receiving any input\n"
" from the fuzzer! There are several probable explanations:\n\n" " from the fuzzer! There are several probable explanations:\n\n"
" - The binary is just buggy and explodes entirely on its own. " " - The binary is just buggy and explodes entirely on its own. "
@ -303,8 +322,9 @@ void init_forkserver(char **argv) {
} else { } else {
SAYF("\n" cLRD "[-] " cRST "Whoops, the target binary crashed suddenly, " SAYF("\n" cLRD "[-] " cRST
"before receiving any input\n" "Whoops, the target binary crashed suddenly, "
"before receiving any input\n"
" from the fuzzer! There are several probable explanations:\n\n" " from the fuzzer! There are several probable explanations:\n\n"
" - The current memory limit (%s) is too restrictive, causing " " - The current memory limit (%s) is too restrictive, causing "
@ -315,7 +335,8 @@ void init_forkserver(char **argv) {
"way confirm\n" "way confirm\n"
" this diagnosis would be:\n\n" " this diagnosis would be:\n\n"
MSG_ULIMIT_USAGE " /path/to/fuzzed_app )\n\n" MSG_ULIMIT_USAGE
" /path/to/fuzzed_app )\n\n"
" Tip: you can use http://jwilk.net/software/recidivm to " " Tip: you can use http://jwilk.net/software/recidivm to "
"quickly\n" "quickly\n"
@ -334,9 +355,11 @@ void init_forkserver(char **argv) {
" fail, poke <afl-users@googlegroups.com> for troubleshooting " " fail, poke <afl-users@googlegroups.com> for troubleshooting "
"tips.\n", "tips.\n",
forkserver_DMS(mem_limit << 20), mem_limit - 1); forkserver_DMS(mem_limit << 20), mem_limit - 1);
} }
FATAL("Fork server crashed with signal %d", WTERMSIG(status)); FATAL("Fork server crashed with signal %d", WTERMSIG(status));
} }
if (*(u32 *)trace_bits == EXEC_FAIL_SIG) if (*(u32 *)trace_bits == EXEC_FAIL_SIG)
@ -344,8 +367,9 @@ void init_forkserver(char **argv) {
if (mem_limit && mem_limit < 500 && uses_asan) { if (mem_limit && mem_limit < 500 && uses_asan) {
SAYF("\n" cLRD "[-] " cRST "Hmm, looks like the target binary terminated " SAYF("\n" cLRD "[-] " cRST
"before we could complete a\n" "Hmm, looks like the target binary terminated "
"before we could complete a\n"
" handshake with the injected code. Since it seems to be built " " handshake with the injected code. Since it seems to be built "
"with ASAN and\n" "with ASAN and\n"
" you have a restrictive memory limit configured, this is " " you have a restrictive memory limit configured, this is "
@ -355,8 +379,9 @@ void init_forkserver(char **argv) {
} else if (!mem_limit) { } else if (!mem_limit) {
SAYF("\n" cLRD "[-] " cRST "Hmm, looks like the target binary terminated " SAYF("\n" cLRD "[-] " cRST
"before we could complete a\n" "Hmm, looks like the target binary terminated "
"before we could complete a\n"
" handshake with the injected code. Perhaps there is a horrible " " handshake with the injected code. Perhaps there is a horrible "
"bug in the\n" "bug in the\n"
" fuzzer. Poke <afl-users@googlegroups.com> for troubleshooting " " fuzzer. Poke <afl-users@googlegroups.com> for troubleshooting "
@ -365,8 +390,9 @@ void init_forkserver(char **argv) {
} else { } else {
SAYF( SAYF(
"\n" cLRD "[-] " cRST "Hmm, looks like the target binary terminated " "\n" cLRD "[-] " cRST
"before we could complete a\n" "Hmm, looks like the target binary terminated "
"before we could complete a\n"
" handshake with the injected code. There are %s probable " " handshake with the injected code. There are %s probable "
"explanations:\n\n" "explanations:\n\n"
@ -377,7 +403,8 @@ void init_forkserver(char **argv) {
"option. A\n" "option. A\n"
" simple way to confirm the diagnosis may be:\n\n" " simple way to confirm the diagnosis may be:\n\n"
MSG_ULIMIT_USAGE " /path/to/fuzzed_app )\n\n" MSG_ULIMIT_USAGE
" /path/to/fuzzed_app )\n\n"
" Tip: you can use http://jwilk.net/software/recidivm to quickly\n" " Tip: you can use http://jwilk.net/software/recidivm to quickly\n"
" estimate the required amount of virtual memory for the " " estimate the required amount of virtual memory for the "
@ -394,8 +421,10 @@ void init_forkserver(char **argv) {
" reached before the program terminates.\n\n" " reached before the program terminates.\n\n"
: "", : "",
forkserver_DMS(mem_limit << 20), mem_limit - 1); forkserver_DMS(mem_limit << 20), mem_limit - 1);
} }
FATAL("Fork server handshake failed"); FATAL("Fork server handshake failed");
} }

View File

@ -46,7 +46,6 @@ void write_bitmap(void) {
} }
/* Read bitmap from file. This is for the -B option again. */ /* Read bitmap from file. This is for the -B option again. */
void read_bitmap(u8* fname) { void read_bitmap(u8* fname) {
@ -61,10 +60,9 @@ void read_bitmap(u8* fname) {
} }
/* Check if the current execution path brings anything new to the table. /* Check if the current execution path brings anything new to the table.
Update virgin bits to reflect the finds. Returns 1 if the only change is Update virgin bits to reflect the finds. Returns 1 if the only change is
the hit-count for a particular tuple; 2 if there are new tuples seen. the hit-count for a particular tuple; 2 if there are new tuples seen.
Updates the map, so subsequent calls will always return 0. Updates the map, so subsequent calls will always return 0.
This function is called after every exec() on a fairly large buffer, so This function is called after every exec() on a fairly large buffer, so
@ -75,20 +73,20 @@ u8 has_new_bits(u8* virgin_map) {
#ifdef __x86_64__ #ifdef __x86_64__
u64* current = (u64*)trace_bits; u64* current = (u64*)trace_bits;
u64* virgin = (u64*)virgin_map; u64* virgin = (u64*)virgin_map;
u32 i = (MAP_SIZE >> 3); u32 i = (MAP_SIZE >> 3);
#else #else
u32* current = (u32*)trace_bits; u32* current = (u32*)trace_bits;
u32* virgin = (u32*)virgin_map; u32* virgin = (u32*)virgin_map;
u32 i = (MAP_SIZE >> 2); u32 i = (MAP_SIZE >> 2);
#endif /* ^__x86_64__ */ #endif /* ^__x86_64__ */
u8 ret = 0; u8 ret = 0;
while (i--) { while (i--) {
@ -111,14 +109,18 @@ u8 has_new_bits(u8* virgin_map) {
if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) || if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
(cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) || (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) ||
(cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) || (cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) ||
(cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff)) ret = 2; (cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff))
else ret = 1; ret = 2;
else
ret = 1;
#else #else
if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) || if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
(cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff)) ret = 2; (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff))
else ret = 1; ret = 2;
else
ret = 1;
#endif /* ^__x86_64__ */ #endif /* ^__x86_64__ */
@ -139,14 +141,13 @@ u8 has_new_bits(u8* virgin_map) {
} }
/* Count the number of bits set in the provided bitmap. Used for the status /* Count the number of bits set in the provided bitmap. Used for the status
screen several times every second, does not have to be fast. */ screen several times every second, does not have to be fast. */
u32 count_bits(u8* mem) { u32 count_bits(u8* mem) {
u32* ptr = (u32*)mem; u32* ptr = (u32*)mem;
u32 i = (MAP_SIZE >> 2); u32 i = (MAP_SIZE >> 2);
u32 ret = 0; u32 ret = 0;
while (i--) { while (i--) {
@ -157,8 +158,10 @@ u32 count_bits(u8* mem) {
data. */ data. */
if (v == 0xffffffff) { if (v == 0xffffffff) {
ret += 32; ret += 32;
continue; continue;
} }
v -= ((v >> 1) & 0x55555555); v -= ((v >> 1) & 0x55555555);
@ -171,8 +174,7 @@ u32 count_bits(u8* mem) {
} }
#define FF(_b) (0xff << ((_b) << 3))
#define FF(_b) (0xff << ((_b) << 3))
/* Count the number of bytes set in the bitmap. Called fairly sporadically, /* Count the number of bytes set in the bitmap. Called fairly sporadically,
mostly to update the status screen or calibrate and examine confirmed mostly to update the status screen or calibrate and examine confirmed
@ -181,7 +183,7 @@ u32 count_bits(u8* mem) {
u32 count_bytes(u8* mem) { u32 count_bytes(u8* mem) {
u32* ptr = (u32*)mem; u32* ptr = (u32*)mem;
u32 i = (MAP_SIZE >> 2); u32 i = (MAP_SIZE >> 2);
u32 ret = 0; u32 ret = 0;
while (i--) { while (i--) {
@ -200,14 +202,13 @@ u32 count_bytes(u8* mem) {
} }
/* Count the number of non-255 bytes set in the bitmap. Used strictly for the /* Count the number of non-255 bytes set in the bitmap. Used strictly for the
status screen, several calls per second or so. */ status screen, several calls per second or so. */
u32 count_non_255_bytes(u8* mem) { u32 count_non_255_bytes(u8* mem) {
u32* ptr = (u32*)mem; u32* ptr = (u32*)mem;
u32 i = (MAP_SIZE >> 2); u32 i = (MAP_SIZE >> 2);
u32 ret = 0; u32 ret = 0;
while (i--) { while (i--) {
@ -229,16 +230,14 @@ u32 count_non_255_bytes(u8* mem) {
} }
/* Destructively simplify trace by eliminating hit count information /* Destructively simplify trace by eliminating hit count information
and replacing it with 0x80 or 0x01 depending on whether the tuple and replacing it with 0x80 or 0x01 depending on whether the tuple
is hit or not. Called on every new crash or timeout, should be is hit or not. Called on every new crash or timeout, should be
reasonably fast. */ reasonably fast. */
const u8 simplify_lookup[256] = { const u8 simplify_lookup[256] = {
[0] = 1, [0] = 1, [1 ... 255] = 128
[1 ... 255] = 128
}; };
@ -265,7 +264,9 @@ void simplify_trace(u64* mem) {
mem8[6] = simplify_lookup[mem8[6]]; mem8[6] = simplify_lookup[mem8[6]];
mem8[7] = simplify_lookup[mem8[7]]; mem8[7] = simplify_lookup[mem8[7]];
} else *mem = 0x0101010101010101ULL; } else
*mem = 0x0101010101010101ULL;
++mem; ++mem;
@ -292,50 +293,49 @@ void simplify_trace(u32* mem) {
mem8[2] = simplify_lookup[mem8[2]]; mem8[2] = simplify_lookup[mem8[2]];
mem8[3] = simplify_lookup[mem8[3]]; mem8[3] = simplify_lookup[mem8[3]];
} else *mem = 0x01010101; } else
*mem = 0x01010101;
++mem; ++mem;
} }
} }
#endif /* ^__x86_64__ */ #endif /* ^__x86_64__ */
/* Destructively classify execution counts in a trace. This is used as a /* Destructively classify execution counts in a trace. This is used as a
preprocessing step for any newly acquired traces. Called on every exec, preprocessing step for any newly acquired traces. Called on every exec,
must be fast. */ must be fast. */
static const u8 count_class_lookup8[256] = { static const u8 count_class_lookup8[256] = {
[0] = 0, [0] = 0,
[1] = 1, [1] = 1,
[2] = 2, [2] = 2,
[3] = 4, [3] = 4,
[4 ... 7] = 8, [4 ... 7] = 8,
[8 ... 15] = 16, [8 ... 15] = 16,
[16 ... 31] = 32, [16 ... 31] = 32,
[32 ... 127] = 64, [32 ... 127] = 64,
[128 ... 255] = 128 [128 ... 255] = 128
}; };
static u16 count_class_lookup16[65536]; static u16 count_class_lookup16[65536];
void init_count_class16(void) { void init_count_class16(void) {
u32 b1, b2; u32 b1, b2;
for (b1 = 0; b1 < 256; b1++) for (b1 = 0; b1 < 256; b1++)
for (b2 = 0; b2 < 256; b2++) for (b2 = 0; b2 < 256; b2++)
count_class_lookup16[(b1 << 8) + b2] = count_class_lookup16[(b1 << 8) + b2] =
(count_class_lookup8[b1] << 8) | (count_class_lookup8[b1] << 8) | count_class_lookup8[b2];
count_class_lookup8[b2];
} }
#ifdef __x86_64__ #ifdef __x86_64__
void classify_counts(u64* mem) { void classify_counts(u64* mem) {
@ -390,7 +390,6 @@ void classify_counts(u32* mem) {
#endif /* ^__x86_64__ */ #endif /* ^__x86_64__ */
/* Compact trace bytes into a smaller bitmap. We effectively just drop the /* Compact trace bytes into a smaller bitmap. We effectively just drop the
count information here. This is called only sporadically, for some count information here. This is called only sporadically, for some
new paths. */ new paths. */
@ -408,7 +407,6 @@ void minimize_bits(u8* dst, u8* src) {
} }
#ifndef SIMPLE_FILES #ifndef SIMPLE_FILES
/* Construct a file name for a new test case, capturing the operation /* Construct a file name for a new test case, capturing the operation
@ -428,8 +426,7 @@ u8* describe_op(u8 hnb) {
sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - start_time); sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - start_time);
if (splicing_with >= 0) if (splicing_with >= 0) sprintf(ret + strlen(ret), "+%06d", splicing_with);
sprintf(ret + strlen(ret), "+%06d", splicing_with);
sprintf(ret + strlen(ret), ",op:%s", stage_short); sprintf(ret + strlen(ret), ",op:%s", stage_short);
@ -438,11 +435,12 @@ u8* describe_op(u8 hnb) {
sprintf(ret + strlen(ret), ",pos:%d", stage_cur_byte); sprintf(ret + strlen(ret), ",pos:%d", stage_cur_byte);
if (stage_val_type != STAGE_VAL_NONE) if (stage_val_type != STAGE_VAL_NONE)
sprintf(ret + strlen(ret), ",val:%s%+d", sprintf(ret + strlen(ret), ",val:%s%+d",
(stage_val_type == STAGE_VAL_BE) ? "be:" : "", (stage_val_type == STAGE_VAL_BE) ? "be:" : "", stage_cur_val);
stage_cur_val);
} else sprintf(ret + strlen(ret), ",rep:%d", stage_cur_val); } else
sprintf(ret + strlen(ret), ",rep:%d", stage_cur_val);
} }
@ -454,13 +452,12 @@ u8* describe_op(u8 hnb) {
#endif /* !SIMPLE_FILES */ #endif /* !SIMPLE_FILES */
/* Write a message accompanying the crash directory :-) */ /* Write a message accompanying the crash directory :-) */
static void write_crash_readme(void) { static void write_crash_readme(void) {
u8* fn = alloc_printf("%s/crashes/README.txt", out_dir); u8* fn = alloc_printf("%s/crashes/README.txt", out_dir);
s32 fd; s32 fd;
FILE* f; FILE* f;
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
@ -473,32 +470,38 @@ static void write_crash_readme(void) {
f = fdopen(fd, "w"); f = fdopen(fd, "w");
if (!f) { if (!f) {
close(fd); close(fd);
return; return;
} }
fprintf(f, "Command line used to find this crash:\n\n" fprintf(
f,
"Command line used to find this crash:\n\n"
"%s\n\n" "%s\n\n"
"If you can't reproduce a bug outside of afl-fuzz, be sure to set the same\n" "If you can't reproduce a bug outside of afl-fuzz, be sure to set the "
"memory limit. The limit used for this fuzzing session was %s.\n\n" "same\n"
"memory limit. The limit used for this fuzzing session was %s.\n\n"
"Need a tool to minimize test cases before investigating the crashes or sending\n" "Need a tool to minimize test cases before investigating the crashes or "
"them to a vendor? Check out the afl-tmin that comes with the fuzzer!\n\n" "sending\n"
"them to a vendor? Check out the afl-tmin that comes with the fuzzer!\n\n"
"Found any cool bugs in open-source tools using afl-fuzz? If yes, please drop\n" "Found any cool bugs in open-source tools using afl-fuzz? If yes, please "
"an mail at <afl-users@googlegroups.com> once the issues are fixed\n\n" "drop\n"
"an mail at <afl-users@googlegroups.com> once the issues are fixed\n\n"
" https://github.com/vanhauser-thc/AFLplusplus\n\n", " https://github.com/vanhauser-thc/AFLplusplus\n\n",
orig_cmdline, DMS(mem_limit << 20)); /* ignore errors */ orig_cmdline, DMS(mem_limit << 20)); /* ignore errors */
fclose(f); fclose(f);
} }
/* Check if the result of an execve() during routine fuzzing is interesting, /* Check if the result of an execve() during routine fuzzing is interesting,
save or queue the input test case for further analysis if so. Returns 1 if save or queue the input test case for further analysis if so. Returns 1 if
entry is saved, 0 otherwise. */ entry is saved, 0 otherwise. */
@ -507,7 +510,7 @@ u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) {
if (len == 0) return 0; if (len == 0) return 0;
u8 *fn = ""; u8* fn = "";
u8 hnb; u8 hnb;
s32 fd; s32 fd;
u8 keeping = 0, res; u8 keeping = 0, res;
@ -517,8 +520,8 @@ u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) {
struct queue_entry* q = queue; struct queue_entry* q = queue;
while (q) { while (q) {
if (q->exec_cksum == cksum)
q->n_fuzz = q->n_fuzz + 1; if (q->exec_cksum == cksum) q->n_fuzz = q->n_fuzz + 1;
q = q->next; q = q->next;
@ -530,9 +533,11 @@ u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) {
future fuzzing, etc. */ future fuzzing, etc. */
if (!(hnb = has_new_bits(virgin_bits))) { if (!(hnb = has_new_bits(virgin_bits))) {
if (crash_mode) ++total_crashes; if (crash_mode) ++total_crashes;
return 0; return 0;
}
}
#ifndef SIMPLE_FILES #ifndef SIMPLE_FILES
@ -548,8 +553,10 @@ u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) {
add_to_queue(fn, len, 0); add_to_queue(fn, len, 0);
if (hnb == 2) { if (hnb == 2) {
queue_top->has_new_cov = 1; queue_top->has_new_cov = 1;
++queued_with_cov; ++queued_with_cov;
} }
queue_top->exec_cksum = cksum; queue_top->exec_cksum = cksum;
@ -559,8 +566,7 @@ u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) {
res = calibrate_case(argv, queue_top, mem, queue_cycle - 1, 0); res = calibrate_case(argv, queue_top, mem, queue_cycle - 1, 0);
if (res == FAULT_ERROR) if (res == FAULT_ERROR) FATAL("Unable to execute target application");
FATAL("Unable to execute target application");
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) PFATAL("Unable to create '%s'", fn); if (fd < 0) PFATAL("Unable to create '%s'", fn);
@ -620,13 +626,12 @@ u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) {
#ifndef SIMPLE_FILES #ifndef SIMPLE_FILES
fn = alloc_printf("%s/hangs/id:%06llu,%s", out_dir, fn = alloc_printf("%s/hangs/id:%06llu,%s", out_dir, unique_hangs,
unique_hangs, describe_op(0)); describe_op(0));
#else #else
fn = alloc_printf("%s/hangs/id_%06llu", out_dir, fn = alloc_printf("%s/hangs/id_%06llu", out_dir, unique_hangs);
unique_hangs);
#endif /* ^!SIMPLE_FILES */ #endif /* ^!SIMPLE_FILES */
@ -638,7 +643,7 @@ u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) {
case FAULT_CRASH: case FAULT_CRASH:
keep_as_crash: keep_as_crash:
/* This is handled in a manner roughly similar to timeouts, /* This is handled in a manner roughly similar to timeouts,
except for slightly different limits and no need to re-run test except for slightly different limits and no need to re-run test

View File

@ -22,32 +22,32 @@
#include "afl-fuzz.h" #include "afl-fuzz.h"
/* Helper function for load_extras. */ /* Helper function for load_extras. */
static int compare_extras_len(const void* p1, const void* p2) { static int compare_extras_len(const void* p1, const void* p2) {
struct extra_data *e1 = (struct extra_data*)p1,
*e2 = (struct extra_data*)p2; struct extra_data *e1 = (struct extra_data*)p1, *e2 = (struct extra_data*)p2;
return e1->len - e2->len; return e1->len - e2->len;
} }
static int compare_extras_use_d(const void* p1, const void* p2) { static int compare_extras_use_d(const void* p1, const void* p2) {
struct extra_data *e1 = (struct extra_data*)p1,
*e2 = (struct extra_data*)p2; struct extra_data *e1 = (struct extra_data*)p1, *e2 = (struct extra_data*)p2;
return e2->hit_cnt - e1->hit_cnt; return e2->hit_cnt - e1->hit_cnt;
}
}
/* Read extras from a file, sort by size. */ /* Read extras from a file, sort by size. */
void load_extras_file(u8* fname, u32* min_len, u32* max_len, u32 dict_level) { void load_extras_file(u8* fname, u32* min_len, u32* max_len, u32 dict_level) {
FILE* f; FILE* f;
u8 buf[MAX_LINE]; u8 buf[MAX_LINE];
u8 *lptr; u8* lptr;
u32 cur_line = 0; u32 cur_line = 0;
f = fopen(fname, "r"); f = fopen(fname, "r");
@ -62,10 +62,12 @@ void load_extras_file(u8* fname, u32* min_len, u32* max_len, u32 dict_level) {
/* Trim on left and right. */ /* Trim on left and right. */
while (isspace(*lptr)) ++lptr; while (isspace(*lptr))
++lptr;
rptr = lptr + strlen(lptr) - 1; rptr = lptr + strlen(lptr) - 1;
while (rptr >= lptr && isspace(*rptr)) --rptr; while (rptr >= lptr && isspace(*rptr))
--rptr;
++rptr; ++rptr;
*rptr = 0; *rptr = 0;
@ -84,7 +86,8 @@ void load_extras_file(u8* fname, u32* min_len, u32* max_len, u32 dict_level) {
/* Skip alphanumerics and dashes (label). */ /* Skip alphanumerics and dashes (label). */
while (isalnum(*lptr) || *lptr == '_') ++lptr; while (isalnum(*lptr) || *lptr == '_')
++lptr;
/* If @number follows, parse that. */ /* If @number follows, parse that. */
@ -92,13 +95,15 @@ void load_extras_file(u8* fname, u32* min_len, u32* max_len, u32 dict_level) {
++lptr; ++lptr;
if (atoi(lptr) > dict_level) continue; if (atoi(lptr) > dict_level) continue;
while (isdigit(*lptr)) ++lptr; while (isdigit(*lptr))
++lptr;
} }
/* Skip whitespace and = signs. */ /* Skip whitespace and = signs. */
while (isspace(*lptr) || *lptr == '=') ++lptr; while (isspace(*lptr) || *lptr == '=')
++lptr;
/* Consume opening '"'. */ /* Consume opening '"'. */
@ -112,8 +117,8 @@ void load_extras_file(u8* fname, u32* min_len, u32* max_len, u32 dict_level) {
/* Okay, let's allocate memory and copy data between "...", handling /* Okay, let's allocate memory and copy data between "...", handling
\xNN escaping, \\, and \". */ \xNN escaping, \\, and \". */
extras = ck_realloc_block(extras, (extras_cnt + 1) * extras =
sizeof(struct extra_data)); ck_realloc_block(extras, (extras_cnt + 1) * sizeof(struct extra_data));
wptr = extras[extras_cnt].data = ck_alloc(rptr - lptr); wptr = extras[extras_cnt].data = ck_alloc(rptr - lptr);
@ -132,27 +137,25 @@ void load_extras_file(u8* fname, u32* min_len, u32* max_len, u32 dict_level) {
++lptr; ++lptr;
if (*lptr == '\\' || *lptr == '"') { if (*lptr == '\\' || *lptr == '"') {
*(wptr++) = *(lptr++); *(wptr++) = *(lptr++);
klen++; klen++;
break; break;
} }
if (*lptr != 'x' || !isxdigit(lptr[1]) || !isxdigit(lptr[2])) if (*lptr != 'x' || !isxdigit(lptr[1]) || !isxdigit(lptr[2]))
FATAL("Invalid escaping (not \\xNN) in line %u.", cur_line); FATAL("Invalid escaping (not \\xNN) in line %u.", cur_line);
*(wptr++) = *(wptr++) = ((strchr(hexdigits, tolower(lptr[1])) - hexdigits) << 4) |
((strchr(hexdigits, tolower(lptr[1])) - hexdigits) << 4) | (strchr(hexdigits, tolower(lptr[2])) - hexdigits);
(strchr(hexdigits, tolower(lptr[2])) - hexdigits);
lptr += 3; lptr += 3;
++klen; ++klen;
break; break;
default: default: *(wptr++) = *(lptr++); ++klen;
*(wptr++) = *(lptr++);
++klen;
} }
@ -161,8 +164,8 @@ void load_extras_file(u8* fname, u32* min_len, u32* max_len, u32 dict_level) {
extras[extras_cnt].len = klen; extras[extras_cnt].len = klen;
if (extras[extras_cnt].len > MAX_DICT_FILE) if (extras[extras_cnt].len > MAX_DICT_FILE)
FATAL("Keyword too big in line %u (%s, limit is %s)", cur_line, FATAL("Keyword too big in line %u (%s, limit is %s)", cur_line, DMS(klen),
DMS(klen), DMS(MAX_DICT_FILE)); DMS(MAX_DICT_FILE));
if (*min_len > klen) *min_len = klen; if (*min_len > klen) *min_len = klen;
if (*max_len < klen) *max_len = klen; if (*max_len < klen) *max_len = klen;
@ -175,15 +178,14 @@ void load_extras_file(u8* fname, u32* min_len, u32* max_len, u32 dict_level) {
} }
/* Read extras from the extras directory and sort them by size. */ /* Read extras from the extras directory and sort them by size. */
void load_extras(u8* dir) { void load_extras(u8* dir) {
DIR* d; DIR* d;
struct dirent* de; struct dirent* de;
u32 min_len = MAX_DICT_FILE, max_len = 0, dict_level = 0; u32 min_len = MAX_DICT_FILE, max_len = 0, dict_level = 0;
u8* x; u8* x;
/* If the name ends with @, extract level and continue. */ /* If the name ends with @, extract level and continue. */
@ -201,8 +203,10 @@ void load_extras(u8* dir) {
if (!d) { if (!d) {
if (errno == ENOTDIR) { if (errno == ENOTDIR) {
load_extras_file(dir, &min_len, &max_len, dict_level); load_extras_file(dir, &min_len, &max_len, dict_level);
goto check_and_sort; goto check_and_sort;
} }
PFATAL("Unable to open '%s'", dir); PFATAL("Unable to open '%s'", dir);
@ -214,11 +218,10 @@ void load_extras(u8* dir) {
while ((de = readdir(d))) { while ((de = readdir(d))) {
struct stat st; struct stat st;
u8* fn = alloc_printf("%s/%s", dir, de->d_name); u8* fn = alloc_printf("%s/%s", dir, de->d_name);
s32 fd; s32 fd;
if (lstat(fn, &st) || access(fn, R_OK)) if (lstat(fn, &st) || access(fn, R_OK)) PFATAL("Unable to access '%s'", fn);
PFATAL("Unable to access '%s'", fn);
/* This also takes care of . and .. */ /* This also takes care of . and .. */
if (!S_ISREG(st.st_mode) || !st.st_size) { if (!S_ISREG(st.st_mode) || !st.st_size) {
@ -229,17 +232,17 @@ void load_extras(u8* dir) {
} }
if (st.st_size > MAX_DICT_FILE) if (st.st_size > MAX_DICT_FILE)
FATAL("Extra '%s' is too big (%s, limit is %s)", fn, FATAL("Extra '%s' is too big (%s, limit is %s)", fn, DMS(st.st_size),
DMS(st.st_size), DMS(MAX_DICT_FILE)); DMS(MAX_DICT_FILE));
if (min_len > st.st_size) min_len = st.st_size; if (min_len > st.st_size) min_len = st.st_size;
if (max_len < st.st_size) max_len = st.st_size; if (max_len < st.st_size) max_len = st.st_size;
extras = ck_realloc_block(extras, (extras_cnt + 1) * extras =
sizeof(struct extra_data)); ck_realloc_block(extras, (extras_cnt + 1) * sizeof(struct extra_data));
extras[extras_cnt].data = ck_alloc(st.st_size); extras[extras_cnt].data = ck_alloc(st.st_size);
extras[extras_cnt].len = st.st_size; extras[extras_cnt].len = st.st_size;
fd = open(fn, O_RDONLY); fd = open(fn, O_RDONLY);
@ -262,8 +265,8 @@ check_and_sort:
qsort(extras, extras_cnt, sizeof(struct extra_data), compare_extras_len); qsort(extras, extras_cnt, sizeof(struct extra_data), compare_extras_len);
OKF("Loaded %u extra tokens, size range %s to %s.", extras_cnt, OKF("Loaded %u extra tokens, size range %s to %s.", extras_cnt, DMS(min_len),
DMS(min_len), DMS(max_len)); DMS(max_len));
if (max_len > 32) if (max_len > 32)
WARNF("Some tokens are relatively large (%s) - consider trimming.", WARNF("Some tokens are relatively large (%s) - consider trimming.",
@ -275,18 +278,16 @@ check_and_sort:
} }
/* Helper function for maybe_add_auto() */ /* Helper function for maybe_add_auto() */
static inline u8 memcmp_nocase(u8* m1, u8* m2, u32 len) { static inline u8 memcmp_nocase(u8* m1, u8* m2, u32 len) {
while (len--) if (tolower(*(m1++)) ^ tolower(*(m2++))) return 1; while (len--)
if (tolower(*(m1++)) ^ tolower(*(m2++))) return 1;
return 0; return 0;
} }
/* Maybe add automatic extra. */ /* Maybe add automatic extra. */
void maybe_add_auto(u8* mem, u32 len) { void maybe_add_auto(u8* mem, u32 len) {
@ -310,9 +311,10 @@ void maybe_add_auto(u8* mem, u32 len) {
i = sizeof(interesting_16) >> 1; i = sizeof(interesting_16) >> 1;
while (i--) while (i--)
if (*((u16*)mem) == interesting_16[i] || if (*((u16*)mem) == interesting_16[i] ||
*((u16*)mem) == SWAP16(interesting_16[i])) return; *((u16*)mem) == SWAP16(interesting_16[i]))
return;
} }
@ -320,9 +322,10 @@ void maybe_add_auto(u8* mem, u32 len) {
i = sizeof(interesting_32) >> 2; i = sizeof(interesting_32) >> 2;
while (i--) while (i--)
if (*((u32*)mem) == interesting_32[i] || if (*((u32*)mem) == interesting_32[i] ||
*((u32*)mem) == SWAP32(interesting_32[i])) return; *((u32*)mem) == SWAP32(interesting_32[i]))
return;
} }
@ -358,22 +361,21 @@ void maybe_add_auto(u8* mem, u32 len) {
if (a_extras_cnt < MAX_AUTO_EXTRAS) { if (a_extras_cnt < MAX_AUTO_EXTRAS) {
a_extras = ck_realloc_block(a_extras, (a_extras_cnt + 1) * a_extras = ck_realloc_block(a_extras,
sizeof(struct extra_data)); (a_extras_cnt + 1) * sizeof(struct extra_data));
a_extras[a_extras_cnt].data = ck_memdup(mem, len); a_extras[a_extras_cnt].data = ck_memdup(mem, len);
a_extras[a_extras_cnt].len = len; a_extras[a_extras_cnt].len = len;
++a_extras_cnt; ++a_extras_cnt;
} else { } else {
i = MAX_AUTO_EXTRAS / 2 + i = MAX_AUTO_EXTRAS / 2 + UR((MAX_AUTO_EXTRAS + 1) / 2);
UR((MAX_AUTO_EXTRAS + 1) / 2);
ck_free(a_extras[i].data); ck_free(a_extras[i].data);
a_extras[i].data = ck_memdup(mem, len); a_extras[i].data = ck_memdup(mem, len);
a_extras[i].len = len; a_extras[i].len = len;
a_extras[i].hit_cnt = 0; a_extras[i].hit_cnt = 0;
} }
@ -387,12 +389,11 @@ sort_a_extras:
/* Then, sort the top USE_AUTO_EXTRAS entries by size. */ /* Then, sort the top USE_AUTO_EXTRAS entries by size. */
qsort(a_extras, MIN(USE_AUTO_EXTRAS, a_extras_cnt), qsort(a_extras, MIN(USE_AUTO_EXTRAS, a_extras_cnt), sizeof(struct extra_data),
sizeof(struct extra_data), compare_extras_len); compare_extras_len);
} }
/* Save automatically generated extras. */ /* Save automatically generated extras. */
void save_auto(void) { void save_auto(void) {
@ -420,7 +421,6 @@ void save_auto(void) {
} }
/* Load automatically generated extras. */ /* Load automatically generated extras. */
void load_auto(void) { void load_auto(void) {
@ -458,24 +458,25 @@ void load_auto(void) {
} }
if (i) OKF("Loaded %u auto-discovered dictionary tokens.", i); if (i)
else OKF("No auto-generated dictionary tokens to reuse."); OKF("Loaded %u auto-discovered dictionary tokens.", i);
else
OKF("No auto-generated dictionary tokens to reuse.");
} }
/* Destroy extras. */ /* Destroy extras. */
void destroy_extras(void) { void destroy_extras(void) {
u32 i; u32 i;
for (i = 0; i < extras_cnt; ++i) for (i = 0; i < extras_cnt; ++i)
ck_free(extras[i].data); ck_free(extras[i].data);
ck_free(extras); ck_free(extras);
for (i = 0; i < a_extras_cnt; ++i) for (i = 0; i < a_extras_cnt; ++i)
ck_free(a_extras[i].data); ck_free(a_extras[i].data);
ck_free(a_extras); ck_free(a_extras);

View File

@ -25,27 +25,13 @@
/* MOpt: /* MOpt:
Lots of globals, but mostly for the status UI and other things where it Lots of globals, but mostly for the status UI and other things where it
really makes no sense to haul them around as function parameters. */ really makes no sense to haul them around as function parameters. */
u64 limit_time_puppet, u64 limit_time_puppet, orig_hit_cnt_puppet, last_limit_time_start,
orig_hit_cnt_puppet, tmp_pilot_time, total_pacemaker_time, total_puppet_find, temp_puppet_find,
last_limit_time_start, most_time_key, most_time, most_execs_key, most_execs, old_hit_count;
tmp_pilot_time,
total_pacemaker_time,
total_puppet_find,
temp_puppet_find,
most_time_key,
most_time,
most_execs_key,
most_execs,
old_hit_count;
s32 SPLICE_CYCLES_puppet, s32 SPLICE_CYCLES_puppet, limit_time_sig, key_puppet, key_module;
limit_time_sig,
key_puppet,
key_module;
double w_init = 0.9, double w_init = 0.9, w_end = 0.3, w_now;
w_end = 0.3,
w_now;
s32 g_now; s32 g_now;
s32 g_max = 5000; s32 g_max = 5000;
@ -53,15 +39,13 @@ s32 g_max = 5000;
u64 tmp_core_time; u64 tmp_core_time;
s32 swarm_now; s32 swarm_now;
double x_now[swarm_num][operator_num], double x_now[swarm_num][operator_num], L_best[swarm_num][operator_num],
L_best[swarm_num][operator_num], eff_best[swarm_num][operator_num], G_best[operator_num],
eff_best[swarm_num][operator_num], v_now[swarm_num][operator_num], probability_now[swarm_num][operator_num],
G_best[operator_num], swarm_fitness[swarm_num];
v_now[swarm_num][operator_num],
probability_now[swarm_num][operator_num],
swarm_fitness[swarm_num];
u64 stage_finds_puppet[swarm_num][operator_num], /* Patterns found per fuzz stage */ u64 stage_finds_puppet[swarm_num]
[operator_num], /* Patterns found per fuzz stage */
stage_finds_puppet_v2[swarm_num][operator_num], stage_finds_puppet_v2[swarm_num][operator_num],
stage_cycles_puppet_v2[swarm_num][operator_num], stage_cycles_puppet_v2[swarm_num][operator_num],
stage_cycles_puppet_v3[swarm_num][operator_num], stage_cycles_puppet_v3[swarm_num][operator_num],
@ -71,207 +55,197 @@ u64 stage_finds_puppet[swarm_num][operator_num], /* Patterns found per
core_operator_finds_puppet_v2[operator_num], core_operator_finds_puppet_v2[operator_num],
core_operator_cycles_puppet[operator_num], core_operator_cycles_puppet[operator_num],
core_operator_cycles_puppet_v2[operator_num], core_operator_cycles_puppet_v2[operator_num],
core_operator_cycles_puppet_v3[operator_num]; /* Execs per fuzz stage */ core_operator_cycles_puppet_v3[operator_num]; /* Execs per fuzz stage */
double period_pilot_tmp = 5000.0; double period_pilot_tmp = 5000.0;
s32 key_lv; s32 key_lv;
u8 *in_dir, /* Input directory with test cases */ u8 *in_dir, /* Input directory with test cases */
*out_dir, /* Working & output directory */ *out_dir, /* Working & output directory */
*tmp_dir , /* Temporary directory for input */ *tmp_dir, /* Temporary directory for input */
*sync_dir, /* Synchronization directory */ *sync_dir, /* Synchronization directory */
*sync_id, /* Fuzzer ID */ *sync_id, /* Fuzzer ID */
*power_name, /* Power schedule name */ *power_name, /* Power schedule name */
*use_banner, /* Display banner */ *use_banner, /* Display banner */
*in_bitmap, /* Input bitmap */ *in_bitmap, /* Input bitmap */
*file_extension, /* File extension */ *file_extension, /* File extension */
*orig_cmdline; /* Original command line */ *orig_cmdline; /* Original command line */
u8 *doc_path, /* Path to documentation dir */ u8 *doc_path, /* Path to documentation dir */
*target_path, /* Path to target binary */ *target_path, /* Path to target binary */
*out_file; /* File to fuzz, if any */ *out_file; /* File to fuzz, if any */
u32 exec_tmout = EXEC_TIMEOUT; /* Configurable exec timeout (ms) */ u32 exec_tmout = EXEC_TIMEOUT; /* Configurable exec timeout (ms) */
u32 hang_tmout = EXEC_TIMEOUT; /* Timeout used for hang det (ms) */ u32 hang_tmout = EXEC_TIMEOUT; /* Timeout used for hang det (ms) */
u64 mem_limit = MEM_LIMIT; /* Memory cap for child (MB) */ u64 mem_limit = MEM_LIMIT; /* Memory cap for child (MB) */
u8 cal_cycles = CAL_CYCLES, /* Calibration cycles defaults */ u8 cal_cycles = CAL_CYCLES, /* Calibration cycles defaults */
cal_cycles_long = CAL_CYCLES_LONG, cal_cycles_long = CAL_CYCLES_LONG, debug, /* Debug mode */
debug, /* Debug mode */ python_only; /* Python-only mode */
python_only; /* Python-only mode */
u32 stats_update_freq = 1; /* Stats update frequency (execs) */ u32 stats_update_freq = 1; /* Stats update frequency (execs) */
char *power_names[POWER_SCHEDULES_NUM] = { char *power_names[POWER_SCHEDULES_NUM] = {"explore", "fast", "coe",
"explore", "lin", "quad", "exploit"};
"fast",
"coe",
"lin",
"quad",
"exploit"
};
u8 schedule = EXPLORE; /* Power schedule (default: EXPLORE)*/ u8 schedule = EXPLORE; /* Power schedule (default: EXPLORE)*/
u8 havoc_max_mult = HAVOC_MAX_MULT; u8 havoc_max_mult = HAVOC_MAX_MULT;
u8 skip_deterministic, /* Skip deterministic stages? */ u8 skip_deterministic, /* Skip deterministic stages? */
force_deterministic, /* Force deterministic stages? */ force_deterministic, /* Force deterministic stages? */
use_splicing, /* Recombine input files? */ use_splicing, /* Recombine input files? */
dumb_mode, /* Run in non-instrumented mode? */ dumb_mode, /* Run in non-instrumented mode? */
score_changed, /* Scoring for favorites changed? */ score_changed, /* Scoring for favorites changed? */
kill_signal, /* Signal that killed the child */ kill_signal, /* Signal that killed the child */
resuming_fuzz, /* Resuming an older fuzzing job? */ resuming_fuzz, /* Resuming an older fuzzing job? */
timeout_given, /* Specific timeout given? */ timeout_given, /* Specific timeout given? */
not_on_tty, /* stdout is not a tty */ not_on_tty, /* stdout is not a tty */
term_too_small, /* terminal dimensions too small */ term_too_small, /* terminal dimensions too small */
no_forkserver, /* Disable forkserver? */ no_forkserver, /* Disable forkserver? */
crash_mode, /* Crash mode! Yeah! */ crash_mode, /* Crash mode! Yeah! */
in_place_resume, /* Attempt in-place resume? */ in_place_resume, /* Attempt in-place resume? */
auto_changed, /* Auto-generated tokens changed? */ auto_changed, /* Auto-generated tokens changed? */
no_cpu_meter_red, /* Feng shui on the status screen */ no_cpu_meter_red, /* Feng shui on the status screen */
no_arith, /* Skip most arithmetic ops */ no_arith, /* Skip most arithmetic ops */
shuffle_queue, /* Shuffle input queue? */ shuffle_queue, /* Shuffle input queue? */
bitmap_changed = 1, /* Time to update bitmap? */ bitmap_changed = 1, /* Time to update bitmap? */
qemu_mode, /* Running in QEMU mode? */ qemu_mode, /* Running in QEMU mode? */
unicorn_mode, /* Running in Unicorn mode? */ unicorn_mode, /* Running in Unicorn mode? */
skip_requested, /* Skip request, via SIGUSR1 */ 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? */ persistent_mode, /* Running in persistent mode? */
deferred_mode, /* Deferred forkserver mode? */ deferred_mode, /* Deferred forkserver mode? */
fixed_seed, /* do not reseed */ fixed_seed, /* do not reseed */
fast_cal, /* Try to calibrate faster? */ fast_cal, /* Try to calibrate faster? */
uses_asan; /* Target uses ASAN? */ uses_asan; /* Target uses ASAN? */
s32 out_fd, /* Persistent fd for out_file */ s32 out_fd, /* Persistent fd for out_file */
#ifndef HAVE_ARC4RANDOM #ifndef HAVE_ARC4RANDOM
dev_urandom_fd = -1, /* Persistent fd for /dev/urandom */ dev_urandom_fd = -1, /* Persistent fd for /dev/urandom */
#endif #endif
dev_null_fd = -1, /* Persistent fd for /dev/null */ dev_null_fd = -1, /* Persistent fd for /dev/null */
fsrv_ctl_fd, /* Fork server control pipe (write) */ fsrv_ctl_fd, /* Fork server control pipe (write) */
fsrv_st_fd; /* Fork server status pipe (read) */ fsrv_st_fd; /* Fork server status pipe (read) */
s32 forksrv_pid, /* PID of the fork server */ s32 forksrv_pid, /* PID of the fork server */
child_pid = -1, /* PID of the fuzzed program */ child_pid = -1, /* PID of the fuzzed program */
out_dir_fd = -1; /* FD of the lock file */ out_dir_fd = -1; /* FD of the lock file */
u8* trace_bits; /* SHM with instrumentation bitmap */ u8 *trace_bits; /* SHM with instrumentation bitmap */
u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */ u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */
virgin_tmout[MAP_SIZE], /* Bits we haven't seen in tmouts */ virgin_tmout[MAP_SIZE], /* Bits we haven't seen in tmouts */
virgin_crash[MAP_SIZE]; /* Bits we haven't seen in crashes */ virgin_crash[MAP_SIZE]; /* Bits we haven't seen in crashes */
u8 var_bytes[MAP_SIZE]; /* Bytes that appear to be variable */ u8 var_bytes[MAP_SIZE]; /* Bytes that appear to be variable */
volatile u8 stop_soon, /* Ctrl-C pressed? */ volatile u8 stop_soon, /* Ctrl-C pressed? */
clear_screen = 1, /* Window resized? */ clear_screen = 1, /* Window resized? */
child_timed_out; /* Traced process timed out? */ child_timed_out; /* Traced process timed out? */
u32 queued_paths, /* Total number of queued testcases */ u32 queued_paths, /* Total number of queued testcases */
queued_variable, /* Testcases with variable behavior */ queued_variable, /* Testcases with variable behavior */
queued_at_start, /* Total number of initial inputs */ queued_at_start, /* Total number of initial inputs */
queued_discovered, /* Items discovered during this run */ queued_discovered, /* Items discovered during this run */
queued_imported, /* Items imported via -S */ queued_imported, /* Items imported via -S */
queued_favored, /* Paths deemed favorable */ queued_favored, /* Paths deemed favorable */
queued_with_cov, /* Paths with new coverage bytes */ queued_with_cov, /* Paths with new coverage bytes */
pending_not_fuzzed, /* Queued but not done yet */ pending_not_fuzzed, /* Queued but not done yet */
pending_favored, /* Pending favored paths */ pending_favored, /* Pending favored paths */
cur_skipped_paths, /* Abandoned inputs in cur cycle */ cur_skipped_paths, /* Abandoned inputs in cur cycle */
cur_depth, /* Current path depth */ cur_depth, /* Current path depth */
max_depth, /* Max path depth */ max_depth, /* Max path depth */
useless_at_start, /* Number of useless starting paths */ useless_at_start, /* Number of useless starting paths */
var_byte_count, /* Bitmap bytes with var behavior */ var_byte_count, /* Bitmap bytes with var behavior */
current_entry, /* Current queue entry ID */ current_entry, /* Current queue entry ID */
havoc_div = 1; /* Cycle count divisor for havoc */ havoc_div = 1; /* Cycle count divisor for havoc */
u64 total_crashes, /* Total number of crashes */ u64 total_crashes, /* Total number of crashes */
unique_crashes, /* Crashes with unique signatures */ unique_crashes, /* Crashes with unique signatures */
total_tmouts, /* Total number of timeouts */ total_tmouts, /* Total number of timeouts */
unique_tmouts, /* Timeouts with unique signatures */ unique_tmouts, /* Timeouts with unique signatures */
unique_hangs, /* Hangs with unique signatures */ unique_hangs, /* Hangs with unique signatures */
total_execs, /* Total execve() calls */ total_execs, /* Total execve() calls */
slowest_exec_ms, /* Slowest testcase non hang in ms */ slowest_exec_ms, /* Slowest testcase non hang in ms */
start_time, /* Unix start time (ms) */ start_time, /* Unix start time (ms) */
last_path_time, /* Time for most recent path (ms) */ last_path_time, /* Time for most recent path (ms) */
last_crash_time, /* Time for most recent crash (ms) */ last_crash_time, /* Time for most recent crash (ms) */
last_hang_time, /* Time for most recent hang (ms) */ last_hang_time, /* Time for most recent hang (ms) */
last_crash_execs, /* Exec counter at last crash */ last_crash_execs, /* Exec counter at last crash */
queue_cycle, /* Queue round counter */ queue_cycle, /* Queue round counter */
cycles_wo_finds, /* Cycles without any new paths */ cycles_wo_finds, /* Cycles without any new paths */
trim_execs, /* Execs done to trim input files */ trim_execs, /* Execs done to trim input files */
bytes_trim_in, /* Bytes coming into the trimmer */ bytes_trim_in, /* Bytes coming into the trimmer */
bytes_trim_out, /* Bytes coming outa the trimmer */ bytes_trim_out, /* Bytes coming outa the trimmer */
blocks_eff_total, /* Blocks subject to effector maps */ blocks_eff_total, /* Blocks subject to effector maps */
blocks_eff_select; /* Blocks selected as fuzzable */ blocks_eff_select; /* Blocks selected as fuzzable */
u32 subseq_tmouts; /* Number of timeouts in a row */ u32 subseq_tmouts; /* Number of timeouts in a row */
u8 *stage_name = "init", /* Name of the current fuzz stage */ u8 *stage_name = "init", /* Name of the current fuzz stage */
*stage_short, /* Short stage name */ *stage_short, /* Short stage name */
*syncing_party; /* Currently syncing with... */ *syncing_party; /* Currently syncing with... */
s32 stage_cur, stage_max; /* Stage progression */ s32 stage_cur, stage_max; /* Stage progression */
s32 splicing_with = -1; /* Splicing with which test case? */ s32 splicing_with = -1; /* Splicing with which test case? */
u32 master_id, master_max; /* Master instance job splitting */ u32 master_id, master_max; /* Master instance job splitting */
u32 syncing_case; /* Syncing with case #... */ u32 syncing_case; /* Syncing with case #... */
s32 stage_cur_byte, /* Byte offset of current stage op */ s32 stage_cur_byte, /* Byte offset of current stage op */
stage_cur_val; /* Value used for stage op */ stage_cur_val; /* Value used for stage op */
u8 stage_val_type; /* Value type (STAGE_VAL_*) */ u8 stage_val_type; /* Value type (STAGE_VAL_*) */
u64 stage_finds[32], /* Patterns found per fuzz stage */ u64 stage_finds[32], /* Patterns found per fuzz stage */
stage_cycles[32]; /* Execs per fuzz stage */ stage_cycles[32]; /* Execs per fuzz stage */
#ifndef HAVE_ARC4RANDOM #ifndef HAVE_ARC4RANDOM
u32 rand_cnt; /* Random number counter */ u32 rand_cnt; /* Random number counter */
#endif #endif
u64 total_cal_us, /* Total calibration time (us) */ u64 total_cal_us, /* Total calibration time (us) */
total_cal_cycles; /* Total calibration cycles */ total_cal_cycles; /* Total calibration cycles */
u64 total_bitmap_size, /* Total bit count for all bitmaps */ u64 total_bitmap_size, /* Total bit count for all bitmaps */
total_bitmap_entries; /* Number of bitmaps counted */ total_bitmap_entries; /* Number of bitmaps counted */
s32 cpu_core_count; /* CPU core count */ s32 cpu_core_count; /* CPU core count */
#ifdef HAVE_AFFINITY #ifdef HAVE_AFFINITY
s32 cpu_aff = -1; /* Selected CPU core */ s32 cpu_aff = -1; /* Selected CPU core */
#endif /* HAVE_AFFINITY */ #endif /* HAVE_AFFINITY */
FILE* plot_file; /* Gnuplot output file */ FILE *plot_file; /* Gnuplot output file */
struct queue_entry *queue, /* Fuzzing queue (linked list) */
*queue_cur, /* Current offset within the queue */
*queue_top, /* Top of the list */
*q_prev100; /* Previous 100 marker */
struct queue_entry *top_rated[MAP_SIZE]; /* Top entries for bitmap bytes */
struct queue_entry *queue, /* Fuzzing queue (linked list) */ struct extra_data *extras; /* Extra tokens to fuzz with */
*queue_cur, /* Current offset within the queue */ u32 extras_cnt; /* Total number of tokens read */
*queue_top, /* Top of the list */
*q_prev100; /* Previous 100 marker */
struct queue_entry* struct extra_data *a_extras; /* Automatically selected extras */
top_rated[MAP_SIZE]; /* Top entries for bitmap bytes */ u32 a_extras_cnt; /* Total number of tokens available */
struct extra_data* extras; /* Extra tokens to fuzz with */ u8 *(*post_handler)(u8 *buf, u32 *len);
u32 extras_cnt; /* Total number of tokens read */
struct extra_data* a_extras; /* Automatically selected extras */
u32 a_extras_cnt; /* Total number of tokens available */
u8* (*post_handler)(u8* buf, u32* len);
/* hooks for the custom mutator function */ /* hooks for the custom mutator function */
size_t (*custom_mutator)(u8 *data, size_t size, u8* mutated_out, size_t max_size, unsigned int seed); size_t (*custom_mutator)(u8 *data, size_t size, u8 *mutated_out,
size_t max_size, unsigned int seed);
size_t (*pre_save_handler)(u8 *data, size_t size, u8 **new_data); size_t (*pre_save_handler)(u8 *data, size_t size, u8 **new_data);
/* Interesting values, as per config.h */ /* Interesting values, as per config.h */
s8 interesting_8[] = { INTERESTING_8 }; s8 interesting_8[] = {INTERESTING_8};
s16 interesting_16[] = { INTERESTING_8, INTERESTING_16 }; s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
s32 interesting_32[] = { INTERESTING_8, INTERESTING_16, INTERESTING_32 }; s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
/* Python stuff */ /* Python stuff */
#ifdef USE_PYTHON #ifdef USE_PYTHON

File diff suppressed because it is too large Load Diff

View File

@ -33,11 +33,16 @@ u8* DI(u64 val) {
cur = (cur + 1) % 12; cur = (cur + 1) % 12;
#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) do { \ #define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \
if (val < (_divisor) * (_limit_mult)) { \ do { \
\
if (val < (_divisor) * (_limit_mult)) { \
\
sprintf(tmp[cur], _fmt, ((_cast)val) / (_divisor)); \ sprintf(tmp[cur], _fmt, ((_cast)val) / (_divisor)); \
return tmp[cur]; \ return tmp[cur]; \
} \ \
} \
\
} while (0) } while (0)
/* 0-9999 */ /* 0-9999 */
@ -79,8 +84,7 @@ u8* DI(u64 val) {
} }
/* Describe float. Similar to the above, except with a single
/* Describe float. Similar to the above, except with a single
static buffer. */ static buffer. */
u8* DF(double val) { u8* DF(double val) {
@ -88,20 +92,23 @@ u8* DF(double val) {
static u8 tmp[16]; static u8 tmp[16];
if (val < 99.995) { if (val < 99.995) {
sprintf(tmp, "%0.02f", val); sprintf(tmp, "%0.02f", val);
return tmp; return tmp;
} }
if (val < 999.95) { if (val < 999.95) {
sprintf(tmp, "%0.01f", val); sprintf(tmp, "%0.01f", val);
return tmp; return tmp;
} }
return DI((u64)val); return DI((u64)val);
} }
/* Describe integer as memory size. */ /* Describe integer as memory size. */
u8* DMS(u64 val) { u8* DMS(u64 val) {
@ -152,14 +159,13 @@ u8* DMS(u64 val) {
} }
/* Describe time delta. Returns one static buffer, 34 chars of less. */ /* Describe time delta. Returns one static buffer, 34 chars of less. */
u8* DTD(u64 cur_ms, u64 event_ms) { u8* DTD(u64 cur_ms, u64 event_ms) {
static u8 tmp[64]; static u8 tmp[64];
u64 delta; u64 delta;
s32 t_d, t_h, t_m, t_s; s32 t_d, t_h, t_m, t_s;
if (!event_ms) return "none seen yet"; if (!event_ms) return "none seen yet";
@ -174,3 +180,4 @@ u8* DTD(u64 cur_ms, u64 event_ms) {
return tmp; return tmp;
} }

File diff suppressed because it is too large Load Diff

View File

@ -26,45 +26,62 @@
#ifdef USE_PYTHON #ifdef USE_PYTHON
int init_py() { int init_py() {
Py_Initialize(); Py_Initialize();
u8* module_name = getenv("AFL_PYTHON_MODULE"); u8* module_name = getenv("AFL_PYTHON_MODULE");
if (module_name) { if (module_name) {
PyObject* py_name = PyString_FromString(module_name); PyObject* py_name = PyString_FromString(module_name);
py_module = PyImport_Import(py_name); py_module = PyImport_Import(py_name);
Py_DECREF(py_name); Py_DECREF(py_name);
if (py_module != NULL) { if (py_module != NULL) {
u8 py_notrim = 0; u8 py_notrim = 0;
py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init"); py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init");
py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz"); py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz");
py_functions[PY_FUNC_INIT_TRIM] = PyObject_GetAttrString(py_module, "init_trim"); py_functions[PY_FUNC_INIT_TRIM] =
py_functions[PY_FUNC_POST_TRIM] = PyObject_GetAttrString(py_module, "post_trim"); PyObject_GetAttrString(py_module, "init_trim");
py_functions[PY_FUNC_POST_TRIM] =
PyObject_GetAttrString(py_module, "post_trim");
py_functions[PY_FUNC_TRIM] = PyObject_GetAttrString(py_module, "trim"); py_functions[PY_FUNC_TRIM] = PyObject_GetAttrString(py_module, "trim");
for (u8 py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) { for (u8 py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) {
if (!py_functions[py_idx] || !PyCallable_Check(py_functions[py_idx])) { if (!py_functions[py_idx] || !PyCallable_Check(py_functions[py_idx])) {
if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) { if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) {
// Implementing the trim API is optional for now // Implementing the trim API is optional for now
if (PyErr_Occurred()) if (PyErr_Occurred()) PyErr_Print();
PyErr_Print();
py_notrim = 1; py_notrim = 1;
} else { } else {
if (PyErr_Occurred())
PyErr_Print(); if (PyErr_Occurred()) PyErr_Print();
fprintf(stderr, "Cannot find/call function with index %d in external Python module.\n", py_idx); fprintf(stderr,
"Cannot find/call function with index %d in external "
"Python module.\n",
py_idx);
return 1; return 1;
} }
} }
} }
if (py_notrim) { if (py_notrim) {
py_functions[PY_FUNC_INIT_TRIM] = NULL; py_functions[PY_FUNC_INIT_TRIM] = NULL;
py_functions[PY_FUNC_POST_TRIM] = NULL; py_functions[PY_FUNC_POST_TRIM] = NULL;
py_functions[PY_FUNC_TRIM] = NULL; py_functions[PY_FUNC_TRIM] = NULL;
WARNF("Python module does not implement trim API, standard trimming will be used."); WARNF(
"Python module does not implement trim API, standard trimming will "
"be used.");
} }
PyObject *py_args, *py_value; PyObject *py_args, *py_value;
@ -73,9 +90,11 @@ int init_py() {
py_args = PyTuple_New(1); py_args = PyTuple_New(1);
py_value = PyInt_FromLong(UR(0xFFFFFFFF)); py_value = PyInt_FromLong(UR(0xFFFFFFFF));
if (!py_value) { if (!py_value) {
Py_DECREF(py_args); Py_DECREF(py_args);
fprintf(stderr, "Cannot convert argument\n"); fprintf(stderr, "Cannot convert argument\n");
return 1; return 1;
} }
PyTuple_SetItem(py_args, 0, py_value); PyTuple_SetItem(py_args, 0, py_value);
@ -85,51 +104,68 @@ int init_py() {
Py_DECREF(py_args); Py_DECREF(py_args);
if (py_value == NULL) { if (py_value == NULL) {
PyErr_Print(); PyErr_Print();
fprintf(stderr,"Call failed\n"); fprintf(stderr, "Call failed\n");
return 1; return 1;
} }
} else { } else {
PyErr_Print(); PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", module_name); fprintf(stderr, "Failed to load \"%s\"\n", module_name);
return 1; return 1;
} }
} }
return 0; return 0;
} }
void finalize_py() { void finalize_py() {
if (py_module != NULL) { if (py_module != NULL) {
u32 i; u32 i;
for (i = 0; i < PY_FUNC_COUNT; ++i) for (i = 0; i < PY_FUNC_COUNT; ++i)
Py_XDECREF(py_functions[i]); Py_XDECREF(py_functions[i]);
Py_DECREF(py_module); Py_DECREF(py_module);
} }
Py_Finalize(); Py_Finalize();
} }
void fuzz_py(char* buf, size_t buflen, char* add_buf, size_t add_buflen, char** ret, size_t* retlen) { void fuzz_py(char* buf, size_t buflen, char* add_buf, size_t add_buflen,
char** ret, size_t* retlen) {
if (py_module != NULL) { if (py_module != NULL) {
PyObject *py_args, *py_value; PyObject *py_args, *py_value;
py_args = PyTuple_New(2); py_args = PyTuple_New(2);
py_value = PyByteArray_FromStringAndSize(buf, buflen); py_value = PyByteArray_FromStringAndSize(buf, buflen);
if (!py_value) { if (!py_value) {
Py_DECREF(py_args); Py_DECREF(py_args);
fprintf(stderr, "Cannot convert argument\n"); fprintf(stderr, "Cannot convert argument\n");
return; return;
} }
PyTuple_SetItem(py_args, 0, py_value); PyTuple_SetItem(py_args, 0, py_value);
py_value = PyByteArray_FromStringAndSize(add_buf, add_buflen); py_value = PyByteArray_FromStringAndSize(add_buf, add_buflen);
if (!py_value) { if (!py_value) {
Py_DECREF(py_args); Py_DECREF(py_args);
fprintf(stderr, "Cannot convert argument\n"); fprintf(stderr, "Cannot convert argument\n");
return; return;
} }
PyTuple_SetItem(py_args, 1, py_value); PyTuple_SetItem(py_args, 1, py_value);
@ -139,26 +175,35 @@ void fuzz_py(char* buf, size_t buflen, char* add_buf, size_t add_buflen, char**
Py_DECREF(py_args); Py_DECREF(py_args);
if (py_value != NULL) { if (py_value != NULL) {
*retlen = PyByteArray_Size(py_value); *retlen = PyByteArray_Size(py_value);
*ret = malloc(*retlen); *ret = malloc(*retlen);
memcpy(*ret, PyByteArray_AsString(py_value), *retlen); memcpy(*ret, PyByteArray_AsString(py_value), *retlen);
Py_DECREF(py_value); Py_DECREF(py_value);
} else { } else {
PyErr_Print(); PyErr_Print();
fprintf(stderr,"Call failed\n"); fprintf(stderr, "Call failed\n");
return; return;
} }
} }
} }
u32 init_trim_py(char* buf, size_t buflen) { u32 init_trim_py(char* buf, size_t buflen) {
PyObject *py_args, *py_value; PyObject *py_args, *py_value;
py_args = PyTuple_New(1); py_args = PyTuple_New(1);
py_value = PyByteArray_FromStringAndSize(buf, buflen); py_value = PyByteArray_FromStringAndSize(buf, buflen);
if (!py_value) { if (!py_value) {
Py_DECREF(py_args); Py_DECREF(py_args);
FATAL("Failed to convert arguments"); FATAL("Failed to convert arguments");
} }
PyTuple_SetItem(py_args, 0, py_value); PyTuple_SetItem(py_args, 0, py_value);
@ -167,24 +212,32 @@ u32 init_trim_py(char* buf, size_t buflen) {
Py_DECREF(py_args); Py_DECREF(py_args);
if (py_value != NULL) { if (py_value != NULL) {
u32 retcnt = PyInt_AsLong(py_value); u32 retcnt = PyInt_AsLong(py_value);
Py_DECREF(py_value); Py_DECREF(py_value);
return retcnt; return retcnt;
} else { } else {
PyErr_Print(); PyErr_Print();
FATAL("Call failed"); FATAL("Call failed");
} }
} }
u32 post_trim_py(char success) { u32 post_trim_py(char success) {
PyObject *py_args, *py_value; PyObject *py_args, *py_value;
py_args = PyTuple_New(1); py_args = PyTuple_New(1);
py_value = PyBool_FromLong(success); py_value = PyBool_FromLong(success);
if (!py_value) { if (!py_value) {
Py_DECREF(py_args); Py_DECREF(py_args);
FATAL("Failed to convert arguments"); FATAL("Failed to convert arguments");
} }
PyTuple_SetItem(py_args, 0, py_value); PyTuple_SetItem(py_args, 0, py_value);
@ -193,16 +246,22 @@ u32 post_trim_py(char success) {
Py_DECREF(py_args); Py_DECREF(py_args);
if (py_value != NULL) { if (py_value != NULL) {
u32 retcnt = PyInt_AsLong(py_value); u32 retcnt = PyInt_AsLong(py_value);
Py_DECREF(py_value); Py_DECREF(py_value);
return retcnt; return retcnt;
} else { } else {
PyErr_Print(); PyErr_Print();
FATAL("Call failed"); FATAL("Call failed");
} }
} }
void trim_py(char** ret, size_t* retlen) { void trim_py(char** ret, size_t* retlen) {
PyObject *py_args, *py_value; PyObject *py_args, *py_value;
py_args = PyTuple_New(0); py_args = PyTuple_New(0);
@ -210,14 +269,19 @@ void trim_py(char** ret, size_t* retlen) {
Py_DECREF(py_args); Py_DECREF(py_args);
if (py_value != NULL) { if (py_value != NULL) {
*retlen = PyByteArray_Size(py_value); *retlen = PyByteArray_Size(py_value);
*ret = malloc(*retlen); *ret = malloc(*retlen);
memcpy(*ret, PyByteArray_AsString(py_value), *retlen); memcpy(*ret, PyByteArray_AsString(py_value), *retlen);
Py_DECREF(py_value); Py_DECREF(py_value);
} else { } else {
PyErr_Print(); PyErr_Print();
FATAL("Call failed"); FATAL("Call failed");
} }
} }
u8 trim_case_python(char** argv, struct queue_entry* q, u8* in_buf) { u8 trim_case_python(char** argv, struct queue_entry* q, u8* in_buf) {
@ -237,20 +301,24 @@ u8 trim_case_python(char** argv, struct queue_entry* q, u8* in_buf) {
stage_max = init_trim_py(in_buf, q->len); stage_max = init_trim_py(in_buf, q->len);
if (not_on_tty && debug) if (not_on_tty && debug)
SAYF("[Python Trimming] START: Max %d iterations, %u bytes", stage_max, q->len); SAYF("[Python Trimming] START: Max %d iterations, %u bytes", stage_max,
q->len);
while (stage_cur < stage_max) {
while(stage_cur < stage_max) {
sprintf(tmp, "ptrim %s", DI(trim_exec)); sprintf(tmp, "ptrim %s", DI(trim_exec));
u32 cksum; u32 cksum;
char* retbuf = NULL; char* retbuf = NULL;
size_t retlen = 0; size_t retlen = 0;
trim_py(&retbuf, &retlen); trim_py(&retbuf, &retlen);
if (retlen > orig_len) if (retlen > orig_len)
FATAL("Trimmed data returned by Python module is larger than original data"); FATAL(
"Trimmed data returned by Python module is larger than original "
"data");
write_to_testcase(retbuf, retlen); write_to_testcase(retbuf, retlen);
@ -280,17 +348,23 @@ u8 trim_case_python(char** argv, struct queue_entry* q, u8* in_buf) {
stage_cur = post_trim_py(1); stage_cur = post_trim_py(1);
if (not_on_tty && debug) if (not_on_tty && debug)
SAYF("[Python Trimming] SUCCESS: %d/%d iterations (now at %u bytes)", stage_cur, stage_max, q->len); SAYF("[Python Trimming] SUCCESS: %d/%d iterations (now at %u bytes)",
stage_cur, stage_max, q->len);
} else { } else {
/* Tell the Python module that the trimming was unsuccessful */ /* Tell the Python module that the trimming was unsuccessful */
stage_cur = post_trim_py(0); stage_cur = post_trim_py(0);
if (not_on_tty && debug) if (not_on_tty && debug)
SAYF("[Python Trimming] FAILURE: %d/%d iterations", stage_cur, stage_max); SAYF("[Python Trimming] FAILURE: %d/%d iterations", stage_cur,
stage_max);
} }
/* Since this can be slow, update the screen every now and then. */ /* Since this can be slow, update the screen every now and then. */
if (!(trim_exec++ % stats_update_freq)) show_stats();
if (!(trim_exec++ % stats_update_freq)) show_stats();
} }
if (not_on_tty && debug) if (not_on_tty && debug)
@ -303,7 +377,7 @@ u8 trim_case_python(char** argv, struct queue_entry* q, u8* in_buf) {
s32 fd; s32 fd;
unlink(q->fname); /* ignore errors */ unlink(q->fname); /* ignore errors */
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
@ -317,8 +391,6 @@ u8 trim_case_python(char** argv, struct queue_entry* q, u8* in_buf) {
} }
abort_trimming: abort_trimming:
bytes_trim_out += q->len; bytes_trim_out += q->len;
@ -327,3 +399,4 @@ abort_trimming:
} }
#endif /* USE_PYTHON */ #endif /* USE_PYTHON */

View File

@ -43,7 +43,6 @@ void mark_as_det_done(struct queue_entry* q) {
} }
/* Mark as variable. Create symlinks if possible to make it easier to examine /* Mark as variable. Create symlinks if possible to make it easier to examine
the files. */ the files. */
@ -69,7 +68,6 @@ void mark_as_variable(struct queue_entry* q) {
} }
/* Mark / unmark as redundant (edge-only). This is not used for restoring state, /* Mark / unmark as redundant (edge-only). This is not used for restoring state,
but may be useful for post-processing datasets. */ but may be useful for post-processing datasets. */
@ -102,18 +100,17 @@ void mark_as_redundant(struct queue_entry* q, u8 state) {
} }
/* Append new test case to the queue. */ /* Append new test case to the queue. */
void add_to_queue(u8* fname, u32 len, u8 passed_det) { void add_to_queue(u8* fname, u32 len, u8 passed_det) {
struct queue_entry* q = ck_alloc(sizeof(struct queue_entry)); struct queue_entry* q = ck_alloc(sizeof(struct queue_entry));
q->fname = fname; q->fname = fname;
q->len = len; q->len = len;
q->depth = cur_depth + 1; q->depth = cur_depth + 1;
q->passed_det = passed_det; q->passed_det = passed_det;
q->n_fuzz = 1; q->n_fuzz = 1;
if (q->depth > max_depth) max_depth = q->depth; if (q->depth > max_depth) max_depth = q->depth;
@ -122,7 +119,9 @@ void add_to_queue(u8* fname, u32 len, u8 passed_det) {
queue_top->next = q; queue_top->next = q;
queue_top = q; queue_top = q;
} else q_prev100 = queue = queue_top = q; } else
q_prev100 = queue = queue_top = q;
++queued_paths; ++queued_paths;
++pending_not_fuzzed; ++pending_not_fuzzed;
@ -140,7 +139,6 @@ void add_to_queue(u8* fname, u32 len, u8 passed_det) {
} }
/* Destroy the entire queue. */ /* Destroy the entire queue. */
void destroy_queue(void) { void destroy_queue(void) {
@ -159,7 +157,6 @@ void destroy_queue(void) {
} }
/* When we bump into a new path, we call this to see if the path appears /* When we bump into a new path, we call this to see if the path appears
more "favorable" than any of the existing ones. The purpose of the more "favorable" than any of the existing ones. The purpose of the
"favorables" is to have a minimal set of paths that trigger all the bits "favorables" is to have a minimal set of paths that trigger all the bits
@ -170,12 +167,11 @@ void destroy_queue(void) {
for every byte in the bitmap. We win that slot if there is no previous for every byte in the bitmap. We win that slot if there is no previous
contender, or if the contender has a more favorable speed x size factor. */ contender, or if the contender has a more favorable speed x size factor. */
void update_bitmap_score(struct queue_entry* q) { void update_bitmap_score(struct queue_entry* q) {
u32 i; u32 i;
u64 fav_factor = q->exec_us * q->len; u64 fav_factor = q->exec_us * q->len;
u64 fuzz_p2 = next_p2 (q->n_fuzz); u64 fuzz_p2 = next_p2(q->n_fuzz);
/* For every byte set in trace_bits[], see if there is a previous winner, /* For every byte set in trace_bits[], see if there is a previous winner,
and how it compares to us. */ and how it compares to us. */
@ -184,48 +180,54 @@ void update_bitmap_score(struct queue_entry* q) {
if (trace_bits[i]) { if (trace_bits[i]) {
if (top_rated[i]) { if (top_rated[i]) {
/* Faster-executing or smaller test cases are favored. */ /* Faster-executing or smaller test cases are favored. */
u64 top_rated_fuzz_p2 = next_p2 (top_rated[i]->n_fuzz); u64 top_rated_fuzz_p2 = next_p2(top_rated[i]->n_fuzz);
u64 top_rated_fav_factor = top_rated[i]->exec_us * top_rated[i]->len; u64 top_rated_fav_factor = top_rated[i]->exec_us * top_rated[i]->len;
if (fuzz_p2 > top_rated_fuzz_p2) { if (fuzz_p2 > top_rated_fuzz_p2) {
continue;
} else if (fuzz_p2 == top_rated_fuzz_p2) {
if (fav_factor > top_rated_fav_factor)
continue;
}
if (fav_factor > top_rated[i]->exec_us * top_rated[i]->len) continue; continue;
/* Looks like we're going to win. Decrease ref count for the } else if (fuzz_p2 == top_rated_fuzz_p2) {
previous winner, discard its trace_bits[] if necessary. */
if (!--top_rated[i]->tc_ref) { if (fav_factor > top_rated_fav_factor) continue;
ck_free(top_rated[i]->trace_mini);
top_rated[i]->trace_mini = 0;
}
} }
/* Insert ourselves as the new winner. */ if (fav_factor > top_rated[i]->exec_us * top_rated[i]->len) continue;
top_rated[i] = q; /* Looks like we're going to win. Decrease ref count for the
++q->tc_ref; previous winner, discard its trace_bits[] if necessary. */
if (!q->trace_mini) { if (!--top_rated[i]->tc_ref) {
q->trace_mini = ck_alloc(MAP_SIZE >> 3);
minimize_bits(q->trace_mini, trace_bits);
}
score_changed = 1; ck_free(top_rated[i]->trace_mini);
top_rated[i]->trace_mini = 0;
} }
}
/* Insert ourselves as the new winner. */
top_rated[i] = q;
++q->tc_ref;
if (!q->trace_mini) {
q->trace_mini = ck_alloc(MAP_SIZE >> 3);
minimize_bits(q->trace_mini, trace_bits);
}
score_changed = 1;
}
} }
/* The second part of the mechanism discussed above is a routine that /* The second part of the mechanism discussed above is a routine that
goes over top_rated[] entries, and then sequentially grabs winners for goes over top_rated[] entries, and then sequentially grabs winners for
previously-unseen bytes (temp_v) and marks them as favored, at least previously-unseen bytes (temp_v) and marks them as favored, at least
@ -235,8 +237,8 @@ void update_bitmap_score(struct queue_entry* q) {
void cull_queue(void) { void cull_queue(void) {
struct queue_entry* q; struct queue_entry* q;
static u8 temp_v[MAP_SIZE >> 3]; static u8 temp_v[MAP_SIZE >> 3];
u32 i; u32 i;
if (dumb_mode || !score_changed) return; if (dumb_mode || !score_changed) return;
@ -244,14 +246,16 @@ void cull_queue(void) {
memset(temp_v, 255, MAP_SIZE >> 3); memset(temp_v, 255, MAP_SIZE >> 3);
queued_favored = 0; queued_favored = 0;
pending_favored = 0; pending_favored = 0;
q = queue; q = queue;
while (q) { while (q) {
q->favored = 0; q->favored = 0;
q = q->next; q = q->next;
} }
/* Let's see if anything in the bitmap isn't captured in temp_v. /* Let's see if anything in the bitmap isn't captured in temp_v.
@ -264,27 +268,29 @@ void cull_queue(void) {
/* Remove all bits belonging to the current entry from temp_v. */ /* Remove all bits belonging to the current entry from temp_v. */
while (j--) while (j--)
if (top_rated[i]->trace_mini[j]) if (top_rated[i]->trace_mini[j])
temp_v[j] &= ~top_rated[i]->trace_mini[j]; temp_v[j] &= ~top_rated[i]->trace_mini[j];
top_rated[i]->favored = 1; top_rated[i]->favored = 1;
++queued_favored; ++queued_favored;
if (top_rated[i]->fuzz_level == 0 || !top_rated[i]->was_fuzzed) ++pending_favored; if (top_rated[i]->fuzz_level == 0 || !top_rated[i]->was_fuzzed)
++pending_favored;
} }
q = queue; q = queue;
while (q) { while (q) {
mark_as_redundant(q, !q->favored); mark_as_redundant(q, !q->favored);
q = q->next; q = q->next;
} }
} }
/* Calculate case desirability score to adjust the length of havoc fuzzing. /* Calculate case desirability score to adjust the length of havoc fuzzing.
A helper function for fuzz_one(). Maybe some of these constants should A helper function for fuzz_one(). Maybe some of these constants should
go into config.h. */ go into config.h. */
@ -305,34 +311,51 @@ u32 calculate_score(struct queue_entry* q) {
// Longer execution time means longer work on the input, the deeper in // Longer execution time means longer work on the input, the deeper in
// coverage, the better the fuzzing, right? -mh // coverage, the better the fuzzing, right? -mh
if (q->exec_us * 0.1 > avg_exec_us) perf_score = 10; if (q->exec_us * 0.1 > avg_exec_us)
else if (q->exec_us * 0.25 > avg_exec_us) perf_score = 25; perf_score = 10;
else if (q->exec_us * 0.5 > avg_exec_us) perf_score = 50; else if (q->exec_us * 0.25 > avg_exec_us)
else if (q->exec_us * 0.75 > avg_exec_us) perf_score = 75; perf_score = 25;
else if (q->exec_us * 4 < avg_exec_us) perf_score = 300; else if (q->exec_us * 0.5 > avg_exec_us)
else if (q->exec_us * 3 < avg_exec_us) perf_score = 200; perf_score = 50;
else if (q->exec_us * 2 < avg_exec_us) perf_score = 150; else if (q->exec_us * 0.75 > avg_exec_us)
perf_score = 75;
else if (q->exec_us * 4 < avg_exec_us)
perf_score = 300;
else if (q->exec_us * 3 < avg_exec_us)
perf_score = 200;
else if (q->exec_us * 2 < avg_exec_us)
perf_score = 150;
/* Adjust score based on bitmap size. The working theory is that better /* Adjust score based on bitmap size. The working theory is that better
coverage translates to better targets. Multiplier from 0.25x to 3x. */ coverage translates to better targets. Multiplier from 0.25x to 3x. */
if (q->bitmap_size * 0.3 > avg_bitmap_size) perf_score *= 3; if (q->bitmap_size * 0.3 > avg_bitmap_size)
else if (q->bitmap_size * 0.5 > avg_bitmap_size) perf_score *= 2; perf_score *= 3;
else if (q->bitmap_size * 0.75 > avg_bitmap_size) perf_score *= 1.5; else if (q->bitmap_size * 0.5 > avg_bitmap_size)
else if (q->bitmap_size * 3 < avg_bitmap_size) perf_score *= 0.25; perf_score *= 2;
else if (q->bitmap_size * 2 < avg_bitmap_size) perf_score *= 0.5; else if (q->bitmap_size * 0.75 > avg_bitmap_size)
else if (q->bitmap_size * 1.5 < avg_bitmap_size) perf_score *= 0.75; perf_score *= 1.5;
else if (q->bitmap_size * 3 < avg_bitmap_size)
perf_score *= 0.25;
else if (q->bitmap_size * 2 < avg_bitmap_size)
perf_score *= 0.5;
else if (q->bitmap_size * 1.5 < avg_bitmap_size)
perf_score *= 0.75;
/* Adjust score based on handicap. Handicap is proportional to how late /* Adjust score based on handicap. Handicap is proportional to how late
in the game we learned about this path. Latecomers are allowed to run in the game we learned about this path. Latecomers are allowed to run
for a bit longer until they catch up with the rest. */ for a bit longer until they catch up with the rest. */
if (q->handicap >= 4) { if (q->handicap >= 4) {
perf_score *= 4; perf_score *= 4;
q->handicap -= 4; q->handicap -= 4;
} else if (q->handicap) { } else if (q->handicap) {
perf_score *= 2; perf_score *= 2;
--q->handicap; --q->handicap;
} }
/* Final adjustment based on input depth, under the assumption that fuzzing /* Final adjustment based on input depth, under the assumption that fuzzing
@ -341,11 +364,11 @@ u32 calculate_score(struct queue_entry* q) {
switch (q->depth) { switch (q->depth) {
case 0 ... 3: break; case 0 ... 3: break;
case 4 ... 7: perf_score *= 2; break; case 4 ... 7: perf_score *= 2; break;
case 8 ... 13: perf_score *= 3; break; case 8 ... 13: perf_score *= 3; break;
case 14 ... 25: perf_score *= 4; break; case 14 ... 25: perf_score *= 4; break;
default: perf_score *= 5; default: perf_score *= 5;
} }
@ -357,61 +380,69 @@ u32 calculate_score(struct queue_entry* q) {
switch (schedule) { switch (schedule) {
case EXPLORE: case EXPLORE: break;
break;
case EXPLOIT: case EXPLOIT: factor = MAX_FACTOR; break;
factor = MAX_FACTOR;
break;
case COE: case COE:
fuzz_total = 0; fuzz_total = 0;
n_paths = 0; n_paths = 0;
struct queue_entry *queue_it = queue; struct queue_entry* queue_it = queue;
while (queue_it) { while (queue_it) {
fuzz_total += queue_it->n_fuzz; fuzz_total += queue_it->n_fuzz;
n_paths ++; n_paths++;
queue_it = queue_it->next; queue_it = queue_it->next;
} }
fuzz_mu = fuzz_total / n_paths; fuzz_mu = fuzz_total / n_paths;
if (fuzz <= fuzz_mu) { if (fuzz <= fuzz_mu) {
if (q->fuzz_level < 16) if (q->fuzz_level < 16)
factor = ((u32) (1 << q->fuzz_level)); factor = ((u32)(1 << q->fuzz_level));
else else
factor = MAX_FACTOR; factor = MAX_FACTOR;
} else { } else {
factor = 0; factor = 0;
} }
break; break;
case FAST: case FAST:
if (q->fuzz_level < 16) { if (q->fuzz_level < 16) {
factor = ((u32) (1 << q->fuzz_level)) / (fuzz == 0 ? 1 : fuzz);
factor = ((u32)(1 << q->fuzz_level)) / (fuzz == 0 ? 1 : fuzz);
} else } else
factor = MAX_FACTOR / (fuzz == 0 ? 1 : next_p2 (fuzz));
factor = MAX_FACTOR / (fuzz == 0 ? 1 : next_p2(fuzz));
break; break;
case LIN: case LIN: factor = q->fuzz_level / (fuzz == 0 ? 1 : fuzz); break;
factor = q->fuzz_level / (fuzz == 0 ? 1 : fuzz);
break;
case QUAD: case QUAD:
factor = q->fuzz_level * q->fuzz_level / (fuzz == 0 ? 1 : fuzz); factor = q->fuzz_level * q->fuzz_level / (fuzz == 0 ? 1 : fuzz);
break; break;
default: default: PFATAL("Unknown Power Schedule");
PFATAL ("Unknown Power Schedule");
} }
if (factor > MAX_FACTOR)
factor = MAX_FACTOR; if (factor > MAX_FACTOR) factor = MAX_FACTOR;
perf_score *= factor / POWER_BETA; perf_score *= factor / POWER_BETA;
// MOpt mode // MOpt mode
if (limit_time_sig != 0 && max_depth - q->depth < 3) perf_score *= 2; if (limit_time_sig != 0 && max_depth - q->depth < 3)
else if (perf_score < 1) perf_score = 1; // Add a lower bound to AFLFast's energy assignment strategies perf_score *= 2;
else if (perf_score < 1)
perf_score =
1; // Add a lower bound to AFLFast's energy assignment strategies
/* Make sure that we don't go over limit. */ /* Make sure that we don't go over limit. */
@ -420,3 +451,4 @@ u32 calculate_score(struct queue_entry* q) {
return perf_score; return perf_score;
} }

View File

@ -28,8 +28,8 @@
u8 run_target(char** argv, u32 timeout) { u8 run_target(char** argv, u32 timeout) {
static struct itimerval it; static struct itimerval it;
static u32 prev_timed_out = 0; static u32 prev_timed_out = 0;
static u64 exec_ms = 0; static u64 exec_ms = 0;
int status = 0; int status = 0;
u32 tb4; u32 tb4;
@ -45,7 +45,7 @@ u8 run_target(char** argv, u32 timeout) {
/* If we're running in "dumb" mode, we can't rely on the fork server /* If we're running in "dumb" mode, we can't rely on the fork server
logic compiled into the target program, so we will just keep calling logic compiled into the target program, so we will just keep calling
execve(). There is a bit of code duplication between here and execve(). There is a bit of code duplication between here and
init_forkserver(), but c'est la vie. */ init_forkserver(), but c'est la vie. */
if (dumb_mode == 1 || no_forkserver) { if (dumb_mode == 1 || no_forkserver) {
@ -64,11 +64,11 @@ u8 run_target(char** argv, u32 timeout) {
#ifdef RLIMIT_AS #ifdef RLIMIT_AS
setrlimit(RLIMIT_AS, &r); /* Ignore errors */ setrlimit(RLIMIT_AS, &r); /* Ignore errors */
#else #else
setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
#endif /* ^RLIMIT_AS */ #endif /* ^RLIMIT_AS */
@ -76,7 +76,7 @@ u8 run_target(char** argv, u32 timeout) {
r.rlim_max = r.rlim_cur = 0; r.rlim_max = r.rlim_cur = 0;
setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
/* Isolate the process and configure standard descriptors. If out_file is /* Isolate the process and configure standard descriptors. If out_file is
specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */
@ -108,10 +108,12 @@ u8 run_target(char** argv, u32 timeout) {
/* Set sane defaults for ASAN if nothing else specified. */ /* Set sane defaults for ASAN if nothing else specified. */
setenv("ASAN_OPTIONS", "abort_on_error=1:" setenv("ASAN_OPTIONS",
"detect_leaks=0:" "abort_on_error=1:"
"symbolize=0:" "detect_leaks=0:"
"allocator_may_return_null=1", 0); "symbolize=0:"
"allocator_may_return_null=1",
0);
setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
"symbolize=0:" "symbolize=0:"
@ -152,7 +154,8 @@ u8 run_target(char** argv, u32 timeout) {
} }
/* Configure timeout, as requested by user, then wait for child to terminate. */ /* Configure timeout, as requested by user, then wait for child to terminate.
*/
it.it_value.tv_sec = (timeout / 1000); it.it_value.tv_sec = (timeout / 1000);
it.it_value.tv_usec = (timeout % 1000) * 1000; it.it_value.tv_usec = (timeout % 1000) * 1000;
@ -179,9 +182,10 @@ u8 run_target(char** argv, u32 timeout) {
} }
if (!WIFSTOPPED(status)) child_pid = 0; if (!WIFSTOPPED(status)) child_pid = 0;
getitimer(ITIMER_REAL, &it); getitimer(ITIMER_REAL, &it);
exec_ms = (u64) timeout - (it.it_value.tv_sec * 1000 + it.it_value.tv_usec / 1000); exec_ms =
(u64)timeout - (it.it_value.tv_sec * 1000 + it.it_value.tv_usec / 1000);
if (slowest_exec_ms < exec_ms) slowest_exec_ms = exec_ms; if (slowest_exec_ms < exec_ms) slowest_exec_ms = exec_ms;
it.it_value.tv_sec = 0; it.it_value.tv_sec = 0;
@ -223,8 +227,10 @@ u8 run_target(char** argv, u32 timeout) {
must use a special exit code. */ must use a special exit code. */
if (uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { if (uses_asan && WEXITSTATUS(status) == MSAN_ERROR) {
kill_signal = 0; kill_signal = 0;
return FAULT_CRASH; return FAULT_CRASH;
} }
if ((dumb_mode == 1 || no_forkserver) && tb4 == EXEC_FAIL_SIG) if ((dumb_mode == 1 || no_forkserver) && tb4 == EXEC_FAIL_SIG)
@ -234,7 +240,6 @@ u8 run_target(char** argv, u32 timeout) {
} }
/* Write modified data to file for testing. If out_file is set, the old file /* Write modified data to file for testing. If out_file is set, the old file
is unlinked and a new one is created. Otherwise, out_fd is rewound and is unlinked and a new one is created. Otherwise, out_fd is rewound and
truncated. */ truncated. */
@ -245,20 +250,26 @@ void write_to_testcase(void* mem, u32 len) {
if (out_file) { if (out_file) {
unlink(out_file); /* Ignore errors. */ unlink(out_file); /* Ignore errors. */
fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600); fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) PFATAL("Unable to create '%s'", out_file); if (fd < 0) PFATAL("Unable to create '%s'", out_file);
} else lseek(fd, 0, SEEK_SET); } else
lseek(fd, 0, SEEK_SET);
if (pre_save_handler) { if (pre_save_handler) {
u8* new_data;
u8* new_data;
size_t new_size = pre_save_handler(mem, len, &new_data); size_t new_size = pre_save_handler(mem, len, &new_data);
ck_write(fd, new_data, new_size, out_file); ck_write(fd, new_data, new_size, out_file);
} else { } else {
ck_write(fd, mem, len, out_file); ck_write(fd, mem, len, out_file);
} }
if (!out_file) { if (!out_file) {
@ -266,11 +277,12 @@ void write_to_testcase(void* mem, u32 len) {
if (ftruncate(fd, len)) PFATAL("ftruncate() failed"); if (ftruncate(fd, len)) PFATAL("ftruncate() failed");
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
} else close(fd); } else
close(fd);
} }
/* The same, but with an adjustable gap. Used for trimming. */ /* The same, but with an adjustable gap. Used for trimming. */
void write_with_gap(void* mem, u32 len, u32 skip_at, u32 skip_len) { void write_with_gap(void* mem, u32 len, u32 skip_at, u32 skip_len) {
@ -280,17 +292,19 @@ void write_with_gap(void* mem, u32 len, u32 skip_at, u32 skip_len) {
if (out_file) { if (out_file) {
unlink(out_file); /* Ignore errors. */ unlink(out_file); /* Ignore errors. */
fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600); fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) PFATAL("Unable to create '%s'", out_file); if (fd < 0) PFATAL("Unable to create '%s'", out_file);
} else lseek(fd, 0, SEEK_SET); } else
lseek(fd, 0, SEEK_SET);
if (skip_at) ck_write(fd, mem, skip_at, out_file); if (skip_at) ck_write(fd, mem, skip_at, out_file);
u8 *memu8 = mem; u8* memu8 = mem;
if (tail_len) ck_write(fd, memu8 + skip_at + skip_len, tail_len, out_file); if (tail_len) ck_write(fd, memu8 + skip_at + skip_len, tail_len, out_file);
if (!out_file) { if (!out_file) {
@ -298,22 +312,23 @@ void write_with_gap(void* mem, u32 len, u32 skip_at, u32 skip_len) {
if (ftruncate(fd, len - skip_len)) PFATAL("ftruncate() failed"); if (ftruncate(fd, len - skip_len)) PFATAL("ftruncate() failed");
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
} else close(fd); } else
close(fd);
} }
/* Calibrate a new test case. This is done when processing the input directory /* Calibrate a new test case. This is done when processing the input directory
to warn about flaky or otherwise problematic test cases early on; and when to warn about flaky or otherwise problematic test cases early on; and when
new paths are discovered to detect variable behavior and so on. */ new paths are discovered to detect variable behavior and so on. */
u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem, u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem, u32 handicap,
u32 handicap, u8 from_queue) { u8 from_queue) {
static u8 first_trace[MAP_SIZE]; static u8 first_trace[MAP_SIZE];
u8 fault = 0, new_bits = 0, var_detected = 0, u8 fault = 0, new_bits = 0, var_detected = 0,
first_run = (q->exec_cksum == 0); first_run = (q->exec_cksum == 0);
u64 start_us, stop_us; u64 start_us, stop_us;
@ -326,19 +341,18 @@ u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem,
to intermittent latency. */ to intermittent latency. */
if (!from_queue || resuming_fuzz) if (!from_queue || resuming_fuzz)
use_tmout = MAX(exec_tmout + CAL_TMOUT_ADD, use_tmout =
exec_tmout * CAL_TMOUT_PERC / 100); MAX(exec_tmout + CAL_TMOUT_ADD, exec_tmout * CAL_TMOUT_PERC / 100);
++q->cal_failed; ++q->cal_failed;
stage_name = "calibration"; stage_name = "calibration";
stage_max = fast_cal ? 3 : CAL_CYCLES; stage_max = fast_cal ? 3 : CAL_CYCLES;
/* Make sure the forkserver is up before we do anything, and let's not /* Make sure the forkserver is up before we do anything, and let's not
count its spin-up time toward binary calibration. */ count its spin-up time toward binary calibration. */
if (dumb_mode != 1 && !no_forkserver && !forksrv_pid) if (dumb_mode != 1 && !no_forkserver && !forksrv_pid) init_forkserver(argv);
init_forkserver(argv);
if (q->exec_cksum) memcpy(first_trace, trace_bits, MAP_SIZE); if (q->exec_cksum) memcpy(first_trace, trace_bits, MAP_SIZE);
@ -360,8 +374,10 @@ u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem,
if (stop_soon || fault != crash_mode) goto abort_calibration; if (stop_soon || fault != crash_mode) goto abort_calibration;
if (!dumb_mode && !stage_cur && !count_bytes(trace_bits)) { if (!dumb_mode && !stage_cur && !count_bytes(trace_bits)) {
fault = FAULT_NOINST; fault = FAULT_NOINST;
goto abort_calibration; goto abort_calibration;
} }
cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);
@ -380,7 +396,7 @@ u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem,
if (!var_bytes[i] && first_trace[i] != trace_bits[i]) { if (!var_bytes[i] && first_trace[i] != trace_bits[i]) {
var_bytes[i] = 1; var_bytes[i] = 1;
stage_max = CAL_CYCLES_LONG; stage_max = CAL_CYCLES_LONG;
} }
@ -401,16 +417,16 @@ u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem,
stop_us = get_cur_time_us(); stop_us = get_cur_time_us();
total_cal_us += stop_us - start_us; total_cal_us += stop_us - start_us;
total_cal_cycles += stage_max; total_cal_cycles += stage_max;
/* OK, let's collect some stats about the performance of this test case. /* OK, let's collect some stats about the performance of this test case.
This is used for fuzzing air time calculations in calculate_score(). */ This is used for fuzzing air time calculations in calculate_score(). */
q->exec_us = (stop_us - start_us) / stage_max; q->exec_us = (stop_us - start_us) / stage_max;
q->bitmap_size = count_bytes(trace_bits); q->bitmap_size = count_bytes(trace_bits);
q->handicap = handicap; q->handicap = handicap;
q->cal_failed = 0; q->cal_failed = 0;
total_bitmap_size += q->bitmap_size; total_bitmap_size += q->bitmap_size;
++total_bitmap_entries; ++total_bitmap_entries;
@ -426,8 +442,10 @@ u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem,
abort_calibration: abort_calibration:
if (new_bits == 2 && !q->has_new_cov) { if (new_bits == 2 && !q->has_new_cov) {
q->has_new_cov = 1; q->has_new_cov = 1;
++queued_with_cov; ++queued_with_cov;
} }
/* Mark variable paths. */ /* Mark variable paths. */
@ -437,15 +455,17 @@ abort_calibration:
var_byte_count = count_bytes(var_bytes); var_byte_count = count_bytes(var_bytes);
if (!q->var_behavior) { if (!q->var_behavior) {
mark_as_variable(q); mark_as_variable(q);
++queued_variable; ++queued_variable;
} }
} }
stage_name = old_sn; stage_name = old_sn;
stage_cur = old_sc; stage_cur = old_sc;
stage_max = old_sm; stage_max = old_sm;
if (!first_run) show_stats(); if (!first_run) show_stats();
@ -453,14 +473,13 @@ abort_calibration:
} }
/* Grab interesting test cases from other fuzzers. */ /* Grab interesting test cases from other fuzzers. */
void sync_fuzzers(char** argv) { void sync_fuzzers(char** argv) {
DIR* sd; DIR* sd;
struct dirent* sd_ent; struct dirent* sd_ent;
u32 sync_cnt = 0; u32 sync_cnt = 0;
sd = opendir(sync_dir); sd = opendir(sync_dir);
if (!sd) PFATAL("Unable to open '%s'", sync_dir); if (!sd) PFATAL("Unable to open '%s'", sync_dir);
@ -468,16 +487,17 @@ void sync_fuzzers(char** argv) {
stage_max = stage_cur = 0; stage_max = stage_cur = 0;
cur_depth = 0; cur_depth = 0;
/* Look at the entries created for every other fuzzer in the sync directory. */ /* Look at the entries created for every other fuzzer in the sync directory.
*/
while ((sd_ent = readdir(sd))) { while ((sd_ent = readdir(sd))) {
static u8 stage_tmp[128]; static u8 stage_tmp[128];
DIR* qd; DIR* qd;
struct dirent* qd_ent; struct dirent* qd_ent;
u8 *qd_path, *qd_synced_path; u8 * qd_path, *qd_synced_path;
u32 min_accept = 0, next_min_accept; u32 min_accept = 0, next_min_accept;
s32 id_fd; s32 id_fd;
@ -490,8 +510,10 @@ void sync_fuzzers(char** argv) {
qd_path = alloc_printf("%s/%s/queue", sync_dir, sd_ent->d_name); qd_path = alloc_printf("%s/%s/queue", sync_dir, sd_ent->d_name);
if (!(qd = opendir(qd_path))) { if (!(qd = opendir(qd_path))) {
ck_free(qd_path); ck_free(qd_path);
continue; continue;
} }
/* Retrieve the ID of the last seen test case. */ /* Retrieve the ID of the last seen test case. */
@ -502,35 +524,34 @@ void sync_fuzzers(char** argv) {
if (id_fd < 0) PFATAL("Unable to create '%s'", qd_synced_path); if (id_fd < 0) PFATAL("Unable to create '%s'", qd_synced_path);
if (read(id_fd, &min_accept, sizeof(u32)) > 0) if (read(id_fd, &min_accept, sizeof(u32)) > 0) lseek(id_fd, 0, SEEK_SET);
lseek(id_fd, 0, SEEK_SET);
next_min_accept = min_accept; next_min_accept = min_accept;
/* Show stats */ /* Show stats */
sprintf(stage_tmp, "sync %u", ++sync_cnt); sprintf(stage_tmp, "sync %u", ++sync_cnt);
stage_name = stage_tmp; stage_name = stage_tmp;
stage_cur = 0; stage_cur = 0;
stage_max = 0; stage_max = 0;
/* For every file queued by this fuzzer, parse ID and see if we have looked at /* For every file queued by this fuzzer, parse ID and see if we have looked
it before; exec a test case if not. */ at it before; exec a test case if not. */
while ((qd_ent = readdir(qd))) { while ((qd_ent = readdir(qd))) {
u8* path; u8* path;
s32 fd; s32 fd;
struct stat st; struct stat st;
if (qd_ent->d_name[0] == '.' || if (qd_ent->d_name[0] == '.' ||
sscanf(qd_ent->d_name, CASE_PREFIX "%06u", &syncing_case) != 1 || sscanf(qd_ent->d_name, CASE_PREFIX "%06u", &syncing_case) != 1 ||
syncing_case < min_accept) continue; syncing_case < min_accept)
continue;
/* OK, sounds like a new one. Let's give it a try. */ /* OK, sounds like a new one. Let's give it a try. */
if (syncing_case >= next_min_accept) if (syncing_case >= next_min_accept) next_min_accept = syncing_case + 1;
next_min_accept = syncing_case + 1;
path = alloc_printf("%s/%s", qd_path, qd_ent->d_name); path = alloc_printf("%s/%s", qd_path, qd_ent->d_name);
@ -539,8 +560,10 @@ void sync_fuzzers(char** argv) {
fd = open(path, O_RDONLY); fd = open(path, O_RDONLY);
if (fd < 0) { if (fd < 0) {
ck_free(path);
continue; ck_free(path);
continue;
} }
if (fstat(fd, &st)) PFATAL("fstat() failed"); if (fstat(fd, &st)) PFATAL("fstat() failed");
@ -584,14 +607,13 @@ void sync_fuzzers(char** argv) {
closedir(qd); closedir(qd);
ck_free(qd_path); ck_free(qd_path);
ck_free(qd_synced_path); ck_free(qd_synced_path);
} }
closedir(sd); closedir(sd);
} }
/* Trim all new test cases to save cycles when doing deterministic checks. The /* Trim all new test cases to save cycles when doing deterministic checks. The
trimmer uses power-of-two increments somewhere between 1/16 and 1/1024 of trimmer uses power-of-two increments somewhere between 1/16 and 1/1024 of
file size, to keep the stage short and sweet. */ file size, to keep the stage short and sweet. */
@ -599,8 +621,7 @@ void sync_fuzzers(char** argv) {
u8 trim_case(char** argv, struct queue_entry* q, u8* in_buf) { u8 trim_case(char** argv, struct queue_entry* q, u8* in_buf) {
#ifdef USE_PYTHON #ifdef USE_PYTHON
if (py_functions[PY_FUNC_TRIM]) if (py_functions[PY_FUNC_TRIM]) return trim_case_python(argv, q, in_buf);
return trim_case_python(argv, q, in_buf);
#endif #endif
static u8 tmp[64]; static u8 tmp[64];
@ -664,9 +685,9 @@ u8 trim_case(char** argv, struct queue_entry* q, u8* in_buf) {
u32 move_tail = q->len - remove_pos - trim_avail; u32 move_tail = q->len - remove_pos - trim_avail;
q->len -= trim_avail; q->len -= trim_avail;
len_p2 = next_p2(q->len); len_p2 = next_p2(q->len);
memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail,
move_tail); move_tail);
/* Let's save a clean trace, which will be needed by /* Let's save a clean trace, which will be needed by
@ -679,7 +700,9 @@ u8 trim_case(char** argv, struct queue_entry* q, u8* in_buf) {
} }
} else remove_pos += remove_len; } else
remove_pos += remove_len;
/* Since this can be slow, update the screen every now and then. */ /* Since this can be slow, update the screen every now and then. */
@ -699,7 +722,7 @@ u8 trim_case(char** argv, struct queue_entry* q, u8* in_buf) {
s32 fd; s32 fd;
unlink(q->fname); /* ignore errors */ unlink(q->fname); /* ignore errors */
fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
@ -720,7 +743,6 @@ abort_trimming:
} }
/* Write a modified test case, run program, process results. Handle /* Write a modified test case, run program, process results. Handle
error conditions, returning 1 if it's time to bail out. This is error conditions, returning 1 if it's time to bail out. This is
a helper function for fuzz_one(). */ a helper function for fuzz_one(). */
@ -745,20 +767,24 @@ u8 common_fuzz_stuff(char** argv, u8* out_buf, u32 len) {
if (fault == FAULT_TMOUT) { if (fault == FAULT_TMOUT) {
if (subseq_tmouts++ > TMOUT_LIMIT) { if (subseq_tmouts++ > TMOUT_LIMIT) {
++cur_skipped_paths; ++cur_skipped_paths;
return 1; return 1;
} }
} else subseq_tmouts = 0; } else
subseq_tmouts = 0;
/* Users can hit us with SIGUSR1 to request the current input /* Users can hit us with SIGUSR1 to request the current input
to be abandoned. */ to be abandoned. */
if (skip_requested) { if (skip_requested) {
skip_requested = 0; skip_requested = 0;
++cur_skipped_paths; ++cur_skipped_paths;
return 1; return 1;
} }

View File

@ -26,11 +26,11 @@
void write_stats_file(double bitmap_cvg, double stability, double eps) { void write_stats_file(double bitmap_cvg, double stability, double eps) {
static double last_bcvg, last_stab, last_eps; static double last_bcvg, last_stab, last_eps;
static struct rusage usage; static struct rusage usage;
u8* fn = alloc_printf("%s/fuzzer_stats", out_dir); u8* fn = alloc_printf("%s/fuzzer_stats", out_dir);
s32 fd; s32 fd;
FILE* f; FILE* f;
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
@ -47,66 +47,74 @@ void write_stats_file(double bitmap_cvg, double stability, double eps) {
where exec/sec stats and such are not readily available. */ where exec/sec stats and such are not readily available. */
if (!bitmap_cvg && !stability && !eps) { if (!bitmap_cvg && !stability && !eps) {
bitmap_cvg = last_bcvg; bitmap_cvg = last_bcvg;
stability = last_stab; stability = last_stab;
eps = last_eps; eps = last_eps;
} else { } else {
last_bcvg = bitmap_cvg; last_bcvg = bitmap_cvg;
last_stab = stability; last_stab = stability;
last_eps = eps; last_eps = eps;
} }
fprintf(f, "start_time : %llu\n" fprintf(f,
"last_update : %llu\n" "start_time : %llu\n"
"fuzzer_pid : %d\n" "last_update : %llu\n"
"cycles_done : %llu\n" "fuzzer_pid : %d\n"
"execs_done : %llu\n" "cycles_done : %llu\n"
"execs_per_sec : %0.02f\n" "execs_done : %llu\n"
"paths_total : %u\n" "execs_per_sec : %0.02f\n"
"paths_favored : %u\n" "paths_total : %u\n"
"paths_found : %u\n" "paths_favored : %u\n"
"paths_imported : %u\n" "paths_found : %u\n"
"max_depth : %u\n" "paths_imported : %u\n"
"cur_path : %u\n" /* Must match find_start_position() */ "max_depth : %u\n"
"pending_favs : %u\n" "cur_path : %u\n" /* Must match find_start_position() */
"pending_total : %u\n" "pending_favs : %u\n"
"variable_paths : %u\n" "pending_total : %u\n"
"stability : %0.02f%%\n" "variable_paths : %u\n"
"bitmap_cvg : %0.02f%%\n" "stability : %0.02f%%\n"
"unique_crashes : %llu\n" "bitmap_cvg : %0.02f%%\n"
"unique_hangs : %llu\n" "unique_crashes : %llu\n"
"last_path : %llu\n" "unique_hangs : %llu\n"
"last_crash : %llu\n" "last_path : %llu\n"
"last_hang : %llu\n" "last_crash : %llu\n"
"execs_since_crash : %llu\n" "last_hang : %llu\n"
"exec_timeout : %u\n" "execs_since_crash : %llu\n"
"slowest_exec_ms : %llu\n" "exec_timeout : %u\n"
"peak_rss_mb : %lu\n" "slowest_exec_ms : %llu\n"
"afl_banner : %s\n" "peak_rss_mb : %lu\n"
"afl_version : " VERSION "\n" "afl_banner : %s\n"
"target_mode : %s%s%s%s%s%s%s%s\n" "afl_version : " VERSION
"command_line : %s\n", "\n"
start_time / 1000, get_cur_time() / 1000, getpid(), "target_mode : %s%s%s%s%s%s%s%s\n"
queue_cycle ? (queue_cycle - 1) : 0, total_execs, eps, "command_line : %s\n",
queued_paths, queued_favored, queued_discovered, queued_imported, start_time / 1000, get_cur_time() / 1000, getpid(),
max_depth, current_entry, pending_favored, pending_not_fuzzed, queue_cycle ? (queue_cycle - 1) : 0, total_execs, eps, queued_paths,
queued_variable, stability, bitmap_cvg, unique_crashes, queued_favored, queued_discovered, queued_imported, max_depth,
unique_hangs, last_path_time / 1000, last_crash_time / 1000, current_entry, pending_favored, pending_not_fuzzed, queued_variable,
last_hang_time / 1000, total_execs - last_crash_execs, stability, bitmap_cvg, unique_crashes, unique_hangs,
exec_tmout, slowest_exec_ms, (unsigned long int)usage.ru_maxrss, use_banner, last_path_time / 1000, last_crash_time / 1000, last_hang_time / 1000,
unicorn_mode ? "unicorn" : "", qemu_mode ? "qemu " : "", dumb_mode ? " dumb " : "", total_execs - last_crash_execs, exec_tmout, slowest_exec_ms,
no_forkserver ? "no_forksrv " : "", crash_mode ? "crash " : "", (unsigned long int)usage.ru_maxrss, use_banner,
persistent_mode ? "persistent " : "", deferred_mode ? "deferred " : "", unicorn_mode ? "unicorn" : "", qemu_mode ? "qemu " : "",
(unicorn_mode || qemu_mode || dumb_mode || no_forkserver || crash_mode || dumb_mode ? " dumb " : "", no_forkserver ? "no_forksrv " : "",
persistent_mode || deferred_mode) ? "" : "default", crash_mode ? "crash " : "", persistent_mode ? "persistent " : "",
orig_cmdline); deferred_mode ? "deferred " : "",
/* ignore errors */ (unicorn_mode || qemu_mode || dumb_mode || no_forkserver ||
crash_mode || persistent_mode || deferred_mode)
? ""
: "default",
orig_cmdline);
/* ignore errors */
fclose(f); fclose(f);
} }
/* Update the plot file if there is a reason to. */ /* Update the plot file if there is a reason to. */
void maybe_update_plot_file(double bitmap_cvg, double eps) { void maybe_update_plot_file(double bitmap_cvg, double eps) {
@ -114,19 +122,20 @@ void maybe_update_plot_file(double bitmap_cvg, double eps) {
static u32 prev_qp, prev_pf, prev_pnf, prev_ce, prev_md; static u32 prev_qp, prev_pf, prev_pnf, prev_ce, prev_md;
static u64 prev_qc, prev_uc, prev_uh; static u64 prev_qc, prev_uc, prev_uh;
if (prev_qp == queued_paths && prev_pf == pending_favored && if (prev_qp == queued_paths && prev_pf == pending_favored &&
prev_pnf == pending_not_fuzzed && prev_ce == current_entry && prev_pnf == pending_not_fuzzed && prev_ce == current_entry &&
prev_qc == queue_cycle && prev_uc == unique_crashes && prev_qc == queue_cycle && prev_uc == unique_crashes &&
prev_uh == unique_hangs && prev_md == max_depth) return; prev_uh == unique_hangs && prev_md == max_depth)
return;
prev_qp = queued_paths; prev_qp = queued_paths;
prev_pf = pending_favored; prev_pf = pending_favored;
prev_pnf = pending_not_fuzzed; prev_pnf = pending_not_fuzzed;
prev_ce = current_entry; prev_ce = current_entry;
prev_qc = queue_cycle; prev_qc = queue_cycle;
prev_uc = unique_crashes; prev_uc = unique_crashes;
prev_uh = unique_hangs; prev_uh = unique_hangs;
prev_md = max_depth; prev_md = max_depth;
/* Fields in the file: /* Fields in the file:
@ -134,17 +143,16 @@ void maybe_update_plot_file(double bitmap_cvg, double eps) {
favored_not_fuzzed, unique_crashes, unique_hangs, max_depth, favored_not_fuzzed, unique_crashes, unique_hangs, max_depth,
execs_per_sec */ execs_per_sec */
fprintf(plot_file, fprintf(plot_file,
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f\n", "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f\n",
get_cur_time() / 1000, queue_cycle - 1, current_entry, queued_paths, get_cur_time() / 1000, queue_cycle - 1, current_entry, queued_paths,
pending_not_fuzzed, pending_favored, bitmap_cvg, unique_crashes, pending_not_fuzzed, pending_favored, bitmap_cvg, unique_crashes,
unique_hangs, max_depth, eps); /* ignore errors */ unique_hangs, max_depth, eps); /* ignore errors */
fflush(plot_file); fflush(plot_file);
} }
/* Check terminal dimensions after resize. */ /* Check terminal dimensions after resize. */
static void check_term_size(void) { static void check_term_size(void) {
@ -160,15 +168,14 @@ static void check_term_size(void) {
} }
/* A spiffy retro stats screen! This is called every stats_update_freq /* A spiffy retro stats screen! This is called every stats_update_freq
execve() calls, plus in several other circumstances. */ execve() calls, plus in several other circumstances. */
void show_stats(void) { void show_stats(void) {
static u64 last_stats_ms, last_plot_ms, last_ms, last_execs; static u64 last_stats_ms, last_plot_ms, last_ms, last_execs;
static double avg_exec; static double avg_exec;
double t_byte_ratio, stab_ratio; double t_byte_ratio, stab_ratio;
u64 cur_ms; u64 cur_ms;
u32 t_bytes, t_bits; u32 t_bytes, t_bits;
@ -194,14 +201,13 @@ void show_stats(void) {
} else { } else {
double cur_avg = ((double)(total_execs - last_execs)) * 1000 / double cur_avg =
(cur_ms - last_ms); ((double)(total_execs - last_execs)) * 1000 / (cur_ms - last_ms);
/* If there is a dramatic (5x+) jump in speed, reset the indicator /* If there is a dramatic (5x+) jump in speed, reset the indicator
more quickly. */ more quickly. */
if (cur_avg * 5 < avg_exec || cur_avg / 5 > avg_exec) if (cur_avg * 5 < avg_exec || cur_avg / 5 > avg_exec) avg_exec = cur_avg;
avg_exec = cur_avg;
avg_exec = avg_exec * (1.0 - 1.0 / AVG_SMOOTHING) + avg_exec = avg_exec * (1.0 - 1.0 / AVG_SMOOTHING) +
cur_avg * (1.0 / AVG_SMOOTHING); cur_avg * (1.0 / AVG_SMOOTHING);
@ -249,7 +255,8 @@ void show_stats(void) {
/* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */ /* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
if (!dumb_mode && cycles_wo_finds > 100 && !pending_not_fuzzed && if (!dumb_mode && cycles_wo_finds > 100 && !pending_not_fuzzed &&
getenv("AFL_EXIT_WHEN_DONE")) stop_soon = 2; getenv("AFL_EXIT_WHEN_DONE"))
stop_soon = 2;
if (total_crashes && getenv("AFL_BENCH_UNTIL_CRASH")) stop_soon = 2; if (total_crashes && getenv("AFL_BENCH_UNTIL_CRASH")) stop_soon = 2;
@ -276,7 +283,8 @@ void show_stats(void) {
if (term_too_small) { if (term_too_small) {
SAYF(cBRI "Your terminal is too small to display the UI.\n" SAYF(cBRI
"Your terminal is too small to display the UI.\n"
"Please resize terminal window to at least 79x24.\n" cRST); "Please resize terminal window to at least 79x24.\n" cRST);
return; return;
@ -285,38 +293,41 @@ void show_stats(void) {
/* Let's start by drawing a centered banner. */ /* Let's start by drawing a centered banner. */
banner_len = (crash_mode ? 24 : 22) + strlen(VERSION) + strlen(use_banner) + strlen(power_name) + 3 + 5; banner_len = (crash_mode ? 24 : 22) + strlen(VERSION) + strlen(use_banner) +
strlen(power_name) + 3 + 5;
banner_pad = (79 - banner_len) / 2; banner_pad = (79 - banner_len) / 2;
memset(tmp, ' ', banner_pad); memset(tmp, ' ', banner_pad);
#ifdef HAVE_AFFINITY #ifdef HAVE_AFFINITY
sprintf(tmp + banner_pad, "%s " cLCY VERSION cLGN sprintf(tmp + banner_pad,
" (%s) " cPIN "[%s]" cBLU " {%d}", crash_mode ? cPIN "peruvian were-rabbit" : "%s " cLCY VERSION cLGN " (%s) " cPIN "[%s]" cBLU " {%d}",
cYEL "american fuzzy lop", use_banner, power_name, cpu_aff); crash_mode ? cPIN "peruvian were-rabbit" : cYEL "american fuzzy lop",
use_banner, power_name, cpu_aff);
#else #else
sprintf(tmp + banner_pad, "%s " cLCY VERSION cLGN sprintf(tmp + banner_pad, "%s " cLCY VERSION cLGN " (%s) " cPIN "[%s]",
" (%s) " cPIN "[%s]", crash_mode ? cPIN "peruvian were-rabbit" : crash_mode ? cPIN "peruvian were-rabbit" : cYEL "american fuzzy lop",
cYEL "american fuzzy lop", use_banner, power_name); use_banner, power_name);
#endif /* HAVE_AFFINITY */ #endif /* HAVE_AFFINITY */
SAYF("\n%s\n", tmp); SAYF("\n%s\n", tmp);
/* "Handy" shortcuts for drawing boxes... */ /* "Handy" shortcuts for drawing boxes... */
#define bSTG bSTART cGRA #define bSTG bSTART cGRA
#define bH2 bH bH #define bH2 bH bH
#define bH5 bH2 bH2 bH #define bH5 bH2 bH2 bH
#define bH10 bH5 bH5 #define bH10 bH5 bH5
#define bH20 bH10 bH10 #define bH20 bH10 bH10
#define bH30 bH20 bH10 #define bH30 bH20 bH10
#define SP5 " " #define SP5 " "
#define SP10 SP5 SP5 #define SP10 SP5 SP5
#define SP20 SP10 SP10 #define SP20 SP10 SP10
/* Lord, forgive me this. */ /* Lord, forgive me this. */
SAYF(SET_G1 bSTG bLT bH bSTOP cCYA " process timing " bSTG bH30 bH5 bH bHB SAYF(SET_G1 bSTG bLT bH bSTOP cCYA
bH bSTOP cCYA " overall results " bSTG bH2 bH2 bRT "\n"); " process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA
" overall results " bSTG bH2 bH2 bRT "\n");
if (dumb_mode) { if (dumb_mode) {
@ -327,29 +338,34 @@ void show_stats(void) {
u64 min_wo_finds = (cur_ms - last_path_time) / 1000 / 60; u64 min_wo_finds = (cur_ms - last_path_time) / 1000 / 60;
/* First queue cycle: don't stop now! */ /* First queue cycle: don't stop now! */
if (queue_cycle == 1 || min_wo_finds < 15) strcpy(tmp, cMGN); else if (queue_cycle == 1 || min_wo_finds < 15)
strcpy(tmp, cMGN);
else
/* Subsequent cycles, but we're still making finds. */ /* Subsequent cycles, but we're still making finds. */
if (cycles_wo_finds < 25 || min_wo_finds < 30) strcpy(tmp, cYEL); else if (cycles_wo_finds < 25 || min_wo_finds < 30)
strcpy(tmp, cYEL);
else
/* No finds for a long time and no test cases to try. */ /* No finds for a long time and no test cases to try. */
if (cycles_wo_finds > 100 && !pending_not_fuzzed && min_wo_finds > 120) if (cycles_wo_finds > 100 && !pending_not_fuzzed && min_wo_finds > 120)
strcpy(tmp, cLGN); strcpy(tmp, cLGN);
/* Default: cautiously OK to stop? */ /* Default: cautiously OK to stop? */
else strcpy(tmp, cLBL); else
strcpy(tmp, cLBL);
} }
SAYF(bV bSTOP " run time : " cRST "%-33s " bSTG bV bSTOP SAYF(bV bSTOP " run time : " cRST "%-33s " bSTG bV bSTOP
" cycles done : %s%-5s " bSTG bV "\n", " cycles done : %s%-5s " bSTG bV "\n",
DTD(cur_ms, start_time), tmp, DI(queue_cycle - 1)); DTD(cur_ms, start_time), tmp, DI(queue_cycle - 1));
/* We want to warn people about not seeing new paths after a full cycle, /* We want to warn people about not seeing new paths after a full cycle,
except when resuming fuzzing or running in non-instrumented mode. */ except when resuming fuzzing or running in non-instrumented mode. */
if (!dumb_mode && (last_path_time || resuming_fuzz || queue_cycle == 1 || if (!dumb_mode && (last_path_time || resuming_fuzz || queue_cycle == 1 ||
in_bitmap || crash_mode)) { in_bitmap || crash_mode)) {
SAYF(bV bSTOP " last new path : " cRST "%-33s ", SAYF(bV bSTOP " last new path : " cRST "%-33s ",
DTD(cur_ms, last_path_time)); DTD(cur_ms, last_path_time));
@ -359,12 +375,12 @@ void show_stats(void) {
if (dumb_mode) if (dumb_mode)
SAYF(bV bSTOP " last new path : " cPIN "n/a" cRST SAYF(bV bSTOP " last new path : " cPIN "n/a" cRST
" (non-instrumented mode) "); " (non-instrumented mode) ");
else else
SAYF(bV bSTOP " last new path : " cRST "none yet " cLRD SAYF(bV bSTOP " last new path : " cRST "none yet " cLRD
"(odd, check syntax!) "); "(odd, check syntax!) ");
} }
@ -378,18 +394,18 @@ void show_stats(void) {
(unique_crashes >= KEEP_UNIQUE_CRASH) ? "+" : ""); (unique_crashes >= KEEP_UNIQUE_CRASH) ? "+" : "");
SAYF(bV bSTOP " last uniq crash : " cRST "%-33s " bSTG bV bSTOP SAYF(bV bSTOP " last uniq crash : " cRST "%-33s " bSTG bV bSTOP
" uniq crashes : %s%-6s" bSTG bV "\n", " uniq crashes : %s%-6s" bSTG bV "\n",
DTD(cur_ms, last_crash_time), unique_crashes ? cLRD : cRST, DTD(cur_ms, last_crash_time), unique_crashes ? cLRD : cRST, tmp);
tmp);
sprintf(tmp, "%s%s", DI(unique_hangs), sprintf(tmp, "%s%s", DI(unique_hangs),
(unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : ""); (unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
SAYF(bV bSTOP " last uniq hang : " cRST "%-33s " bSTG bV bSTOP SAYF(bV bSTOP " last uniq hang : " cRST "%-33s " bSTG bV bSTOP
" uniq hangs : " cRST "%-6s" bSTG bV "\n", " uniq hangs : " cRST "%-6s" bSTG bV "\n",
DTD(cur_ms, last_hang_time), tmp); DTD(cur_ms, last_hang_time), tmp);
SAYF(bVR bH bSTOP cCYA " cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA SAYF(bVR bH bSTOP cCYA
" cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA
" map coverage " bSTG bH bHT bH20 bH2 bVL "\n"); " map coverage " bSTG bH bHT bH20 bH2 bVL "\n");
/* This gets funny because we want to print several variable-length variables /* This gets funny because we want to print several variable-length variables
@ -402,23 +418,24 @@ void show_stats(void) {
SAYF(bV bSTOP " now processing : " cRST "%-16s " bSTG bV bSTOP, tmp); SAYF(bV bSTOP " now processing : " cRST "%-16s " bSTG bV bSTOP, tmp);
sprintf(tmp, "%0.02f%% / %0.02f%%", ((double)queue_cur->bitmap_size) * sprintf(tmp, "%0.02f%% / %0.02f%%",
100 / MAP_SIZE, t_byte_ratio); ((double)queue_cur->bitmap_size) * 100 / MAP_SIZE, t_byte_ratio);
SAYF(" map density : %s%-21s" bSTG bV "\n", t_byte_ratio > 70 ? cLRD : SAYF(" map density : %s%-21s" bSTG bV "\n",
((t_bytes < 200 && !dumb_mode) ? cPIN : cRST), tmp); t_byte_ratio > 70 ? cLRD : ((t_bytes < 200 && !dumb_mode) ? cPIN : cRST),
tmp);
sprintf(tmp, "%s (%0.02f%%)", DI(cur_skipped_paths), sprintf(tmp, "%s (%0.02f%%)", DI(cur_skipped_paths),
((double)cur_skipped_paths * 100) / queued_paths); ((double)cur_skipped_paths * 100) / queued_paths);
SAYF(bV bSTOP " paths timed out : " cRST "%-16s " bSTG bV, tmp); SAYF(bV bSTOP " paths timed out : " cRST "%-16s " bSTG bV, tmp);
sprintf(tmp, "%0.02f bits/tuple", sprintf(tmp, "%0.02f bits/tuple", t_bytes ? (((double)t_bits) / t_bytes) : 0);
t_bytes ? (((double)t_bits) / t_bytes) : 0);
SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp); SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp);
SAYF(bVR bH bSTOP cCYA " stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA SAYF(bVR bH bSTOP cCYA
" stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA
" findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n");
sprintf(tmp, "%s (%0.02f%%)", DI(queued_favored), sprintf(tmp, "%s (%0.02f%%)", DI(queued_favored),
@ -427,7 +444,8 @@ void show_stats(void) {
/* Yeah... it's still going on... halp? */ /* Yeah... it's still going on... halp? */
SAYF(bV bSTOP " now trying : " cRST "%-20s " bSTG bV bSTOP SAYF(bV bSTOP " now trying : " cRST "%-20s " bSTG bV bSTOP
" favored paths : " cRST "%-22s" bSTG bV "\n", stage_name, tmp); " favored paths : " cRST "%-22s" bSTG bV "\n",
stage_name, tmp);
if (!stage_max) { if (!stage_max) {
@ -453,14 +471,14 @@ void show_stats(void) {
if (crash_mode) { if (crash_mode) {
SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
" new crashes : %s%-22s" bSTG bV "\n", DI(total_execs), " new crashes : %s%-22s" bSTG bV "\n",
unique_crashes ? cLRD : cRST, tmp); DI(total_execs), unique_crashes ? cLRD : cRST, tmp);
} else { } else {
SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
" total crashes : %s%-22s" bSTG bV "\n", DI(total_execs), " total crashes : %s%-22s" bSTG bV "\n",
unique_crashes ? cLRD : cRST, tmp); DI(total_execs), unique_crashes ? cLRD : cRST, tmp);
} }
@ -468,8 +486,8 @@ void show_stats(void) {
if (avg_exec < 100) { if (avg_exec < 100) {
sprintf(tmp, "%s/sec (%s)", DF(avg_exec), avg_exec < 20 ? sprintf(tmp, "%s/sec (%s)", DF(avg_exec),
"zzzz..." : "slow!"); avg_exec < 20 ? "zzzz..." : "slow!");
SAYF(bV bSTOP " exec speed : " cLRD "%-20s ", tmp); SAYF(bV bSTOP " exec speed : " cLRD "%-20s ", tmp);
@ -483,12 +501,13 @@ void show_stats(void) {
sprintf(tmp, "%s (%s%s unique)", DI(total_tmouts), DI(unique_tmouts), sprintf(tmp, "%s (%s%s unique)", DI(total_tmouts), DI(unique_tmouts),
(unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : ""); (unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
SAYF (bSTG bV bSTOP " total tmouts : " cRST "%-22s" bSTG bV "\n", tmp); SAYF(bSTG bV bSTOP " total tmouts : " cRST "%-22s" bSTG bV "\n", tmp);
/* Aaaalmost there... hold on! */ /* Aaaalmost there... hold on! */
SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bHT bH10 SAYF(bVR bH cCYA bSTOP
bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA
" path geometry " bSTG bH5 bH2 bVL "\n");
if (skip_deterministic) { if (skip_deterministic) {
@ -496,66 +515,77 @@ void show_stats(void) {
} else { } else {
sprintf(tmp, "%s/%s, %s/%s, %s/%s", sprintf(tmp, "%s/%s, %s/%s, %s/%s", DI(stage_finds[STAGE_FLIP1]),
DI(stage_finds[STAGE_FLIP1]), DI(stage_cycles[STAGE_FLIP1]), DI(stage_cycles[STAGE_FLIP1]), DI(stage_finds[STAGE_FLIP2]),
DI(stage_finds[STAGE_FLIP2]), DI(stage_cycles[STAGE_FLIP2]), DI(stage_cycles[STAGE_FLIP2]), DI(stage_finds[STAGE_FLIP4]),
DI(stage_finds[STAGE_FLIP4]), DI(stage_cycles[STAGE_FLIP4])); DI(stage_cycles[STAGE_FLIP4]));
} }
SAYF(bV bSTOP " bit flips : " cRST "%-36s " bSTG bV bSTOP " levels : " SAYF(bV bSTOP " bit flips : " cRST "%-36s " bSTG bV bSTOP
cRST "%-10s" bSTG bV "\n", tmp, DI(max_depth)); " levels : " cRST "%-10s" bSTG bV "\n",
tmp, DI(max_depth));
if (!skip_deterministic) if (!skip_deterministic)
sprintf(tmp, "%s/%s, %s/%s, %s/%s", sprintf(tmp, "%s/%s, %s/%s, %s/%s", DI(stage_finds[STAGE_FLIP8]),
DI(stage_finds[STAGE_FLIP8]), DI(stage_cycles[STAGE_FLIP8]), DI(stage_cycles[STAGE_FLIP8]), DI(stage_finds[STAGE_FLIP16]),
DI(stage_finds[STAGE_FLIP16]), DI(stage_cycles[STAGE_FLIP16]), DI(stage_cycles[STAGE_FLIP16]), DI(stage_finds[STAGE_FLIP32]),
DI(stage_finds[STAGE_FLIP32]), DI(stage_cycles[STAGE_FLIP32])); DI(stage_cycles[STAGE_FLIP32]));
SAYF(bV bSTOP " byte flips : " cRST "%-36s " bSTG bV bSTOP " pending : " SAYF(bV bSTOP " byte flips : " cRST "%-36s " bSTG bV bSTOP
cRST "%-10s" bSTG bV "\n", tmp, DI(pending_not_fuzzed)); " pending : " cRST "%-10s" bSTG bV "\n",
tmp, DI(pending_not_fuzzed));
if (!skip_deterministic) if (!skip_deterministic)
sprintf(tmp, "%s/%s, %s/%s, %s/%s", sprintf(tmp, "%s/%s, %s/%s, %s/%s", DI(stage_finds[STAGE_ARITH8]),
DI(stage_finds[STAGE_ARITH8]), DI(stage_cycles[STAGE_ARITH8]), DI(stage_cycles[STAGE_ARITH8]), DI(stage_finds[STAGE_ARITH16]),
DI(stage_finds[STAGE_ARITH16]), DI(stage_cycles[STAGE_ARITH16]), DI(stage_cycles[STAGE_ARITH16]), DI(stage_finds[STAGE_ARITH32]),
DI(stage_finds[STAGE_ARITH32]), DI(stage_cycles[STAGE_ARITH32])); DI(stage_cycles[STAGE_ARITH32]));
SAYF(bV bSTOP " arithmetics : " cRST "%-36s " bSTG bV bSTOP " pend fav : " SAYF(bV bSTOP " arithmetics : " cRST "%-36s " bSTG bV bSTOP
cRST "%-10s" bSTG bV "\n", tmp, DI(pending_favored)); " pend fav : " cRST "%-10s" bSTG bV "\n",
tmp, DI(pending_favored));
if (!skip_deterministic) if (!skip_deterministic)
sprintf(tmp, "%s/%s, %s/%s, %s/%s", sprintf(
DI(stage_finds[STAGE_INTEREST8]), DI(stage_cycles[STAGE_INTEREST8]), tmp, "%s/%s, %s/%s, %s/%s", DI(stage_finds[STAGE_INTEREST8]),
DI(stage_finds[STAGE_INTEREST16]), DI(stage_cycles[STAGE_INTEREST16]), DI(stage_cycles[STAGE_INTEREST8]), DI(stage_finds[STAGE_INTEREST16]),
DI(stage_finds[STAGE_INTEREST32]), DI(stage_cycles[STAGE_INTEREST32])); DI(stage_cycles[STAGE_INTEREST16]), DI(stage_finds[STAGE_INTEREST32]),
DI(stage_cycles[STAGE_INTEREST32]));
SAYF(bV bSTOP " known ints : " cRST "%-36s " bSTG bV bSTOP " own finds : " SAYF(bV bSTOP " known ints : " cRST "%-36s " bSTG bV bSTOP
cRST "%-10s" bSTG bV "\n", tmp, DI(queued_discovered)); " own finds : " cRST "%-10s" bSTG bV "\n",
tmp, DI(queued_discovered));
if (!skip_deterministic) if (!skip_deterministic)
sprintf(tmp, "%s/%s, %s/%s, %s/%s", sprintf(tmp, "%s/%s, %s/%s, %s/%s", DI(stage_finds[STAGE_EXTRAS_UO]),
DI(stage_finds[STAGE_EXTRAS_UO]), DI(stage_cycles[STAGE_EXTRAS_UO]), DI(stage_cycles[STAGE_EXTRAS_UO]), DI(stage_finds[STAGE_EXTRAS_UI]),
DI(stage_finds[STAGE_EXTRAS_UI]), DI(stage_cycles[STAGE_EXTRAS_UI]), DI(stage_cycles[STAGE_EXTRAS_UI]), DI(stage_finds[STAGE_EXTRAS_AO]),
DI(stage_finds[STAGE_EXTRAS_AO]), DI(stage_cycles[STAGE_EXTRAS_AO])); DI(stage_cycles[STAGE_EXTRAS_AO]));
SAYF(bV bSTOP " dictionary : " cRST "%-36s " bSTG bV bSTOP SAYF(bV bSTOP " dictionary : " cRST "%-36s " bSTG bV bSTOP
" imported : " cRST "%-10s" bSTG bV "\n", tmp, " imported : " cRST "%-10s" bSTG bV "\n",
sync_id ? DI(queued_imported) : (u8*)"n/a"); tmp, sync_id ? DI(queued_imported) : (u8*)"n/a");
sprintf(tmp, "%s/%s, %s/%s, %s/%s", sprintf(tmp, "%s/%s, %s/%s, %s/%s", DI(stage_finds[STAGE_HAVOC]),
DI(stage_finds[STAGE_HAVOC]), DI(stage_cycles[STAGE_HAVOC]), DI(stage_cycles[STAGE_HAVOC]), DI(stage_finds[STAGE_SPLICE]),
DI(stage_finds[STAGE_SPLICE]), DI(stage_cycles[STAGE_SPLICE]), DI(stage_cycles[STAGE_SPLICE]), DI(stage_finds[STAGE_PYTHON]),
DI(stage_finds[STAGE_PYTHON]), DI(stage_cycles[STAGE_PYTHON])); DI(stage_cycles[STAGE_PYTHON]));
SAYF(bV bSTOP " havoc : " cRST "%-36s " bSTG bV bSTOP, tmp); SAYF(bV bSTOP " havoc : " cRST "%-36s " bSTG bV bSTOP, tmp);
if (t_bytes) sprintf(tmp, "%0.02f%%", stab_ratio); if (t_bytes)
else strcpy(tmp, "n/a"); 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) SAYF(" stability : %s%-10s" bSTG bV "\n",
? cLRD : ((queued_variable && (!persistent_mode || var_byte_count > 20)) (stab_ratio < 85 && var_byte_count > 40)
? cMGN : cRST), tmp); ? cLRD
: ((queued_variable && (!persistent_mode || var_byte_count > 20))
? cMGN
: cRST),
tmp);
if (!bytes_trim_out) { if (!bytes_trim_out) {
@ -582,18 +612,26 @@ void show_stats(void) {
sprintf(tmp2, "%0.02f%%", sprintf(tmp2, "%0.02f%%",
((double)(blocks_eff_total - blocks_eff_select)) * 100 / ((double)(blocks_eff_total - blocks_eff_select)) * 100 /
blocks_eff_total); blocks_eff_total);
strcat(tmp, tmp2); strcat(tmp, tmp2);
} }
if (custom_mutator) { if (custom_mutator) {
sprintf(tmp, "%s/%s", DI(stage_finds[STAGE_CUSTOM_MUTATOR]), DI(stage_cycles[STAGE_CUSTOM_MUTATOR]));
SAYF(bV bSTOP " custom mut. : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n" sprintf(tmp, "%s/%s", DI(stage_finds[STAGE_CUSTOM_MUTATOR]),
bLB bH30 bH20 bH2 bH bRB bSTOP cRST RESET_G1, tmp); DI(stage_cycles[STAGE_CUSTOM_MUTATOR]));
SAYF(bV bSTOP " custom mut. : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB
"\n" bLB bH30 bH20 bH2 bH bRB bSTOP cRST RESET_G1,
tmp);
} else { } else {
SAYF(bV bSTOP " trim : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n"
bLB bH30 bH20 bH2 bRB bSTOP cRST RESET_G1, tmp); SAYF(bV bSTOP " trim : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB
"\n" bLB bH30 bH20 bH2 bRB bSTOP cRST RESET_G1,
tmp);
} }
/* Provide some CPU utilization stats. */ /* Provide some CPU utilization stats. */
@ -601,7 +639,7 @@ void show_stats(void) {
if (cpu_core_count) { if (cpu_core_count) {
double cur_runnable = get_runnable_processes(); double cur_runnable = get_runnable_processes();
u32 cur_utilization = cur_runnable * 100 / cpu_core_count; u32 cur_utilization = cur_runnable * 100 / cpu_core_count;
u8* cpu_color = cCYA; u8* cpu_color = cCYA;
@ -618,25 +656,26 @@ void show_stats(void) {
if (cpu_aff >= 0) { if (cpu_aff >= 0) {
SAYF(SP10 cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, SAYF(SP10 cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, MIN(cpu_aff, 999),
MIN(cpu_aff, 999), cpu_color, cpu_color, MIN(cur_utilization, 999));
MIN(cur_utilization, 999));
} else { } else {
SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color,
cpu_color, MIN(cur_utilization, 999)); MIN(cur_utilization, 999));
} }
#else #else
SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color,
cpu_color, MIN(cur_utilization, 999)); MIN(cur_utilization, 999));
#endif /* ^HAVE_AFFINITY */ #endif /* ^HAVE_AFFINITY */
} else SAYF("\r"); } else
SAYF("\r");
/* Hallelujah! */ /* Hallelujah! */
@ -644,7 +683,6 @@ void show_stats(void) {
} }
/* Display quick statistics at the end of processing the input directory, /* Display quick statistics at the end of processing the input directory,
plus a bunch of warnings. Some calibration stuff also ended up here, plus a bunch of warnings. Some calibration stuff also ended up here,
along with several hardcoded constants. Maybe clean up eventually. */ along with several hardcoded constants. Maybe clean up eventually. */
@ -652,10 +690,10 @@ void show_stats(void) {
void show_init_stats(void) { void show_init_stats(void) {
struct queue_entry* q = queue; struct queue_entry* q = queue;
u32 min_bits = 0, max_bits = 0; u32 min_bits = 0, max_bits = 0;
u64 min_us = 0, max_us = 0; u64 min_us = 0, max_us = 0;
u64 avg_us = 0; u64 avg_us = 0;
u32 max_len = 0; u32 max_len = 0;
if (total_cal_cycles) avg_us = total_cal_us / total_cal_cycles; if (total_cal_cycles) avg_us = total_cal_us / total_cal_cycles;
@ -681,9 +719,12 @@ void show_init_stats(void) {
/* Let's keep things moving with slow binaries. */ /* Let's keep things moving with slow binaries. */
if (avg_us > 50000) havoc_div = 10; /* 0-19 execs/sec */ if (avg_us > 50000)
else if (avg_us > 20000) havoc_div = 5; /* 20-49 execs/sec */ havoc_div = 10; /* 0-19 execs/sec */
else if (avg_us > 10000) havoc_div = 2; /* 50-100 execs/sec */ else if (avg_us > 20000)
havoc_div = 5; /* 20-49 execs/sec */
else if (avg_us > 10000)
havoc_div = 2; /* 50-100 execs/sec */
if (!resuming_fuzz) { if (!resuming_fuzz) {
@ -698,7 +739,9 @@ void show_init_stats(void) {
WARNF(cLRD "Some test cases look useless. Consider using a smaller set."); WARNF(cLRD "Some test cases look useless. Consider using a smaller set.");
if (queued_paths > 100) if (queued_paths > 100)
WARNF(cLRD "You probably have far too many input files! Consider trimming down."); WARNF(cLRD
"You probably have far too many input files! Consider trimming "
"down.");
else if (queued_paths > 20) else if (queued_paths > 20)
WARNF("You have lots of input files; try starting small."); WARNF("You have lots of input files; try starting small.");
@ -706,11 +749,13 @@ void show_init_stats(void) {
OKF("Here are some useful stats:\n\n" OKF("Here are some useful stats:\n\n"
cGRA " Test case count : " cRST "%u favored, %u variable, %u total\n" cGRA " Test case count : " cRST
cGRA " Bitmap range : " cRST "%u to %u bits (average: %0.02f bits)\n" "%u favored, %u variable, %u total\n" cGRA " Bitmap range : " cRST
cGRA " Exec timing : " cRST "%s to %s us (average: %s us)\n", "%u to %u bits (average: %0.02f bits)\n" cGRA
queued_favored, queued_variable, queued_paths, min_bits, max_bits, " Exec timing : " cRST "%s to %s us (average: %s us)\n",
((double)total_bitmap_size) / (total_bitmap_entries ? total_bitmap_entries : 1), queued_favored, queued_variable, queued_paths, min_bits, max_bits,
((double)total_bitmap_size) /
(total_bitmap_entries ? total_bitmap_entries : 1),
DI(min_us), DI(max_us), DI(avg_us)); DI(min_us), DI(max_us), DI(avg_us));
if (!timeout_given) { if (!timeout_given) {
@ -722,16 +767,19 @@ void show_init_stats(void) {
random scheduler jitter is less likely to have any impact, and because random scheduler jitter is less likely to have any impact, and because
our patience is wearing thin =) */ our patience is wearing thin =) */
if (avg_us > 50000) exec_tmout = avg_us * 2 / 1000; if (avg_us > 50000)
else if (avg_us > 10000) exec_tmout = avg_us * 3 / 1000; exec_tmout = avg_us * 2 / 1000;
else exec_tmout = avg_us * 5 / 1000; else if (avg_us > 10000)
exec_tmout = avg_us * 3 / 1000;
else
exec_tmout = avg_us * 5 / 1000;
exec_tmout = MAX(exec_tmout, max_us / 1000); exec_tmout = MAX(exec_tmout, max_us / 1000);
exec_tmout = (exec_tmout + EXEC_TM_ROUND) / EXEC_TM_ROUND * EXEC_TM_ROUND; exec_tmout = (exec_tmout + EXEC_TM_ROUND) / EXEC_TM_ROUND * EXEC_TM_ROUND;
if (exec_tmout > EXEC_TIMEOUT) exec_tmout = EXEC_TIMEOUT; if (exec_tmout > EXEC_TIMEOUT) exec_tmout = EXEC_TIMEOUT;
ACTF("No -t option specified, so I'll use exec timeout of %u ms.", ACTF("No -t option specified, so I'll use exec timeout of %u ms.",
exec_tmout); exec_tmout);
timeout_given = 1; timeout_given = 1;

File diff suppressed because it is too large Load Diff

View File

@ -43,19 +43,18 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
static u8* as_path; /* Path to the AFL 'as' wrapper */ static u8* as_path; /* Path to the AFL 'as' wrapper */
static u8** cc_params; /* Parameters passed to the real CC */ static u8** cc_params; /* Parameters passed to the real CC */
static u32 cc_par_cnt = 1; /* Param count, including argv0 */ static u32 cc_par_cnt = 1; /* Param count, including argv0 */
static u8 be_quiet, /* Quiet mode */ static u8 be_quiet, /* Quiet mode */
clang_mode; /* Invoked as afl-clang*? */ clang_mode; /* Invoked as afl-clang*? */
/* Try to find our "fake" GNU assembler in AFL_PATH or at the location derived /* Try to find our "fake" GNU assembler in AFL_PATH or at the location derived
from argv[0]. If that fails, abort. */ from argv[0]. If that fails, abort. */
static void find_as(u8* argv0) { static void find_as(u8* argv0) {
u8 *afl_path = getenv("AFL_PATH"); u8* afl_path = getenv("AFL_PATH");
u8 *slash, *tmp; u8 *slash, *tmp;
if (afl_path) { if (afl_path) {
@ -63,9 +62,11 @@ static void find_as(u8* argv0) {
tmp = alloc_printf("%s/as", afl_path); tmp = alloc_printf("%s/as", afl_path);
if (!access(tmp, X_OK)) { if (!access(tmp, X_OK)) {
as_path = afl_path; as_path = afl_path;
ck_free(tmp); ck_free(tmp);
return; return;
} }
ck_free(tmp); ck_free(tmp);
@ -76,7 +77,7 @@ static void find_as(u8* argv0) {
if (slash) { if (slash) {
u8 *dir; u8* dir;
*slash = 0; *slash = 0;
dir = ck_strdup(argv0); dir = ck_strdup(argv0);
@ -85,9 +86,11 @@ static void find_as(u8* argv0) {
tmp = alloc_printf("%s/afl-as", dir); tmp = alloc_printf("%s/afl-as", dir);
if (!access(tmp, X_OK)) { if (!access(tmp, X_OK)) {
as_path = dir; as_path = dir;
ck_free(tmp); ck_free(tmp);
return; return;
} }
ck_free(tmp); ck_free(tmp);
@ -96,21 +99,22 @@ static void find_as(u8* argv0) {
} }
if (!access(AFL_PATH "/as", X_OK)) { if (!access(AFL_PATH "/as", X_OK)) {
as_path = AFL_PATH; as_path = AFL_PATH;
return; return;
} }
FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH"); FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH");
}
}
/* Copy argv to cc_params, making the necessary edits. */ /* Copy argv to cc_params, making the necessary edits. */
static void edit_params(u32 argc, char** argv) { static void edit_params(u32 argc, char** argv) {
u8 fortify_set = 0, asan_set = 0; u8 fortify_set = 0, asan_set = 0;
u8 *name; u8* name;
#if defined(__FreeBSD__) && defined(__x86_64__) #if defined(__FreeBSD__) && defined(__x86_64__)
u8 m32_set = 0; u8 m32_set = 0;
@ -119,7 +123,10 @@ static void edit_params(u32 argc, char** argv) {
cc_params = ck_alloc((argc + 128) * sizeof(u8*)); cc_params = ck_alloc((argc + 128) * sizeof(u8*));
name = strrchr(argv[0], '/'); name = strrchr(argv[0], '/');
if (!name) name = argv[0]; else name++; if (!name)
name = argv[0];
else
name++;
if (!strncmp(name, "afl-clang", 9)) { if (!strncmp(name, "afl-clang", 9)) {
@ -128,11 +135,15 @@ static void edit_params(u32 argc, char** argv) {
setenv(CLANG_ENV_VAR, "1", 1); setenv(CLANG_ENV_VAR, "1", 1);
if (!strcmp(name, "afl-clang++")) { if (!strcmp(name, "afl-clang++")) {
u8* alt_cxx = getenv("AFL_CXX"); u8* alt_cxx = getenv("AFL_CXX");
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++";
} else { } else {
u8* alt_cc = getenv("AFL_CC"); u8* alt_cc = getenv("AFL_CC");
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";
} }
} else { } else {
@ -145,16 +156,22 @@ static void edit_params(u32 argc, char** argv) {
#ifdef __APPLE__ #ifdef __APPLE__
if (!strcmp(name, "afl-g++")) cc_params[0] = getenv("AFL_CXX"); if (!strcmp(name, "afl-g++"))
else if (!strcmp(name, "afl-gcj")) cc_params[0] = getenv("AFL_GCJ"); cc_params[0] = getenv("AFL_CXX");
else cc_params[0] = getenv("AFL_CC"); else if (!strcmp(name, "afl-gcj"))
cc_params[0] = getenv("AFL_GCJ");
else
cc_params[0] = getenv("AFL_CC");
if (!cc_params[0]) { if (!cc_params[0]) {
SAYF("\n" cLRD "[-] " cRST SAYF("\n" cLRD "[-] " cRST
"On Apple systems, 'gcc' is usually just a wrapper for clang. Please use the\n" "On Apple systems, 'gcc' is usually just a wrapper for clang. "
" 'afl-clang' utility instead of 'afl-gcc'. If you really have GCC installed,\n" "Please use the\n"
" set AFL_CC or AFL_CXX to specify the correct path to that compiler.\n"); " 'afl-clang' utility instead of 'afl-gcc'. If you really have "
"GCC installed,\n"
" set AFL_CC or AFL_CXX to specify the correct path to that "
"compiler.\n");
FATAL("AFL_CC or AFL_CXX required on MacOS X"); FATAL("AFL_CC or AFL_CXX required on MacOS X");
@ -163,14 +180,20 @@ static void edit_params(u32 argc, char** argv) {
#else #else
if (!strcmp(name, "afl-g++")) { if (!strcmp(name, "afl-g++")) {
u8* alt_cxx = getenv("AFL_CXX"); u8* alt_cxx = getenv("AFL_CXX");
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"g++"; cc_params[0] = alt_cxx ? alt_cxx : (u8*)"g++";
} else if (!strcmp(name, "afl-gcj")) { } else if (!strcmp(name, "afl-gcj")) {
u8* alt_cc = getenv("AFL_GCJ"); u8* alt_cc = getenv("AFL_GCJ");
cc_params[0] = alt_cc ? alt_cc : (u8*)"gcj"; cc_params[0] = alt_cc ? alt_cc : (u8*)"gcj";
} else { } else {
u8* alt_cc = getenv("AFL_CC"); u8* alt_cc = getenv("AFL_CC");
cc_params[0] = alt_cc ? alt_cc : (u8*)"gcc"; cc_params[0] = alt_cc ? alt_cc : (u8*)"gcc";
} }
#endif /* __APPLE__ */ #endif /* __APPLE__ */
@ -178,13 +201,20 @@ static void edit_params(u32 argc, char** argv) {
} }
while (--argc) { while (--argc) {
u8* cur = *(++argv); u8* cur = *(++argv);
if (!strncmp(cur, "-B", 2)) { if (!strncmp(cur, "-B", 2)) {
if (!be_quiet) WARNF("-B is already set, overriding"); if (!be_quiet) WARNF("-B is already set, overriding");
if (!cur[2] && argc > 1) { argc--; argv++; } if (!cur[2] && argc > 1) {
argc--;
argv++;
}
continue; continue;
} }
@ -197,8 +227,8 @@ static void edit_params(u32 argc, char** argv) {
if (!strcmp(cur, "-m32")) m32_set = 1; if (!strcmp(cur, "-m32")) m32_set = 1;
#endif #endif
if (!strcmp(cur, "-fsanitize=address") || if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
!strcmp(cur, "-fsanitize=memory")) asan_set = 1; asan_set = 1;
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
@ -209,15 +239,13 @@ static void edit_params(u32 argc, char** argv) {
cc_params[cc_par_cnt++] = "-B"; cc_params[cc_par_cnt++] = "-B";
cc_params[cc_par_cnt++] = as_path; cc_params[cc_par_cnt++] = as_path;
if (clang_mode) if (clang_mode) cc_params[cc_par_cnt++] = "-no-integrated-as";
cc_params[cc_par_cnt++] = "-no-integrated-as";
if (getenv("AFL_HARDEN")) { if (getenv("AFL_HARDEN")) {
cc_params[cc_par_cnt++] = "-fstack-protector-all"; cc_params[cc_par_cnt++] = "-fstack-protector-all";
if (!fortify_set) if (!fortify_set) cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
} }
@ -229,8 +257,7 @@ static void edit_params(u32 argc, char** argv) {
} else if (getenv("AFL_USE_ASAN")) { } else if (getenv("AFL_USE_ASAN")) {
if (getenv("AFL_USE_MSAN")) if (getenv("AFL_USE_MSAN")) FATAL("ASAN and MSAN are mutually exclusive");
FATAL("ASAN and MSAN are mutually exclusive");
if (getenv("AFL_HARDEN")) if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive"); FATAL("ASAN and AFL_HARDEN are mutually exclusive");
@ -240,8 +267,7 @@ static void edit_params(u32 argc, char** argv) {
} else if (getenv("AFL_USE_MSAN")) { } else if (getenv("AFL_USE_MSAN")) {
if (getenv("AFL_USE_ASAN")) if (getenv("AFL_USE_ASAN")) FATAL("ASAN and MSAN are mutually exclusive");
FATAL("ASAN and MSAN are mutually exclusive");
if (getenv("AFL_HARDEN")) if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive"); FATAL("MSAN and AFL_HARDEN are mutually exclusive");
@ -249,11 +275,10 @@ static void edit_params(u32 argc, char** argv) {
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
cc_params[cc_par_cnt++] = "-fsanitize=memory"; cc_params[cc_par_cnt++] = "-fsanitize=memory";
} }
#ifdef USEMMAP #ifdef USEMMAP
cc_params[cc_par_cnt++] = "-lrt"; cc_params[cc_par_cnt++] = "-lrt";
#endif #endif
if (!getenv("AFL_DONT_OPTIMIZE")) { if (!getenv("AFL_DONT_OPTIMIZE")) {
@ -264,12 +289,11 @@ static void edit_params(u32 argc, char** argv) {
works OK. This has nothing to do with us, but let's avoid triggering works OK. This has nothing to do with us, but let's avoid triggering
that bug. */ that bug. */
if (!clang_mode || !m32_set) if (!clang_mode || !m32_set) cc_params[cc_par_cnt++] = "-g";
cc_params[cc_par_cnt++] = "-g";
#else #else
cc_params[cc_par_cnt++] = "-g"; cc_params[cc_par_cnt++] = "-g";
#endif #endif
@ -300,7 +324,6 @@ static void edit_params(u32 argc, char** argv) {
} }
/* Main entry point */ /* Main entry point */
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -308,23 +331,33 @@ int main(int argc, char** argv) {
if (isatty(2) && !getenv("AFL_QUIET")) { if (isatty(2) && !getenv("AFL_QUIET")) {
SAYF(cCYA "afl-cc" VERSION cRST " by <lcamtuf@google.com>\n"); SAYF(cCYA "afl-cc" VERSION cRST " by <lcamtuf@google.com>\n");
SAYF(cYEL "[!] " cBRI "NOTE: " cRST "afl-gcc is deprecated, llvm_mode is much faster and has more options\n"); SAYF(cYEL "[!] " cBRI "NOTE: " cRST
"afl-gcc is deprecated, llvm_mode is much faster and has more "
"options\n");
} else be_quiet = 1; } else
be_quiet = 1;
if (argc < 2) { if (argc < 2) {
SAYF("\n" SAYF(
"This is a helper application for afl-fuzz. It serves as a drop-in replacement\n" "\n"
"for gcc or clang, letting you recompile third-party code with the required\n" "This is a helper application for afl-fuzz. It serves as a drop-in "
"runtime instrumentation. A common use pattern would be one of the following:\n\n" "replacement\n"
"for gcc or clang, letting you recompile third-party code with the "
"required\n"
"runtime instrumentation. A common use pattern would be one of the "
"following:\n\n"
" CC=%s/afl-gcc ./configure\n" " CC=%s/afl-gcc ./configure\n"
" CXX=%s/afl-g++ ./configure\n\n" " CXX=%s/afl-g++ ./configure\n\n"
"You can specify custom next-stage toolchain via AFL_CC, AFL_CXX, and AFL_AS.\n" "You can specify custom next-stage toolchain via AFL_CC, AFL_CXX, and "
"Setting AFL_HARDEN enables hardening optimizations in the compiled code.\n\n", "AFL_AS.\n"
BIN_PATH, BIN_PATH); "Setting AFL_HARDEN enables hardening optimizations in the compiled "
"code.\n\n",
BIN_PATH, BIN_PATH);
exit(1); exit(1);
@ -341,3 +374,4 @@ int main(int argc, char** argv) {
return 0; return 0;
} }

View File

@ -31,7 +31,7 @@
#endif #endif
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "android-ashmem.h" # include "android-ashmem.h"
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -51,12 +51,11 @@
# define HAVE_AFFINITY 1 # define HAVE_AFFINITY 1
#endif /* __linux__ */ #endif /* __linux__ */
/* Get unix time in microseconds. */ /* Get unix time in microseconds. */
static u64 get_cur_time_us(void) { static u64 get_cur_time_us(void) {
struct timeval tv; struct timeval tv;
struct timezone tz; struct timezone tz;
gettimeofday(&tv, &tz); gettimeofday(&tv, &tz);
@ -65,7 +64,6 @@ static u64 get_cur_time_us(void) {
} }
/* Get CPU usage in microseconds. */ /* Get CPU usage in microseconds. */
static u64 get_cpu_usage_us(void) { static u64 get_cpu_usage_us(void) {
@ -79,7 +77,6 @@ static u64 get_cpu_usage_us(void) {
} }
/* Measure preemption rate. */ /* Measure preemption rate. */
static u32 measure_preemption(u32 target_ms) { static u32 measure_preemption(u32 target_ms) {
@ -96,14 +93,17 @@ repeat_loop:
v1 = CTEST_BUSY_CYCLES; v1 = CTEST_BUSY_CYCLES;
while (v1--) v2++; while (v1--)
v2++;
sched_yield(); sched_yield();
en_t = get_cur_time_us(); en_t = get_cur_time_us();
if (en_t - st_t < target_ms * 1000) { if (en_t - st_t < target_ms * 1000) {
loop_repeats++; loop_repeats++;
goto repeat_loop; goto repeat_loop;
} }
/* Let's see what percentage of this time we actually had a chance to /* Let's see what percentage of this time we actually had a chance to
@ -111,22 +111,20 @@ repeat_loop:
en_c = get_cpu_usage_us(); en_c = get_cpu_usage_us();
real_delta = (en_t - st_t) / 1000; real_delta = (en_t - st_t) / 1000;
slice_delta = (en_c - st_c) / 1000; slice_delta = (en_c - st_c) / 1000;
return real_delta * 100 / slice_delta; return real_delta * 100 / slice_delta;
} }
/* Do the benchmark thing. */ /* Do the benchmark thing. */
int main(int argc, char** argv) { int main(int argc, char** argv) {
#ifdef HAVE_AFFINITY #ifdef HAVE_AFFINITY
u32 cpu_cnt = sysconf(_SC_NPROCESSORS_ONLN), u32 cpu_cnt = sysconf(_SC_NPROCESSORS_ONLN), idle_cpus = 0, maybe_cpus = 0, i;
idle_cpus = 0, maybe_cpus = 0, i;
SAYF(cCYA "afl-gotcpu" VERSION cRST " by <lcamtuf@google.com>\n"); SAYF(cCYA "afl-gotcpu" VERSION cRST " by <lcamtuf@google.com>\n");
@ -142,7 +140,7 @@ int main(int argc, char** argv) {
if (!fr) { if (!fr) {
cpu_set_t c; cpu_set_t c;
u32 util_perc; u32 util_perc;
CPU_ZERO(&c); CPU_ZERO(&c);
CPU_SET(i, &c); CPU_SET(i, &c);
@ -159,7 +157,7 @@ int main(int argc, char** argv) {
} else if (util_perc < 250) { } else if (util_perc < 250) {
SAYF(" Core #%u: " cYEL "CAUTION " cRST "(%u%%)\n", i, util_perc); SAYF(" Core #%u: " cYEL "CAUTION " cRST "(%u%%)\n", i, util_perc);
exit(1); exit(1);
} }
@ -255,3 +253,4 @@ int main(int argc, char** argv) {
#endif /* ^HAVE_AFFINITY */ #endif /* ^HAVE_AFFINITY */
} }

View File

@ -5,7 +5,7 @@
#define AFL_MAIN #define AFL_MAIN
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "android-ashmem.h" # include "android-ashmem.h"
#endif #endif
#include "config.h" #include "config.h"
#include "types.h" #include "types.h"
@ -32,68 +32,79 @@
#include <sys/mman.h> #include <sys/mman.h>
#ifndef USEMMAP #ifndef USEMMAP
#include <sys/ipc.h> # include <sys/ipc.h>
#include <sys/shm.h> # include <sys/shm.h>
#endif #endif
extern unsigned char*trace_bits; extern unsigned char *trace_bits;
#ifdef USEMMAP #ifdef USEMMAP
/* ================ Proteas ================ */ /* ================ Proteas ================ */
int g_shm_fd = -1; int g_shm_fd = -1;
unsigned char *g_shm_base = NULL; unsigned char *g_shm_base = NULL;
char g_shm_file_path[L_tmpnam]; char g_shm_file_path[L_tmpnam];
/* ========================================= */ /* ========================================= */
#else #else
static s32 shm_id; /* ID of the SHM region */ static s32 shm_id; /* ID of the SHM region */
#endif #endif
/* Get rid of shared memory (atexit handler). */ /* Get rid of shared memory (atexit handler). */
void remove_shm(void) { void remove_shm(void) {
#ifdef USEMMAP #ifdef USEMMAP
if (g_shm_base != NULL) { if (g_shm_base != NULL) {
munmap(g_shm_base, MAP_SIZE); munmap(g_shm_base, MAP_SIZE);
g_shm_base = NULL; g_shm_base = NULL;
} }
if (g_shm_fd != -1) { if (g_shm_fd != -1) {
close(g_shm_fd); close(g_shm_fd);
g_shm_fd = -1; g_shm_fd = -1;
} }
#else #else
shmctl(shm_id, IPC_RMID, NULL); shmctl(shm_id, IPC_RMID, NULL);
#endif #endif
}
}
/* Configure shared memory. */ /* Configure shared memory. */
void setup_shm(unsigned char dumb_mode) { void setup_shm(unsigned char dumb_mode) {
#ifdef USEMMAP #ifdef USEMMAP
/* generate random file name for multi instance */ /* generate random file name for multi instance */
/* thanks to f*cking glibc we can not use tmpnam securely, it generates a security warning that cannot be suppressed */ /* thanks to f*cking glibc we can not use tmpnam securely, it generates a
* security warning that cannot be suppressed */
/* so we do this worse workaround */ /* so we do this worse workaround */
snprintf(g_shm_file_path, L_tmpnam, "/afl_%d_%ld", getpid(), random()); snprintf(g_shm_file_path, L_tmpnam, "/afl_%d_%ld", getpid(), random());
/* create the shared memory segment as if it was a file */ /* create the shared memory segment as if it was a file */
g_shm_fd = shm_open(g_shm_file_path, O_CREAT | O_RDWR | O_EXCL, 0600); g_shm_fd = shm_open(g_shm_file_path, O_CREAT | O_RDWR | O_EXCL, 0600);
if (g_shm_fd == -1) { if (g_shm_fd == -1) { PFATAL("shm_open() failed"); }
PFATAL("shm_open() failed");
}
/* configure the size of the shared memory segment */ /* configure the size of the shared memory segment */
if (ftruncate(g_shm_fd, MAP_SIZE)) { if (ftruncate(g_shm_fd, MAP_SIZE)) {
PFATAL("setup_shm(): ftruncate() failed"); PFATAL("setup_shm(): ftruncate() failed");
} }
/* map the shared memory segment to the address space of the process */ /* map the shared memory segment to the address space of the process */
g_shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, g_shm_fd, 0); g_shm_base =
mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, g_shm_fd, 0);
if (g_shm_base == MAP_FAILED) { if (g_shm_base == MAP_FAILED) {
close(g_shm_fd); close(g_shm_fd);
g_shm_fd = -1; g_shm_fd = -1;
PFATAL("mmap() failed"); PFATAL("mmap() failed");
} }
atexit(remove_shm); atexit(remove_shm);
@ -108,7 +119,7 @@ void setup_shm(unsigned char dumb_mode) {
trace_bits = g_shm_base; trace_bits = g_shm_base;
if (!trace_bits) PFATAL("mmap() failed"); if (!trace_bits) PFATAL("mmap() failed");
#else #else
u8* shm_str; u8* shm_str;
@ -132,9 +143,10 @@ void setup_shm(unsigned char dumb_mode) {
ck_free(shm_str); ck_free(shm_str);
trace_bits = shmat(shm_id, NULL, 0); trace_bits = shmat(shm_id, NULL, 0);
if (!trace_bits) PFATAL("shmat() failed"); if (!trace_bits) PFATAL("shmat() failed");
#endif #endif
} }

View File

@ -24,7 +24,7 @@
#define AFL_MAIN #define AFL_MAIN
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "android-ashmem.h" # include "android-ashmem.h"
#endif #endif
#include "config.h" #include "config.h"
#include "types.h" #include "types.h"
@ -51,61 +51,54 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/resource.h> #include <sys/resource.h>
static s32 child_pid; /* PID of the tested program */ static s32 child_pid; /* PID of the tested program */
u8* trace_bits; /* SHM with instrumentation bitmap */ u8* trace_bits; /* SHM with instrumentation bitmap */
static u8 *out_file, /* Trace output file */ static u8 *out_file, /* Trace output file */
*doc_path, /* Path to docs */ *doc_path, /* Path to docs */
*target_path, /* Path to target binary */ *target_path, /* Path to target binary */
*at_file; /* Substitution string for @@ */ *at_file; /* Substitution string for @@ */
static u32 exec_tmout; /* Exec timeout (ms) */ static u32 exec_tmout; /* Exec timeout (ms) */
static u32 total, highest; /* tuple content information */ static u32 total, highest; /* tuple content information */
static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
static u8 quiet_mode, /* Hide non-essential messages? */ static u8 quiet_mode, /* Hide non-essential messages? */
edges_only, /* Ignore hit counts? */ edges_only, /* Ignore hit counts? */
raw_instr_output, /* Do not apply AFL filters */ raw_instr_output, /* Do not apply AFL filters */
cmin_mode, /* Generate output in afl-cmin mode? */ cmin_mode, /* Generate output in afl-cmin mode? */
binary_mode, /* Write output as a binary map */ binary_mode, /* Write output as a binary map */
keep_cores; /* Allow coredumps? */ keep_cores; /* Allow coredumps? */
static volatile u8 static volatile u8 stop_soon, /* Ctrl-C pressed? */
stop_soon, /* Ctrl-C pressed? */ child_timed_out, /* Child timed out? */
child_timed_out, /* Child timed out? */ child_crashed; /* Child crashed? */
child_crashed; /* Child crashed? */
/* Classify tuple counts. Instead of mapping to individual bits, as in /* Classify tuple counts. Instead of mapping to individual bits, as in
afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */ afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
static const u8 count_class_human[256] = { static const u8 count_class_human[256] = {
[0] = 0, [0] = 0, [1] = 1, [2] = 2, [3] = 3,
[1] = 1, [4 ... 7] = 4, [8 ... 15] = 5, [16 ... 31] = 6, [32 ... 127] = 7,
[2] = 2, [128 ... 255] = 8
[3] = 3,
[4 ... 7] = 4,
[8 ... 15] = 5,
[16 ... 31] = 6,
[32 ... 127] = 7,
[128 ... 255] = 8
}; };
static const u8 count_class_binary[256] = { static const u8 count_class_binary[256] = {
[0] = 0, [0] = 0,
[1] = 1, [1] = 1,
[2] = 2, [2] = 2,
[3] = 4, [3] = 4,
[4 ... 7] = 8, [4 ... 7] = 8,
[8 ... 15] = 16, [8 ... 15] = 16,
[16 ... 31] = 32, [16 ... 31] = 32,
[32 ... 127] = 64, [32 ... 127] = 64,
[128 ... 255] = 128 [128 ... 255] = 128
}; };
@ -116,22 +109,25 @@ static void classify_counts(u8* mem, const u8* map) {
if (edges_only) { if (edges_only) {
while (i--) { while (i--) {
if (*mem) *mem = 1; if (*mem) *mem = 1;
mem++; mem++;
} }
} else if (!raw_instr_output) { } else if (!raw_instr_output) {
while (i--) { while (i--) {
*mem = map[*mem]; *mem = map[*mem];
mem++; mem++;
} }
} }
} }
/* Write results. */ /* Write results. */
static u32 write_results(void) { static u32 write_results(void) {
@ -139,8 +135,8 @@ static u32 write_results(void) {
s32 fd; s32 fd;
u32 i, ret = 0; u32 i, ret = 0;
u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"), u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"),
caa = !!getenv("AFL_CMIN_ALLOW_ANY"); caa = !!getenv("AFL_CMIN_ALLOW_ANY");
if (!strncmp(out_file, "/dev/", 5)) { if (!strncmp(out_file, "/dev/", 5)) {
@ -154,7 +150,7 @@ static u32 write_results(void) {
} else { } else {
unlink(out_file); /* Ignore errors */ unlink(out_file); /* Ignore errors */
fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600); fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) PFATAL("Unable to create '%s'", out_file); if (fd < 0) PFATAL("Unable to create '%s'", out_file);
@ -164,7 +160,7 @@ static u32 write_results(void) {
for (i = 0; i < MAP_SIZE; i++) for (i = 0; i < MAP_SIZE; i++)
if (trace_bits[i]) ret++; if (trace_bits[i]) ret++;
ck_write(fd, trace_bits, MAP_SIZE, out_file); ck_write(fd, trace_bits, MAP_SIZE, out_file);
close(fd); close(fd);
@ -178,10 +174,9 @@ static u32 write_results(void) {
if (!trace_bits[i]) continue; if (!trace_bits[i]) continue;
ret++; ret++;
total += trace_bits[i]; total += trace_bits[i];
if (highest < trace_bits[i]) if (highest < trace_bits[i]) highest = trace_bits[i];
highest = trace_bits[i];
if (cmin_mode) { if (cmin_mode) {
@ -190,10 +185,12 @@ static u32 write_results(void) {
fprintf(f, "%u%u\n", trace_bits[i], i); fprintf(f, "%u%u\n", trace_bits[i], i);
} else fprintf(f, "%06u:%u\n", i, trace_bits[i]); } else
fprintf(f, "%06u:%u\n", i, trace_bits[i]);
} }
fclose(f); fclose(f);
} }
@ -202,7 +199,6 @@ static u32 write_results(void) {
} }
/* Handle timeout signal. */ /* Handle timeout signal. */
static void handle_timeout(int sig) { static void handle_timeout(int sig) {
@ -212,16 +208,14 @@ static void handle_timeout(int sig) {
} }
/* Execute target application. */ /* Execute target application. */
static void run_target(char** argv) { static void run_target(char** argv) {
static struct itimerval it; static struct itimerval it;
int status = 0; int status = 0;
if (!quiet_mode) if (!quiet_mode) SAYF("-- Program output begins --\n" cRST);
SAYF("-- Program output begins --\n" cRST);
MEM_BARRIER(); MEM_BARRIER();
@ -238,8 +232,10 @@ static void run_target(char** argv) {
s32 fd = open("/dev/null", O_RDWR); s32 fd = open("/dev/null", O_RDWR);
if (fd < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) { if (fd < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) {
*(u32*)trace_bits = EXEC_FAIL_SIG; *(u32*)trace_bits = EXEC_FAIL_SIG;
PFATAL("Descriptor initialization failed"); PFATAL("Descriptor initialization failed");
} }
close(fd); close(fd);
@ -252,20 +248,22 @@ static void run_target(char** argv) {
#ifdef RLIMIT_AS #ifdef RLIMIT_AS
setrlimit(RLIMIT_AS, &r); /* Ignore errors */ setrlimit(RLIMIT_AS, &r); /* Ignore errors */
#else #else
setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
#endif /* ^RLIMIT_AS */ #endif /* ^RLIMIT_AS */
} }
if (!keep_cores) r.rlim_max = r.rlim_cur = 0; if (!keep_cores)
else r.rlim_max = r.rlim_cur = RLIM_INFINITY; r.rlim_max = r.rlim_cur = 0;
else
r.rlim_max = r.rlim_cur = RLIM_INFINITY;
setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0);
@ -304,14 +302,12 @@ static void run_target(char** argv) {
if (*(u32*)trace_bits == EXEC_FAIL_SIG) if (*(u32*)trace_bits == EXEC_FAIL_SIG)
FATAL("Unable to execute '%s'", argv[0]); FATAL("Unable to execute '%s'", argv[0]);
classify_counts(trace_bits, binary_mode ? classify_counts(trace_bits,
count_class_binary : count_class_human); binary_mode ? count_class_binary : count_class_human);
if (!quiet_mode) if (!quiet_mode) SAYF(cRST "-- Program output ends --\n");
SAYF(cRST "-- Program output ends --\n");
if (!child_timed_out && !stop_soon && WIFSIGNALED(status)) if (!child_timed_out && !stop_soon && WIFSIGNALED(status)) child_crashed = 1;
child_crashed = 1;
if (!quiet_mode) { if (!quiet_mode) {
@ -320,14 +316,13 @@ static void run_target(char** argv) {
else if (stop_soon) else if (stop_soon)
SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST); SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST);
else if (child_crashed) else if (child_crashed)
SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST, WTERMSIG(status)); SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST,
WTERMSIG(status));
} }
} }
/* Handle Ctrl-C and the like. */ /* Handle Ctrl-C and the like. */
static void handle_stop_sig(int sig) { static void handle_stop_sig(int sig) {
@ -338,15 +333,16 @@ static void handle_stop_sig(int sig) {
} }
/* Do basic preparations - persistent fds, filenames, etc. */ /* Do basic preparations - persistent fds, filenames, etc. */
static void set_up_environment(void) { static void set_up_environment(void) {
setenv("ASAN_OPTIONS", "abort_on_error=1:" setenv("ASAN_OPTIONS",
"detect_leaks=0:" "abort_on_error=1:"
"symbolize=0:" "detect_leaks=0:"
"allocator_may_return_null=1", 0); "symbolize=0:"
"allocator_may_return_null=1",
0);
setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
"symbolize=0:" "symbolize=0:"
@ -355,21 +351,22 @@ static void set_up_environment(void) {
"msan_track_origins=0", 0); "msan_track_origins=0", 0);
if (getenv("AFL_PRELOAD")) { if (getenv("AFL_PRELOAD")) {
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
} }
} }
/* Setup signal handlers, duh. */ /* Setup signal handlers, duh. */
static void setup_signal_handlers(void) { static void setup_signal_handlers(void) {
struct sigaction sa; struct sigaction sa;
sa.sa_handler = NULL; sa.sa_handler = NULL;
sa.sa_flags = SA_RESTART; sa.sa_flags = SA_RESTART;
sa.sa_sigaction = NULL; sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
@ -388,7 +385,6 @@ static void setup_signal_handlers(void) {
} }
/* Show banner. */ /* Show banner. */
static void show_banner(void) { static void show_banner(void) {
@ -403,42 +399,43 @@ static void usage(u8* argv0) {
show_banner(); show_banner();
SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" SAYF(
"\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
"Required parameters:\n\n" "Required parameters:\n\n"
" -o file - file to write the trace data to\n\n" " -o file - file to write the trace data to\n\n"
"Execution control settings:\n\n" "Execution control settings:\n\n"
" -t msec - timeout for each run (none)\n" " -t msec - timeout for each run (none)\n"
" -m megs - memory limit for child process (%d MB)\n" " -m megs - memory limit for child process (%d MB)\n"
" -Q - use binary-only instrumentation (QEMU mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n"
" -U - use Unicorn-based instrumentation (Unicorn mode)\n" " -U - use Unicorn-based instrumentation (Unicorn mode)\n"
" (Not necessary, here for consistency with other afl-* tools)\n\n" " (Not necessary, here for consistency with other afl-* "
"tools)\n\n"
"Other settings:\n\n" "Other settings:\n\n"
" -q - sink program's output and don't show messages\n" " -q - sink program's output and don't show messages\n"
" -e - show edge coverage only, ignore hit counts\n" " -e - show edge coverage only, ignore hit counts\n"
" -r - show real tuple values instead of AFL filter values\n" " -r - show real tuple values instead of AFL filter values\n"
" -c - allow core dumps\n\n" " -c - allow core dumps\n\n"
"This tool displays raw tuple data captured by AFL instrumentation.\n" "This tool displays raw tuple data captured by AFL instrumentation.\n"
"For additional help, consult %s/README.\n\n" cRST, "For additional help, consult %s/README.\n\n" cRST,
argv0, MEM_LIMIT, doc_path); argv0, MEM_LIMIT, doc_path);
exit(1); exit(1);
} }
/* Find binary. */ /* Find binary. */
static void find_binary(u8* fname) { static void find_binary(u8* fname) {
u8* env_path = 0; u8* env_path = 0;
struct stat st; struct stat st;
if (strchr(fname, '/') || !(env_path = getenv("PATH"))) { if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
@ -461,7 +458,9 @@ static void find_binary(u8* fname) {
memcpy(cur_elem, env_path, delim - env_path); memcpy(cur_elem, env_path, delim - env_path);
delim++; delim++;
} else cur_elem = ck_strdup(env_path); } else
cur_elem = ck_strdup(env_path);
env_path = delim; env_path = delim;
@ -473,7 +472,8 @@ static void find_binary(u8* fname) {
ck_free(cur_elem); ck_free(cur_elem);
if (!stat(target_path, &st) && S_ISREG(st.st_mode) && if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
(st.st_mode & 0111) && st.st_size >= 4) break; (st.st_mode & 0111) && st.st_size >= 4)
break;
ck_free(target_path); ck_free(target_path);
target_path = 0; target_path = 0;
@ -486,13 +486,12 @@ static void find_binary(u8* fname) {
} }
/* Fix up argv for QEMU. */ /* Fix up argv for QEMU. */
static char** get_qemu_argv(u8* own_loc, char** argv, int argc) { static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
u8 *tmp, *cp, *rsl, *own_copy; u8 * tmp, *cp, *rsl, *own_copy;
memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc); memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
@ -507,8 +506,7 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
cp = alloc_printf("%s/afl-qemu-trace", tmp); cp = alloc_printf("%s/afl-qemu-trace", tmp);
if (access(cp, X_OK)) if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
FATAL("Unable to find '%s'", tmp);
target_path = new_argv[0] = cp; target_path = new_argv[0] = cp;
return new_argv; return new_argv;
@ -532,7 +530,9 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
} }
} else ck_free(own_copy); } else
ck_free(own_copy);
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) { if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
@ -556,7 +556,7 @@ int main(int argc, char** argv) {
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
while ((opt = getopt(argc,argv,"+o:m:t:A:eqZQUbcr")) > 0) while ((opt = getopt(argc, argv, "+o:m:t:A:eqZQUbcr")) > 0)
switch (opt) { switch (opt) {
@ -568,40 +568,41 @@ int main(int argc, char** argv) {
case 'm': { case 'm': {
u8 suffix = 'M'; u8 suffix = 'M';
if (mem_limit_given) FATAL("Multiple -m options not supported"); if (mem_limit_given) FATAL("Multiple -m options not supported");
mem_limit_given = 1; mem_limit_given = 1;
if (!strcmp(optarg, "none")) { if (!strcmp(optarg, "none")) {
mem_limit = 0; mem_limit = 0;
break; break;
}
if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
optarg[0] == '-') FATAL("Bad syntax used for -m");
switch (suffix) {
case 'T': mem_limit *= 1024 * 1024; break;
case 'G': mem_limit *= 1024; break;
case 'k': mem_limit /= 1024; break;
case 'M': break;
default: FATAL("Unsupported suffix or bad syntax for -m");
}
if (mem_limit < 5) FATAL("Dangerously low value of -m");
if (sizeof(rlim_t) == 4 && mem_limit > 2000)
FATAL("Value of -m out of range on 32-bit systems");
} }
break; if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
optarg[0] == '-')
FATAL("Bad syntax used for -m");
switch (suffix) {
case 'T': mem_limit *= 1024 * 1024; break;
case 'G': mem_limit *= 1024; break;
case 'k': mem_limit /= 1024; break;
case 'M': break;
default: FATAL("Unsupported suffix or bad syntax for -m");
}
if (mem_limit < 5) FATAL("Dangerously low value of -m");
if (sizeof(rlim_t) == 4 && mem_limit > 2000)
FATAL("Value of -m out of range on 32-bit systems");
}
break;
case 't': case 't':
@ -609,6 +610,7 @@ int main(int argc, char** argv) {
timeout_given = 1; timeout_given = 1;
if (strcmp(optarg, "none")) { if (strcmp(optarg, "none")) {
exec_tmout = atoi(optarg); exec_tmout = atoi(optarg);
if (exec_tmout < 20 || optarg[0] == '-') if (exec_tmout < 20 || optarg[0] == '-')
@ -636,7 +638,7 @@ int main(int argc, char** argv) {
/* This is an undocumented option to write data in the syntax expected /* This is an undocumented option to write data in the syntax expected
by afl-cmin. Nobody else should have any use for this. */ by afl-cmin. Nobody else should have any use for this. */
cmin_mode = 1; cmin_mode = 1;
quiet_mode = 1; quiet_mode = 1;
break; break;
@ -675,7 +677,7 @@ int main(int argc, char** argv) {
if (keep_cores) FATAL("Multiple -c options not supported"); if (keep_cores) FATAL("Multiple -c options not supported");
keep_cores = 1; keep_cores = 1;
break; break;
case 'r': case 'r':
if (raw_instr_output) FATAL("Multiple -r options not supported"); if (raw_instr_output) FATAL("Multiple -r options not supported");
@ -683,9 +685,7 @@ int main(int argc, char** argv) {
raw_instr_output = 1; raw_instr_output = 1;
break; break;
default: default: usage(argv[0]);
usage(argv[0]);
} }
@ -699,8 +699,10 @@ int main(int argc, char** argv) {
find_binary(argv[optind]); find_binary(argv[optind]);
if (!quiet_mode) { if (!quiet_mode) {
show_banner(); show_banner();
ACTF("Executing '%s'...\n", target_path); ACTF("Executing '%s'...\n", target_path);
} }
detect_file_args(argv + optind, at_file); detect_file_args(argv + optind, at_file);
@ -717,7 +719,8 @@ int main(int argc, char** argv) {
if (!quiet_mode) { if (!quiet_mode) {
if (!tcnt) FATAL("No instrumentation detected" cRST); if (!tcnt) FATAL("No instrumentation detected" cRST);
OKF("Captured %u tuples (highest value %u, total values %u) in '%s'." cRST, tcnt, highest, total, out_file); OKF("Captured %u tuples (highest value %u, total values %u) in '%s'." cRST,
tcnt, highest, total, out_file);
} }

View File

@ -22,7 +22,7 @@
#define AFL_MAIN #define AFL_MAIN
#ifdef __ANDROID__ #ifdef __ANDROID__
#include "android-ashmem.h" # include "android-ashmem.h"
#endif #endif
#include "config.h" #include "config.h"
@ -51,72 +51,71 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/resource.h> #include <sys/resource.h>
s32 forksrv_pid, /* PID of the fork server */ s32 forksrv_pid, /* PID of the fork server */
child_pid; /* PID of the tested program */ child_pid; /* PID of the tested program */
s32 fsrv_ctl_fd, /* Fork server control pipe (write) */ s32 fsrv_ctl_fd, /* Fork server control pipe (write) */
fsrv_st_fd; /* Fork server status pipe (read) */ fsrv_st_fd; /* Fork server status pipe (read) */
u8 *trace_bits; /* SHM with instrumentation bitmap */ u8* trace_bits; /* SHM with instrumentation bitmap */
static u8 *mask_bitmap; /* Mask for trace bits (-B) */ static u8* mask_bitmap; /* Mask for trace bits (-B) */
u8 *in_file, /* Minimizer input test case */ u8 *in_file, /* Minimizer input test case */
*output_file, /* Minimizer output file */ *output_file, /* Minimizer output file */
*out_file, /* Targeted program input file */ *out_file, /* Targeted program input file */
*target_path, /* Path to target binary */ *target_path, /* Path to target binary */
*doc_path; /* Path to docs */ *doc_path; /* Path to docs */
s32 out_fd; /* Persistent fd for out_file */ s32 out_fd; /* Persistent fd for out_file */
static u8* in_data; /* Input data for trimming */ static u8* in_data; /* Input data for trimming */
static u32 in_len, /* Input data length */ static u32 in_len, /* Input data length */
orig_cksum, /* Original checksum */ orig_cksum, /* Original checksum */
total_execs, /* Total number of execs */ total_execs, /* Total number of execs */
missed_hangs, /* Misses due to hangs */ missed_hangs, /* Misses due to hangs */
missed_crashes, /* Misses due to crashes */ missed_crashes, /* Misses due to crashes */
missed_paths; /* Misses due to exec path diffs */ missed_paths; /* Misses due to exec path diffs */
u32 exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */ u32 exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */
u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
s32 dev_null_fd = -1; /* FD to /dev/null */ s32 dev_null_fd = -1; /* FD to /dev/null */
static u8 crash_mode, /* Crash-centric mode? */ static u8 crash_mode, /* Crash-centric mode? */
exit_crash, /* Treat non-zero exit as crash? */ exit_crash, /* Treat non-zero exit as crash? */
edges_only, /* Ignore hit counts? */ edges_only, /* Ignore hit counts? */
exact_mode, /* Require path match for crashes? */ exact_mode, /* Require path match for crashes? */
use_stdin = 1; /* Use stdin for program input? */ use_stdin = 1; /* Use stdin for program input? */
static volatile u8 static volatile u8 stop_soon; /* Ctrl-C pressed? */
stop_soon; /* Ctrl-C pressed? */
/* /*
* forkserver section * forkserver section
*/ */
/* we only need this to use afl-forkserver */ /* we only need this to use afl-forkserver */
FILE *plot_file; FILE* plot_file;
u8 uses_asan; u8 uses_asan;
s32 out_fd = -1, out_dir_fd = -1, dev_urandom_fd = -1; s32 out_fd = -1, out_dir_fd = -1, dev_urandom_fd = -1;
/* we import this as we need this information */ /* we import this as we need this information */
extern u8 child_timed_out; extern u8 child_timed_out;
/* Classify tuple counts. This is a slow & naive version, but good enough here.
/* Classify tuple counts. This is a slow & naive version, but good enough here. */ */
static const u8 count_class_lookup[256] = { static const u8 count_class_lookup[256] = {
[0] = 0, [0] = 0,
[1] = 1, [1] = 1,
[2] = 2, [2] = 2,
[3] = 4, [3] = 4,
[4 ... 7] = 8, [4 ... 7] = 8,
[8 ... 15] = 16, [8 ... 15] = 16,
[16 ... 31] = 32, [16 ... 31] = 32,
[32 ... 127] = 64, [32 ... 127] = 64,
[128 ... 255] = 128 [128 ... 255] = 128
}; };
@ -127,22 +126,25 @@ static void classify_counts(u8* mem) {
if (edges_only) { if (edges_only) {
while (i--) { while (i--) {
if (*mem) *mem = 1; if (*mem) *mem = 1;
mem++; mem++;
} }
} else { } else {
while (i--) { while (i--) {
*mem = count_class_lookup[*mem]; *mem = count_class_lookup[*mem];
mem++; mem++;
} }
} }
} }
/* Apply mask to classified bitmap (if set). */ /* Apply mask to classified bitmap (if set). */
static void apply_mask(u32* mem, u32* mask) { static void apply_mask(u32* mem, u32* mask) {
@ -161,25 +163,26 @@ static void apply_mask(u32* mem, u32* mask) {
} }
/* See if any bytes are set in the bitmap. */ /* See if any bytes are set in the bitmap. */
static inline u8 anything_set(void) { static inline u8 anything_set(void) {
u32* ptr = (u32*)trace_bits; u32* ptr = (u32*)trace_bits;
u32 i = (MAP_SIZE >> 2); u32 i = (MAP_SIZE >> 2);
while (i--) if (*(ptr++)) return 1; while (i--)
if (*(ptr++)) return 1;
return 0; return 0;
} }
/* Get rid of temp files (atexit handler). */ /* Get rid of temp files (atexit handler). */
static void at_exit_handler(void) { static void at_exit_handler(void) {
if (out_file) unlink(out_file); /* Ignore errors */
if (out_file) unlink(out_file); /* Ignore errors */
} }
/* Read initial file. */ /* Read initial file. */
@ -187,17 +190,16 @@ static void at_exit_handler(void) {
static void read_initial_file(void) { static void read_initial_file(void) {
struct stat st; struct stat st;
s32 fd = open(in_file, O_RDONLY); s32 fd = open(in_file, O_RDONLY);
if (fd < 0) PFATAL("Unable to open '%s'", in_file); if (fd < 0) PFATAL("Unable to open '%s'", in_file);
if (fstat(fd, &st) || !st.st_size) if (fstat(fd, &st) || !st.st_size) FATAL("Zero-sized input file.");
FATAL("Zero-sized input file.");
if (st.st_size >= TMIN_MAX_FILE) if (st.st_size >= TMIN_MAX_FILE)
FATAL("Input file is too large (%u MB max)", TMIN_MAX_FILE / 1024 / 1024); FATAL("Input file is too large (%u MB max)", TMIN_MAX_FILE / 1024 / 1024);
in_len = st.st_size; in_len = st.st_size;
in_data = ck_alloc_nozero(in_len); in_data = ck_alloc_nozero(in_len);
ck_read(fd, in_data, in_len, in_file); ck_read(fd, in_data, in_len, in_file);
@ -208,14 +210,13 @@ static void read_initial_file(void) {
} }
/* Write output file. */ /* Write output file. */
static s32 write_to_file(u8* path, u8* mem, u32 len) { static s32 write_to_file(u8* path, u8* mem, u32 len) {
s32 ret; s32 ret;
unlink(path); /* Ignore errors */ unlink(path); /* Ignore errors */
ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600); ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
@ -239,13 +240,15 @@ static void write_to_testcase(void* mem, u32 len) {
if (!use_stdin) { if (!use_stdin) {
unlink(out_file); /* Ignore errors. */ unlink(out_file); /* Ignore errors. */
fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600); fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) PFATAL("Unable to create '%s'", out_file); if (fd < 0) PFATAL("Unable to create '%s'", out_file);
} else lseek(fd, 0, SEEK_SET); } else
lseek(fd, 0, SEEK_SET);
ck_write(fd, mem, len, out_file); ck_write(fd, mem, len, out_file);
@ -254,12 +257,12 @@ static void write_to_testcase(void* mem, u32 len) {
if (ftruncate(fd, len)) PFATAL("ftruncate() failed"); if (ftruncate(fd, len)) PFATAL("ftruncate() failed");
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
} else close(fd); } else
close(fd);
} }
/* Handle timeout signal. */ /* Handle timeout signal. */
/* /*
static void handle_timeout(int sig) { static void handle_timeout(int sig) {
@ -277,11 +280,13 @@ static void handle_timeout(int sig) {
} }
} }
*/ */
/* start the app and it's forkserver */ /* start the app and it's forkserver */
/* /*
static void init_forkserver(char **argv) { static void init_forkserver(char **argv) {
static struct itimerval it; static struct itimerval it;
int st_pipe[2], ctl_pipe[2]; int st_pipe[2], ctl_pipe[2];
int status = 0; int status = 0;
@ -348,7 +353,7 @@ static void init_forkserver(char **argv) {
} }
// Close the unneeded endpoints. // Close the unneeded endpoints.
close(ctl_pipe[0]); close(ctl_pipe[0]);
close(st_pipe[1]); close(st_pipe[1]);
@ -378,8 +383,10 @@ static void init_forkserver(char **argv) {
// Otherwise, try to figure out what went wrong. // Otherwise, try to figure out what went wrong.
if (rlen == 4) { if (rlen == 4) {
ACTF("All right - fork server is up."); ACTF("All right - fork server is up.");
return; return;
} }
if (waitpid(forksrv_pid, &status, 0) <= 0) if (waitpid(forksrv_pid, &status, 0) <= 0)
@ -398,6 +405,7 @@ static void init_forkserver(char **argv) {
SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST, WTERMSIG(status)); SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST, WTERMSIG(status));
} }
*/ */
/* Execute target application. Returns 0 if the changes are a dud, or /* Execute target application. Returns 0 if the changes are a dud, or
@ -406,8 +414,8 @@ static void init_forkserver(char **argv) {
static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) { static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
static struct itimerval it; static struct itimerval it;
static u32 prev_timed_out = 0; static u32 prev_timed_out = 0;
int status = 0; int status = 0;
u32 cksum; u32 cksum;
@ -440,8 +448,10 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
/* Configure timeout, wait for child, cancel timeout. */ /* Configure timeout, wait for child, cancel timeout. */
if (exec_tmout) { if (exec_tmout) {
it.it_value.tv_sec = (exec_tmout / 1000); it.it_value.tv_sec = (exec_tmout / 1000);
it.it_value.tv_usec = (exec_tmout % 1000) * 1000; it.it_value.tv_usec = (exec_tmout % 1000) * 1000;
} }
setitimer(ITIMER_REAL, &it, NULL); setitimer(ITIMER_REAL, &it, NULL);
@ -508,9 +518,9 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
} else } else
/* Handle non-crashing inputs appropriately. */ /* Handle non-crashing inputs appropriately. */
if (crash_mode) { if (crash_mode) {
missed_paths++; missed_paths++;
return 0; return 0;
@ -522,24 +532,23 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
if (first_run) orig_cksum = cksum; if (first_run) orig_cksum = cksum;
if (orig_cksum == cksum) return 1; if (orig_cksum == cksum) return 1;
missed_paths++; missed_paths++;
return 0; return 0;
} }
/* Find first power of two greater or equal to val. */ /* Find first power of two greater or equal to val. */
static u32 next_p2(u32 val) { static u32 next_p2(u32 val) {
u32 ret = 1; u32 ret = 1;
while (val > ret) ret <<= 1; while (val > ret)
ret <<= 1;
return ret; return ret;
} }
/* Actually minimize! */ /* Actually minimize! */
static void minimize(char** argv) { static void minimize(char** argv) {
@ -557,8 +566,8 @@ static void minimize(char** argv) {
* BLOCK NORMALIZATION * * BLOCK NORMALIZATION *
***********************/ ***********************/
set_len = next_p2(in_len / TMIN_SET_STEPS); set_len = next_p2(in_len / TMIN_SET_STEPS);
set_pos = 0; set_pos = 0;
if (set_len < TMIN_SET_MIN_SIZE) set_len = TMIN_SET_MIN_SIZE; if (set_len < TMIN_SET_MIN_SIZE) set_len = TMIN_SET_MIN_SIZE;
@ -575,14 +584,14 @@ static void minimize(char** argv) {
memcpy(tmp_buf, in_data, in_len); memcpy(tmp_buf, in_data, in_len);
memset(tmp_buf + set_pos, '0', use_len); memset(tmp_buf + set_pos, '0', use_len);
u8 res; u8 res;
res = run_target(argv, tmp_buf, in_len, 0); res = run_target(argv, tmp_buf, in_len, 0);
if (res) { if (res) {
memset(in_data + set_pos, '0', use_len); memset(in_data + set_pos, '0', use_len);
/* changed_any = 1; value is not used */ /* changed_any = 1; value is not used */
alpha_del0 += use_len; alpha_del0 += use_len;
} }
@ -615,11 +624,11 @@ next_pass:
next_del_blksize: next_del_blksize:
if (!del_len) del_len = 1; if (!del_len) del_len = 1;
del_pos = 0; del_pos = 0;
prev_del = 1; prev_del = 1;
SAYF(cGRA " Block length = %u, remaining size = %u\n" cRST, SAYF(cGRA " Block length = %u, remaining size = %u\n" cRST, del_len,
del_len, in_len); in_len);
while (del_pos < in_len) { while (del_pos < in_len) {
@ -634,8 +643,8 @@ next_del_blksize:
very end of the buffer (tail_len > 0), and the current block is the same very end of the buffer (tail_len > 0), and the current block is the same
as the previous one... skip this step as a no-op. */ as the previous one... skip this step as a no-op. */
if (!prev_del && tail_len && !memcmp(in_data + del_pos - del_len, if (!prev_del && tail_len &&
in_data + del_pos, del_len)) { !memcmp(in_data + del_pos - del_len, in_data + del_pos, del_len)) {
del_pos += del_len; del_pos += del_len;
continue; continue;
@ -656,11 +665,13 @@ next_del_blksize:
memcpy(in_data, tmp_buf, del_pos + tail_len); memcpy(in_data, tmp_buf, del_pos + tail_len);
prev_del = 1; prev_del = 1;
in_len = del_pos + tail_len; in_len = del_pos + tail_len;
changed_any = 1; changed_any = 1;
} else del_pos += del_len; } else
del_pos += del_len;
} }
@ -674,7 +685,8 @@ next_del_blksize:
OKF("Block removal complete, %u bytes deleted.", stage_o_len - in_len); OKF("Block removal complete, %u bytes deleted.", stage_o_len - in_len);
if (!in_len && changed_any) if (!in_len && changed_any)
WARNF(cLRD "Down to zero bytes - check the command line and mem limit!" cRST); WARNF(cLRD
"Down to zero bytes - check the command line and mem limit!" cRST);
if (cur_pass > 1 && !changed_any) goto finalize_all; if (cur_pass > 1 && !changed_any) goto finalize_all;
@ -682,15 +694,17 @@ next_del_blksize:
* ALPHABET MINIMIZATION * * ALPHABET MINIMIZATION *
*************************/ *************************/
alpha_size = 0; alpha_size = 0;
alpha_del1 = 0; alpha_del1 = 0;
syms_removed = 0; syms_removed = 0;
memset(alpha_map, 0, sizeof(alpha_map)); memset(alpha_map, 0, sizeof(alpha_map));
for (i = 0; i < in_len; i++) { for (i = 0; i < in_len; i++) {
if (!alpha_map[in_data[i]]) alpha_size++; if (!alpha_map[in_data[i]]) alpha_size++;
alpha_map[in_data[i]]++; alpha_map[in_data[i]]++;
} }
ACTF(cBRI "Stage #2: " cRST "Minimizing symbols (%u code point%s)...", ACTF(cBRI "Stage #2: " cRST "Minimizing symbols (%u code point%s)...",
@ -699,14 +713,14 @@ next_del_blksize:
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
u32 r; u32 r;
u8 res; u8 res;
if (i == '0' || !alpha_map[i]) continue; if (i == '0' || !alpha_map[i]) continue;
memcpy(tmp_buf, in_data, in_len); memcpy(tmp_buf, in_data, in_len);
for (r = 0; r < in_len; r++) for (r = 0; r < in_len; r++)
if (tmp_buf[r] == i) tmp_buf[r] = '0'; if (tmp_buf[r] == i) tmp_buf[r] = '0';
res = run_target(argv, tmp_buf, in_len, 0); res = run_target(argv, tmp_buf, in_len, 0);
@ -724,8 +738,8 @@ next_del_blksize:
alpha_d_total += alpha_del1; alpha_d_total += alpha_del1;
OKF("Symbol minimization finished, %u symbol%s (%u byte%s) replaced.", OKF("Symbol minimization finished, %u symbol%s (%u byte%s) replaced.",
syms_removed, syms_removed == 1 ? "" : "s", syms_removed, syms_removed == 1 ? "" : "s", alpha_del1,
alpha_del1, alpha_del1 == 1 ? "" : "s"); alpha_del1 == 1 ? "" : "s");
/************************** /**************************
* CHARACTER MINIMIZATION * * CHARACTER MINIMIZATION *
@ -752,36 +766,34 @@ next_del_blksize:
alpha_del2++; alpha_del2++;
changed_any = 1; changed_any = 1;
} else tmp_buf[i] = orig; } else
tmp_buf[i] = orig;
} }
alpha_d_total += alpha_del2; alpha_d_total += alpha_del2;
OKF("Character minimization done, %u byte%s replaced.", OKF("Character minimization done, %u byte%s replaced.", alpha_del2,
alpha_del2, alpha_del2 == 1 ? "" : "s"); alpha_del2 == 1 ? "" : "s");
if (changed_any) goto next_pass; if (changed_any) goto next_pass;
finalize_all: finalize_all:
SAYF("\n" SAYF("\n" cGRA " File size reduced by : " cRST
cGRA " File size reduced by : " cRST "%0.02f%% (to %u byte%s)\n" "%0.02f%% (to %u byte%s)\n" cGRA " Characters simplified : " cRST
cGRA " Characters simplified : " cRST "%0.02f%%\n" "%0.02f%%\n" cGRA " Number of execs done : " cRST "%u\n" cGRA
cGRA " Number of execs done : " cRST "%u\n" " Fruitless execs : " cRST "path=%u crash=%u hang=%s%u\n\n",
cGRA " Fruitless execs : " cRST "path=%u crash=%u hang=%s%u\n\n",
100 - ((double)in_len) * 100 / orig_len, in_len, in_len == 1 ? "" : "s", 100 - ((double)in_len) * 100 / orig_len, in_len, in_len == 1 ? "" : "s",
((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), total_execs,
total_execs, missed_paths, missed_crashes, missed_hangs ? cLRD : "", missed_paths, missed_crashes, missed_hangs ? cLRD : "", missed_hangs);
missed_hangs);
if (total_execs > 50 && missed_hangs * 10 > total_execs) if (total_execs > 50 && missed_hangs * 10 > total_execs)
WARNF(cLRD "Frequent timeouts - results may be skewed." cRST); WARNF(cLRD "Frequent timeouts - results may be skewed." cRST);
} }
/* Handle Ctrl-C and the like. */ /* Handle Ctrl-C and the like. */
static void handle_stop_sig(int sig) { static void handle_stop_sig(int sig) {
@ -792,7 +804,6 @@ static void handle_stop_sig(int sig) {
} }
/* Do basic preparations - persistent fds, filenames, etc. */ /* Do basic preparations - persistent fds, filenames, etc. */
static void set_up_environment(void) { static void set_up_environment(void) {
@ -823,7 +834,6 @@ static void set_up_environment(void) {
if (out_fd < 0) PFATAL("Unable to create '%s'", out_file); if (out_fd < 0) PFATAL("Unable to create '%s'", out_file);
/* Set sane defaults... */ /* Set sane defaults... */
x = getenv("ASAN_OPTIONS"); x = getenv("ASAN_OPTIONS");
@ -843,18 +853,20 @@ static void set_up_environment(void) {
if (x) { if (x) {
if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR)))
FATAL("Custom MSAN_OPTIONS set without exit_code=" FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
STRINGIFY(MSAN_ERROR) " - please fix!"); MSAN_ERROR) " - please fix!");
if (!strstr(x, "symbolize=0")) if (!strstr(x, "symbolize=0"))
FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
} }
setenv("ASAN_OPTIONS", "abort_on_error=1:" setenv("ASAN_OPTIONS",
"detect_leaks=0:" "abort_on_error=1:"
"symbolize=0:" "detect_leaks=0:"
"allocator_may_return_null=1", 0); "symbolize=0:"
"allocator_may_return_null=1",
0);
setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
"symbolize=0:" "symbolize=0:"
@ -863,21 +875,22 @@ static void set_up_environment(void) {
"msan_track_origins=0", 0); "msan_track_origins=0", 0);
if (getenv("AFL_PRELOAD")) { if (getenv("AFL_PRELOAD")) {
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
} }
} }
/* Setup signal handlers, duh. */ /* Setup signal handlers, duh. */
static void setup_signal_handlers(void) { static void setup_signal_handlers(void) {
struct sigaction sa; struct sigaction sa;
sa.sa_handler = NULL; sa.sa_handler = NULL;
sa.sa_flags = SA_RESTART; sa.sa_flags = SA_RESTART;
sa.sa_sigaction = NULL; sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
@ -896,46 +909,46 @@ static void setup_signal_handlers(void) {
} }
/* Display usage hints. */ /* Display usage hints. */
static void usage(u8* argv0) { static void usage(u8* argv0) {
SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" SAYF(
"\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
"Required parameters:\n\n" "Required parameters:\n\n"
" -i file - input test case to be shrunk by the tool\n" " -i file - input test case to be shrunk by the tool\n"
" -o file - final output location for the minimized data\n\n" " -o file - final output location for the minimized data\n\n"
"Execution control settings:\n\n" "Execution control settings:\n\n"
" -f file - input file read by the tested program (stdin)\n" " -f file - input file read by the tested program (stdin)\n"
" -t msec - timeout for each run (%d ms)\n" " -t msec - timeout for each run (%d ms)\n"
" -m megs - memory limit for child process (%d MB)\n" " -m megs - memory limit for child process (%d MB)\n"
" -Q - use binary-only instrumentation (QEMU mode)\n" " -Q - use binary-only instrumentation (QEMU mode)\n"
" -U - use Unicorn-based instrumentation (Unicorn mode)\n\n" " -U - use Unicorn-based instrumentation (Unicorn mode)\n\n"
" (Not necessary, here for consistency with other afl-* tools)\n\n" " (Not necessary, here for consistency with other afl-* "
"tools)\n\n"
"Minimization settings:\n\n" "Minimization settings:\n\n"
" -e - solve for edge coverage only, ignore hit counts\n" " -e - solve for edge coverage only, ignore hit counts\n"
" -x - treat non-zero exit codes as crashes\n\n" " -x - treat non-zero exit codes as crashes\n\n"
"For additional tips, please consult %s/README.\n\n", "For additional tips, please consult %s/README.\n\n",
argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path); argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
exit(1); exit(1);
} }
/* Find binary. */ /* Find binary. */
static void find_binary(u8* fname) { static void find_binary(u8* fname) {
u8* env_path = 0; u8* env_path = 0;
struct stat st; struct stat st;
if (strchr(fname, '/') || !(env_path = getenv("PATH"))) { if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
@ -958,7 +971,9 @@ static void find_binary(u8* fname) {
memcpy(cur_elem, env_path, delim - env_path); memcpy(cur_elem, env_path, delim - env_path);
delim++; delim++;
} else cur_elem = ck_strdup(env_path); } else
cur_elem = ck_strdup(env_path);
env_path = delim; env_path = delim;
@ -970,7 +985,8 @@ static void find_binary(u8* fname) {
ck_free(cur_elem); ck_free(cur_elem);
if (!stat(target_path, &st) && S_ISREG(st.st_mode) && if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
(st.st_mode & 0111) && st.st_size >= 4) break; (st.st_mode & 0111) && st.st_size >= 4)
break;
ck_free(target_path); ck_free(target_path);
target_path = 0; target_path = 0;
@ -983,13 +999,12 @@ static void find_binary(u8* fname) {
} }
/* Fix up argv for QEMU. */ /* Fix up argv for QEMU. */
static char** get_qemu_argv(u8* own_loc, char** argv, int argc) { static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
u8 *tmp, *cp, *rsl, *own_copy; u8 * tmp, *cp, *rsl, *own_copy;
memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc); memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
@ -1004,8 +1019,7 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
cp = alloc_printf("%s/afl-qemu-trace", tmp); cp = alloc_printf("%s/afl-qemu-trace", tmp);
if (access(cp, X_OK)) if (access(cp, X_OK)) FATAL("Unable to find '%s'", tmp);
FATAL("Unable to find '%s'", tmp);
target_path = new_argv[0] = cp; target_path = new_argv[0] = cp;
return new_argv; return new_argv;
@ -1029,7 +1043,9 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
} }
} else ck_free(own_copy); } else
ck_free(own_copy);
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) { if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
@ -1056,8 +1072,6 @@ static void read_bitmap(u8* fname) {
} }
/* Main entry point */ /* Main entry point */
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -1070,7 +1084,7 @@ int main(int argc, char** argv) {
SAYF(cCYA "afl-tmin" VERSION cRST " by <lcamtuf@google.com>\n"); SAYF(cCYA "afl-tmin" VERSION cRST " by <lcamtuf@google.com>\n");
while ((opt = getopt(argc,argv,"+i:o:f:m:t:B:xeQU")) > 0) while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeQU")) > 0)
switch (opt) { switch (opt) {
@ -1090,7 +1104,7 @@ int main(int argc, char** argv) {
if (out_file) FATAL("Multiple -f options not supported"); if (out_file) FATAL("Multiple -f options not supported");
use_stdin = 0; use_stdin = 0;
out_file = optarg; out_file = optarg;
break; break;
case 'e': case 'e':
@ -1107,40 +1121,41 @@ int main(int argc, char** argv) {
case 'm': { case 'm': {
u8 suffix = 'M'; u8 suffix = 'M';
if (mem_limit_given) FATAL("Multiple -m options not supported"); if (mem_limit_given) FATAL("Multiple -m options not supported");
mem_limit_given = 1; mem_limit_given = 1;
if (!strcmp(optarg, "none")) { if (!strcmp(optarg, "none")) {
mem_limit = 0; mem_limit = 0;
break; break;
}
if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
optarg[0] == '-') FATAL("Bad syntax used for -m");
switch (suffix) {
case 'T': mem_limit *= 1024 * 1024; break;
case 'G': mem_limit *= 1024; break;
case 'k': mem_limit /= 1024; break;
case 'M': break;
default: FATAL("Unsupported suffix or bad syntax for -m");
}
if (mem_limit < 5) FATAL("Dangerously low value of -m");
if (sizeof(rlim_t) == 4 && mem_limit > 2000)
FATAL("Value of -m out of range on 32-bit systems");
} }
break; if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
optarg[0] == '-')
FATAL("Bad syntax used for -m");
switch (suffix) {
case 'T': mem_limit *= 1024 * 1024; break;
case 'G': mem_limit *= 1024; break;
case 'k': mem_limit /= 1024; break;
case 'M': break;
default: FATAL("Unsupported suffix or bad syntax for -m");
}
if (mem_limit < 5) FATAL("Dangerously low value of -m");
if (sizeof(rlim_t) == 4 && mem_limit > 2000)
FATAL("Value of -m out of range on 32-bit systems");
}
break;
case 't': case 't':
@ -1170,7 +1185,7 @@ int main(int argc, char** argv) {
unicorn_mode = 1; unicorn_mode = 1;
break; break;
case 'B': /* load bitmap */ case 'B': /* load bitmap */
/* This is a secret undocumented option! It is speculated to be useful /* This is a secret undocumented option! It is speculated to be useful
if you have a baseline "boring" input file and another "interesting" if you have a baseline "boring" input file and another "interesting"
@ -1190,9 +1205,7 @@ int main(int argc, char** argv) {
read_bitmap(optarg); read_bitmap(optarg);
break; break;
default: default: usage(argv[0]);
usage(argv[0]);
} }
@ -1230,15 +1243,16 @@ int main(int argc, char** argv) {
if (!crash_mode) { if (!crash_mode) {
OKF("Program terminates normally, minimizing in " OKF("Program terminates normally, minimizing in " cCYA "instrumented" cRST
cCYA "instrumented" cRST " mode."); " mode.");
if (!anything_set()) FATAL("No instrumentation detected."); if (!anything_set()) FATAL("No instrumentation detected.");
} else { } else {
OKF("Program exits with a signal, minimizing in " cMGN "%scrash" cRST OKF("Program exits with a signal, minimizing in " cMGN "%scrash" cRST
" mode.", exact_mode ? "EXACT " : ""); " mode.",
exact_mode ? "EXACT " : "");
} }

View File

@ -20,14 +20,16 @@
int main(int argc, char** argv) { int main(int argc, char** argv) {
char buff[8]; char buff[8];
char *buf = buff; char* buf = buff;
if (argc > 1) if (argc > 1)
buf = argv[1]; buf = argv[1];
else if (read(0, buf, sizeof(buf)) < 1) { else if (read(0, buf, sizeof(buf)) < 1) {
printf("Hum?\n"); printf("Hum?\n");
exit(1); exit(1);
} }
if (buf[0] == '0') if (buf[0] == '0')
@ -40,3 +42,4 @@ int main(int argc, char** argv) {
exit(0); exit(0);
} }

View File

@ -32,19 +32,17 @@
#include "../../config.h" #include "../../config.h"
/* NeverZero */ /* NeverZero */
#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO)
# define INC_AFL_AREA(loc) \ # define INC_AFL_AREA(loc) \
asm volatile ( \ asm volatile( \
"incb (%0, %1, 1)\n" \ "incb (%0, %1, 1)\n" \
"adcb $0, (%0, %1, 1)\n" \ "adcb $0, (%0, %1, 1)\n" \
: /* no out */ \ : /* no out */ \
: "r" (afl_area_ptr), "r" (loc) \ : "r"(afl_area_ptr), "r"(loc) \
: "memory", "eax" \ : "memory", "eax")
)
#else #else
# define INC_AFL_AREA(loc) \ # define INC_AFL_AREA(loc) afl_area_ptr[loc]++
afl_area_ptr[loc]++
#endif #endif

View File

@ -44,21 +44,29 @@
it to translate within its own context, too (this avoids translation it to translate within its own context, too (this avoids translation
overhead in the next forked-off copy). */ overhead in the next forked-off copy). */
#define AFL_UNICORN_CPU_SNIPPET1 do { \ #define AFL_UNICORN_CPU_SNIPPET1 \
do { \
\
afl_request_tsl(pc, cs_base, flags); \ afl_request_tsl(pc, cs_base, flags); \
\
} while (0) } while (0)
/* This snippet kicks in when the instruction pointer is positioned at /* This snippet kicks in when the instruction pointer is positioned at
_start and does the usual forkserver stuff, not very different from _start and does the usual forkserver stuff, not very different from
regular instrumentation injected via afl-as.h. */ regular instrumentation injected via afl-as.h. */
#define AFL_UNICORN_CPU_SNIPPET2 do { \ #define AFL_UNICORN_CPU_SNIPPET2 \
if(unlikely(afl_first_instr == 0)) { \ do { \
afl_setup(env->uc); \ \
afl_forkserver(env); \ if (unlikely(afl_first_instr == 0)) { \
afl_first_instr = 1; \ \
} \ afl_setup(env->uc); \
afl_maybe_log(env->uc, tb->pc); \ afl_forkserver(env); \
afl_first_instr = 1; \
\
} \
afl_maybe_log(env->uc, tb->pc); \
\
} while (0) } while (0)
/* We use one additional file descriptor to relay "needs translation" /* We use one additional file descriptor to relay "needs translation"
@ -69,26 +77,28 @@
/* Set in the child process in forkserver mode: */ /* Set in the child process in forkserver mode: */
static unsigned char afl_fork_child; static unsigned char afl_fork_child;
static unsigned int afl_forksrv_pid; static unsigned int afl_forksrv_pid;
/* Function declarations. */ /* Function declarations. */
static void afl_setup(struct uc_struct* uc); static void afl_setup(struct uc_struct* uc);
static void afl_forkserver(CPUArchState*); static void afl_forkserver(CPUArchState*);
static inline void afl_maybe_log(struct uc_struct* uc, unsigned long); static inline void afl_maybe_log(struct uc_struct* uc, unsigned long);
static void afl_wait_tsl(CPUArchState*, int); static void afl_wait_tsl(CPUArchState*, int);
static void afl_request_tsl(target_ulong, target_ulong, uint64_t); static void afl_request_tsl(target_ulong, target_ulong, uint64_t);
static TranslationBlock *tb_find_slow(CPUArchState*, target_ulong, static TranslationBlock* tb_find_slow(CPUArchState*, target_ulong, target_ulong,
target_ulong, uint64_t); uint64_t);
/* Data structure passed around by the translate handlers: */ /* Data structure passed around by the translate handlers: */
struct afl_tsl { struct afl_tsl {
target_ulong pc; target_ulong pc;
target_ulong cs_base; target_ulong cs_base;
uint64_t flags; uint64_t flags;
}; };
/************************* /*************************
@ -99,8 +109,7 @@ struct afl_tsl {
static void afl_setup(struct uc_struct* uc) { static void afl_setup(struct uc_struct* uc) {
char *id_str = getenv(SHM_ENV_VAR), char *id_str = getenv(SHM_ENV_VAR), *inst_r = getenv("AFL_INST_RATIO");
*inst_r = getenv("AFL_INST_RATIO");
int shm_id; int shm_id;
@ -116,9 +125,9 @@ static void afl_setup(struct uc_struct* uc) {
uc->afl_inst_rms = MAP_SIZE * r / 100; uc->afl_inst_rms = MAP_SIZE * r / 100;
} else { } else {
uc->afl_inst_rms = MAP_SIZE; uc->afl_inst_rms = MAP_SIZE;
} }
if (id_str) { if (id_str) {
@ -132,22 +141,22 @@ static void afl_setup(struct uc_struct* uc) {
so that the parent doesn't give up on us. */ so that the parent doesn't give up on us. */
if (inst_r) uc->afl_area_ptr[0] = 1; if (inst_r) uc->afl_area_ptr[0] = 1;
}
/* Maintain for compatibility */
if (getenv("AFL_QEMU_COMPCOV")) {
uc->afl_compcov_level = 1;
} }
/* Maintain for compatibility */
if (getenv("AFL_QEMU_COMPCOV")) { uc->afl_compcov_level = 1; }
if (getenv("AFL_COMPCOV_LEVEL")) { if (getenv("AFL_COMPCOV_LEVEL")) {
uc->afl_compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL")); uc->afl_compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL"));
} }
} }
/* Fork server logic, invoked once we hit first emulated instruction. */ /* Fork server logic, invoked once we hit first emulated instruction. */
static void afl_forkserver(CPUArchState *env) { static void afl_forkserver(CPUArchState* env) {
static unsigned char tmp[4]; static unsigned char tmp[4];
@ -165,13 +174,13 @@ static void afl_forkserver(CPUArchState *env) {
while (1) { while (1) {
pid_t child_pid; pid_t child_pid;
int status, t_fd[2]; int status, t_fd[2];
/* Whoops, parent dead? */ /* Whoops, parent dead? */
if (read(FORKSRV_FD, tmp, 4) != 4) exit(2); if (read(FORKSRV_FD, tmp, 4) != 4) exit(2);
/* Establish a channel with child to grab translation commands. We'll /* Establish a channel with child to grab translation commands. We'll
read from t_fd[0], child will write to TSL_FD. */ read from t_fd[0], child will write to TSL_FD. */
if (pipe(t_fd) || dup2(t_fd[1], TSL_FD) < 0) exit(3); if (pipe(t_fd) || dup2(t_fd[1], TSL_FD) < 0) exit(3);
@ -211,7 +220,6 @@ static void afl_forkserver(CPUArchState *env) {
} }
/* The equivalent of the tuple logging routine from afl-as.h. */ /* The equivalent of the tuple logging routine from afl-as.h. */
static inline void afl_maybe_log(struct uc_struct* uc, unsigned long cur_loc) { static inline void afl_maybe_log(struct uc_struct* uc, unsigned long cur_loc) {
@ -220,14 +228,13 @@ static inline void afl_maybe_log(struct uc_struct* uc, unsigned long cur_loc) {
u8* afl_area_ptr = uc->afl_area_ptr; u8* afl_area_ptr = uc->afl_area_ptr;
if(!afl_area_ptr) if (!afl_area_ptr) return;
return;
/* Looks like QEMU always maps to fixed locations, so ASAN is not a /* Looks like QEMU always maps to fixed locations, so ASAN is not a
concern. Phew. But instruction addresses may be aligned. Let's mangle concern. Phew. But instruction addresses may be aligned. Let's mangle
the value to get something quasi-uniform. */ the value to get something quasi-uniform. */
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 1; cur_loc &= MAP_SIZE - 1;
/* Implement probabilistic instrumentation by looking at scrambled block /* Implement probabilistic instrumentation by looking at scrambled block
@ -243,7 +250,6 @@ static inline void afl_maybe_log(struct uc_struct* uc, unsigned long cur_loc) {
} }
/* This code is invoked whenever QEMU decides that it doesn't have a /* This code is invoked whenever QEMU decides that it doesn't have a
translation of a particular block and needs to compute it. When this happens, translation of a particular block and needs to compute it. When this happens,
we tell the parent to mirror the operation, so that the next fork() has a we tell the parent to mirror the operation, so that the next fork() has a
@ -255,20 +261,19 @@ static void afl_request_tsl(target_ulong pc, target_ulong cb, uint64_t flags) {
if (!afl_fork_child) return; if (!afl_fork_child) return;
t.pc = pc; t.pc = pc;
t.cs_base = cb; t.cs_base = cb;
t.flags = flags; t.flags = flags;
if (write(TSL_FD, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) if (write(TSL_FD, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl))
return; return;
} }
/* This is the other side of the same channel. Since timeouts are handled by /* This is the other side of the same channel. Since timeouts are handled by
afl-fuzz simply killing the child, we can just wait until the pipe breaks. */ afl-fuzz simply killing the child, we can just wait until the pipe breaks. */
static void afl_wait_tsl(CPUArchState *env, int fd) { static void afl_wait_tsl(CPUArchState* env, int fd) {
struct afl_tsl t; struct afl_tsl t;
@ -276,12 +281,13 @@ static void afl_wait_tsl(CPUArchState *env, int fd) {
/* Broken pipe means it's time to return to the fork server routine. */ /* Broken pipe means it's time to return to the fork server routine. */
if (read(fd, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) if (read(fd, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) break;
break;
tb_find_slow(env, t.pc, t.cs_base, t.flags); tb_find_slow(env, t.pc, t.cs_base, t.flags);
} }
close(fd); close(fd);
} }

View File

@ -35,28 +35,23 @@
static void afl_gen_compcov(TCGContext *s, uint64_t cur_loc, TCGv_i64 arg1, static void afl_gen_compcov(TCGContext *s, uint64_t cur_loc, TCGv_i64 arg1,
TCGv_i64 arg2, TCGMemOp ot, int is_imm) { TCGv_i64 arg2, TCGMemOp ot, int is_imm) {
if (!s->uc->afl_compcov_level || !s->uc->afl_area_ptr) if (!s->uc->afl_compcov_level || !s->uc->afl_area_ptr) return;
return;
if (!is_imm && s->uc->afl_compcov_level < 2)
return;
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); if (!is_imm && s->uc->afl_compcov_level < 2) return;
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 7; cur_loc &= MAP_SIZE - 7;
if (cur_loc >= s->uc->afl_inst_rms) return; if (cur_loc >= s->uc->afl_inst_rms) return;
switch (ot) { switch (ot) {
case MO_64:
gen_afl_compcov_log_64(s, cur_loc, arg1, arg2); case MO_64: gen_afl_compcov_log_64(s, cur_loc, arg1, arg2); break;
break; case MO_32: gen_afl_compcov_log_32(s, cur_loc, arg1, arg2); break;
case MO_32: case MO_16: gen_afl_compcov_log_16(s, cur_loc, arg1, arg2); break;
gen_afl_compcov_log_32(s, cur_loc, arg1, arg2); default: return;
break;
case MO_16:
gen_afl_compcov_log_16(s, cur_loc, arg1, arg2);
break;
default:
return;
} }
} }

View File

@ -31,26 +31,29 @@
*/ */
static inline void gen_afl_compcov_log_16(TCGContext *tcg_ctx, uint64_t cur_loc, static inline void gen_afl_compcov_log_16(TCGContext *tcg_ctx, uint64_t cur_loc,
TCGv_i64 arg1, TCGv_i64 arg2) TCGv_i64 arg1, TCGv_i64 arg2) {
{
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc); TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc); TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
gen_helper_afl_compcov_log_16(tcg_ctx, tuc, tcur_loc, arg1, arg2); gen_helper_afl_compcov_log_16(tcg_ctx, tuc, tcur_loc, arg1, arg2);
} }
static inline void gen_afl_compcov_log_32(TCGContext *tcg_ctx, uint64_t cur_loc, static inline void gen_afl_compcov_log_32(TCGContext *tcg_ctx, uint64_t cur_loc,
TCGv_i64 arg1, TCGv_i64 arg2) TCGv_i64 arg1, TCGv_i64 arg2) {
{
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc); TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc); TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
gen_helper_afl_compcov_log_32(tcg_ctx, tuc, tcur_loc, arg1, arg2); gen_helper_afl_compcov_log_32(tcg_ctx, tuc, tcur_loc, arg1, arg2);
} }
static inline void gen_afl_compcov_log_64(TCGContext *tcg_ctx, uint64_t cur_loc, static inline void gen_afl_compcov_log_64(TCGContext *tcg_ctx, uint64_t cur_loc,
TCGv_i64 arg1, TCGv_i64 arg2) TCGv_i64 arg1, TCGv_i64 arg2) {
{
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc); TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc); TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
gen_helper_afl_compcov_log_64(tcg_ctx, tuc, tcur_loc, arg1, arg2); gen_helper_afl_compcov_log_64(tcg_ctx, tuc, tcur_loc, arg1, arg2);
} }

View File

@ -38,9 +38,8 @@ void HELPER(afl_compcov_log_16)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1,
u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr; u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr;
if ((arg1 & 0xff) == (arg2 & 0xff)) { if ((arg1 & 0xff) == (arg2 & 0xff)) { INC_AFL_AREA(cur_loc); }
INC_AFL_AREA(cur_loc);
}
} }
void HELPER(afl_compcov_log_32)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, void HELPER(afl_compcov_log_32)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1,
@ -49,14 +48,17 @@ void HELPER(afl_compcov_log_32)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1,
u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr; u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr;
if ((arg1 & 0xff) == (arg2 & 0xff)) { if ((arg1 & 0xff) == (arg2 & 0xff)) {
INC_AFL_AREA(cur_loc); INC_AFL_AREA(cur_loc);
if ((arg1 & 0xffff) == (arg2 & 0xffff)) { if ((arg1 & 0xffff) == (arg2 & 0xffff)) {
INC_AFL_AREA(cur_loc +1);
if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { INC_AFL_AREA(cur_loc + 1);
INC_AFL_AREA(cur_loc +2); if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { INC_AFL_AREA(cur_loc + 2); }
}
} }
} }
} }
void HELPER(afl_compcov_log_64)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, void HELPER(afl_compcov_log_64)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1,
@ -65,25 +67,40 @@ void HELPER(afl_compcov_log_64)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1,
u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr; u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr;
if ((arg1 & 0xff) == (arg2 & 0xff)) { if ((arg1 & 0xff) == (arg2 & 0xff)) {
INC_AFL_AREA(cur_loc); INC_AFL_AREA(cur_loc);
if ((arg1 & 0xffff) == (arg2 & 0xffff)) { if ((arg1 & 0xffff) == (arg2 & 0xffff)) {
INC_AFL_AREA(cur_loc +1);
INC_AFL_AREA(cur_loc + 1);
if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) {
INC_AFL_AREA(cur_loc +2);
INC_AFL_AREA(cur_loc + 2);
if ((arg1 & 0xffffffff) == (arg2 & 0xffffffff)) { if ((arg1 & 0xffffffff) == (arg2 & 0xffffffff)) {
INC_AFL_AREA(cur_loc +3);
INC_AFL_AREA(cur_loc + 3);
if ((arg1 & 0xffffffffff) == (arg2 & 0xffffffffff)) { if ((arg1 & 0xffffffffff) == (arg2 & 0xffffffffff)) {
INC_AFL_AREA(cur_loc +4);
INC_AFL_AREA(cur_loc + 4);
if ((arg1 & 0xffffffffffff) == (arg2 & 0xffffffffffff)) { if ((arg1 & 0xffffffffffff) == (arg2 & 0xffffffffffff)) {
INC_AFL_AREA(cur_loc +5);
INC_AFL_AREA(cur_loc + 5);
if ((arg1 & 0xffffffffffffff) == (arg2 & 0xffffffffffffff)) { if ((arg1 & 0xffffffffffffff) == (arg2 & 0xffffffffffffff)) {
INC_AFL_AREA(cur_loc +6);
INC_AFL_AREA(cur_loc + 6);
} }
} }
} }
} }
} }
} }
} }
} }