mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-12 18:18:07 +00:00
run code formatter
This commit is contained in:
4
Makefile
4
Makefile
@ -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
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -4,3 +4,4 @@
|
|||||||
|
|
||||||
void detect_file_args(char **argv, u8 *prog_in);
|
void detect_file_args(char **argv, u8 *prog_in);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
214
include/config.h
214
include/config.h
@ -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 */
|
||||||
|
|
||||||
|
180
include/debug.h
180
include/debug.h
@ -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 */
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
@ -5,3 +5,4 @@ void setup_shm(unsigned char dumb_mode);
|
|||||||
void remove_shm(void);
|
void remove_shm(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
164
src/afl-as.c
164
src/afl-as.c
@ -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();
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5707
src/afl-fuzz-one.c
5707
src/afl-fuzz-one.c
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
629
src/afl-fuzz.c
629
src/afl-fuzz.c
File diff suppressed because it is too large
Load Diff
128
src/afl-gcc.c
128
src/afl-gcc.c
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
374
src/afl-tmin.c
374
src/afl-tmin.c
@ -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 " : "");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user