mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-14 02:58:08 +00:00
Revert "Merge branch 'debug' into dev"
This reverts commita7537b5511
, reversing changes made to15e799f7ae
.
This commit is contained in:
@ -521,7 +521,6 @@ clean:
|
||||
$(MAKE) -C examples/argv_fuzzing clean
|
||||
$(MAKE) -C qemu_mode/unsigaction clean
|
||||
$(MAKE) -C qemu_mode/libcompcov clean
|
||||
test -d qemu_taint/qemu && { cd qemu_taint ; ./clean.sh ; }
|
||||
rm -rf qemu_mode/qemu-3.1.1
|
||||
ifeq "$(IN_REPO)" "1"
|
||||
test -d unicorn_mode/unicornafl && $(MAKE) -C unicorn_mode/unicornafl clean || true
|
||||
@ -532,7 +531,6 @@ endif
|
||||
|
||||
deepclean: clean
|
||||
rm -rf qemu_mode/qemu-3.1.1.tar.xz
|
||||
rm -rf qemu_taint/qemu
|
||||
rm -rf unicorn_mode/unicornafl
|
||||
git reset --hard >/dev/null 2>&1 || true
|
||||
|
||||
@ -590,7 +588,6 @@ install: all $(MANPAGES)
|
||||
install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH)
|
||||
rm -f $${DESTDIR}$(BIN_PATH)/afl-as
|
||||
if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f afl-qemu-taint ]; then install -m 755 afl-qemu-taint $${DESTDIR}$(BIN_PATH); fi
|
||||
if [ -f afl-gcc-fast ]; then set e; install -m 755 afl-gcc-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-gcc-fast $${DESTDIR}$(BIN_PATH)/afl-g++-fast; install -m 755 afl-gcc-pass.so afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH); fi
|
||||
if [ -f afl-clang-fast ]; then $(MAKE) -C llvm_mode install; fi
|
||||
if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
|
33
README.md
33
README.md
@ -1,36 +1,3 @@
|
||||
# qemu_taint variant.
|
||||
|
||||
UPDATE: **WORKS NOW** **PLEASE TEST** **:-)**
|
||||
|
||||
## HOWTO
|
||||
|
||||
cd qemu_taint && ./build_qemu_taint.sh
|
||||
|
||||
afl-fuzz -A ...
|
||||
|
||||
## CAVEATS
|
||||
|
||||
* llvm shmem persistent mode does not and can not not work
|
||||
* MOpt works but totally ignores the taint information, so disabled here
|
||||
* custom mutators? dunno if they work or not. depends on how they work.
|
||||
* not tested with qemu_mode
|
||||
* there are several debug checks to ensure the data is fine which slows down
|
||||
fuzzing, if the beta experiment runs fine these will be improved and it
|
||||
will result in quite a speed gain.
|
||||
|
||||
## THE TAINT
|
||||
|
||||
taint can be seen in out/taint/
|
||||
|
||||
the id:000 mirrors the out/queue entry, except the content it 0x00 for
|
||||
untainted bytes and '!' for tainted bytes.
|
||||
If a file has new tainted bytes compared to from which previous entry it
|
||||
was created then there is a id:000[...].new file where the new bytes are
|
||||
marked '!'.
|
||||
|
||||
the mutation switches between fuzzing all tainted bytes in one cycle and
|
||||
only new bytes in the other cycle.
|
||||
|
||||
# American Fuzzy Lop plus plus (afl++)
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
|
||||
|
191
afl_driver.cpp
191
afl_driver.cpp
@ -1,191 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Platform detection. Copied from FuzzerInternal.h
|
||||
#ifdef __linux__
|
||||
#define LIBFUZZER_LINUX 1
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __APPLE__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 1
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __NetBSD__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 1
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __FreeBSD__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 1
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __OpenBSD__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 1
|
||||
#else
|
||||
#error "Support for your platform has not been implemented"
|
||||
#endif
|
||||
|
||||
// libFuzzer interface is thin, so we don't include any libFuzzer headers.
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||
|
||||
// Notify AFL about persistent mode.
|
||||
static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
|
||||
int __afl_persistent_loop(unsigned int);
|
||||
static volatile char suppress_warning2 = AFL_PERSISTENT[0];
|
||||
|
||||
// Notify AFL about deferred forkserver.
|
||||
static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
|
||||
void __afl_manual_init();
|
||||
static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
|
||||
|
||||
// Input buffer.
|
||||
static const size_t kMaxAflInputSize = 1024000;
|
||||
static uint8_t AflInputBuf[kMaxAflInputSize];
|
||||
|
||||
// Use this optionally defined function to output sanitizer messages even if
|
||||
// user asks to close stderr.
|
||||
__attribute__((weak)) void __sanitizer_set_report_fd(void *);
|
||||
|
||||
// Keep track of where stderr content is being written to, so that
|
||||
// dup_and_close_stderr can use the correct one.
|
||||
static FILE *output_file = stderr;
|
||||
|
||||
// Experimental feature to use afl_driver without AFL's deferred mode.
|
||||
// Needs to run before __afl_auto_init.
|
||||
__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {
|
||||
if (getenv("AFL_DRIVER_DONT_DEFER")) {
|
||||
if (unsetenv("__AFL_DEFER_FORKSRV")) {
|
||||
perror("Failed to unset __AFL_DEFER_FORKSRV");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the user asks us to duplicate stderr, then do it.
|
||||
static void maybe_duplicate_stderr() {
|
||||
char *stderr_duplicate_filename =
|
||||
getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
|
||||
|
||||
if (!stderr_duplicate_filename)
|
||||
return;
|
||||
|
||||
FILE *stderr_duplicate_stream =
|
||||
freopen(stderr_duplicate_filename, "a+", stderr);
|
||||
|
||||
if (!stderr_duplicate_stream) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
|
||||
abort();
|
||||
}
|
||||
output_file = stderr_duplicate_stream;
|
||||
}
|
||||
|
||||
// Most of these I/O functions were inspired by/copied from libFuzzer's code.
|
||||
static void discard_output(int fd) {
|
||||
FILE *temp = fopen("/dev/null", "w");
|
||||
if (!temp)
|
||||
abort();
|
||||
dup2(fileno(temp), fd);
|
||||
fclose(temp);
|
||||
}
|
||||
|
||||
static void close_stdout() { discard_output(STDOUT_FILENO); }
|
||||
|
||||
// Prevent the targeted code from writing to "stderr" but allow sanitizers and
|
||||
// this driver to do so.
|
||||
static void dup_and_close_stderr() {
|
||||
int output_fileno = fileno(output_file);
|
||||
int output_fd = dup(output_fileno);
|
||||
if (output_fd <= 0)
|
||||
abort();
|
||||
FILE *new_output_file = fdopen(output_fd, "w");
|
||||
if (!new_output_file)
|
||||
abort();
|
||||
if (!__sanitizer_set_report_fd)
|
||||
return;
|
||||
__sanitizer_set_report_fd(reinterpret_cast<void *>(output_fd));
|
||||
discard_output(output_fileno);
|
||||
}
|
||||
|
||||
// Close stdout and/or stderr if user asks for it.
|
||||
static void maybe_close_fd_mask() {
|
||||
char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK");
|
||||
if (!fd_mask_str)
|
||||
return;
|
||||
int fd_mask = atoi(fd_mask_str);
|
||||
if (fd_mask & 2)
|
||||
dup_and_close_stderr();
|
||||
if (fd_mask & 1)
|
||||
close_stdout();
|
||||
}
|
||||
|
||||
// Define LLVMFuzzerMutate to avoid link failures for targets that use it
|
||||
// with libFuzzer's LLVMFuzzerCustomMutator.
|
||||
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||
assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
printf(
|
||||
"======================= INFO =========================\n"
|
||||
"This binary is built for AFL-fuzz.\n"
|
||||
"To run the target function on individual input(s) execute this:\n"
|
||||
" %s < INPUT_FILE\n"
|
||||
"To fuzz with afl-fuzz execute this:\n"
|
||||
" afl-fuzz [afl-flags] %s [-N]\n"
|
||||
"afl-fuzz will run N iterations before "
|
||||
"re-spawning the process (default: 1000)\n"
|
||||
"======================================================\n",
|
||||
argv[0], argv[0]);
|
||||
|
||||
maybe_duplicate_stderr();
|
||||
maybe_close_fd_mask();
|
||||
if (LLVMFuzzerInitialize)
|
||||
LLVMFuzzerInitialize(&argc, &argv);
|
||||
// Do any other expensive one-time initialization here.
|
||||
|
||||
int N = 100000;
|
||||
if (argc == 2 && argv[1][0] == '-')
|
||||
N = atoi(argv[1] + 1);
|
||||
else if(argc == 2 && (N = atoi(argv[1])) > 0)
|
||||
printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
|
||||
|
||||
assert(N > 0);
|
||||
|
||||
if (!getenv("AFL_DRIVER_DONT_DEFER"))
|
||||
__afl_manual_init();
|
||||
|
||||
// Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
|
||||
// on the first execution of LLVMFuzzerTestOneInput is ignored.
|
||||
uint8_t dummy_input[1] = {0};
|
||||
LLVMFuzzerTestOneInput(dummy_input, 1);
|
||||
|
||||
while (__afl_persistent_loop(N)) {
|
||||
ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
|
||||
if (n_read > 0) {
|
||||
LLVMFuzzerTestOneInput(AflInputBuf, n_read);
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s: successfully executed input(s)\n", argv[0]);
|
||||
}
|
@ -106,7 +106,10 @@ If 1, close stdout at startup. If 2 close stderr; if 3 close both.
|
||||
#error "Support for your platform has not been implemented"
|
||||
#endif
|
||||
|
||||
int __afl_sharedmem_fuzzing = 0;
|
||||
int __afl_sharedmem_fuzzing = 1;
|
||||
extern unsigned int * __afl_fuzz_len;
|
||||
extern unsigned char *__afl_fuzz_ptr;
|
||||
// extern struct cmp_map *__afl_cmp_map;
|
||||
|
||||
// libFuzzer interface is thin, so we don't include any libFuzzer headers.
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
@ -272,7 +275,6 @@ int main(int argc, char **argv) {
|
||||
// Do any other expensive one-time initialization here.
|
||||
|
||||
uint8_t dummy_input[64] = {0};
|
||||
uint8_t buf[1024000];
|
||||
memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT));
|
||||
memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR,
|
||||
sizeof(AFL_DEFER_FORKSVR));
|
||||
@ -283,25 +285,17 @@ int main(int argc, char **argv) {
|
||||
printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
|
||||
else if (argc > 1) {
|
||||
|
||||
if (!getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) {
|
||||
|
||||
__afl_sharedmem_fuzzing = 0;
|
||||
__afl_manual_init();
|
||||
|
||||
}
|
||||
|
||||
return ExecuteFilesOnyByOne(argc, argv);
|
||||
|
||||
}
|
||||
|
||||
assert(N > 0);
|
||||
|
||||
if (!getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) {
|
||||
|
||||
fprintf(stderr, "performing manual init\n");
|
||||
// if (!getenv("AFL_DRIVER_DONT_DEFER"))
|
||||
__afl_manual_init();
|
||||
|
||||
}
|
||||
|
||||
// Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
|
||||
// on the first execution of LLVMFuzzerTestOneInput is ignored.
|
||||
LLVMFuzzerTestOneInput(dummy_input, 1);
|
||||
@ -309,13 +303,25 @@ int main(int argc, char **argv) {
|
||||
int num_runs = 0;
|
||||
while (__afl_persistent_loop(N)) {
|
||||
|
||||
ssize_t r = read(0, buf, sizeof(buf));
|
||||
#ifdef _DEBUG
|
||||
fprintf(stderr, "CLIENT crc: %016llx len: %u\n",
|
||||
hash64(__afl_fuzz_ptr, *__afl_fuzz_len, 0xa5b35705),
|
||||
*__afl_fuzz_len);
|
||||
fprintf(stderr, "RECV:");
|
||||
for (int i = 0; i < *__afl_fuzz_len; i++)
|
||||
fprintf(stderr, "%02x", __afl_fuzz_ptr[i]);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
if (*__afl_fuzz_len) {
|
||||
|
||||
if (r > 0) { LLVMFuzzerTestOneInput(buf, r); }
|
||||
num_runs++;
|
||||
LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len);
|
||||
|
||||
}
|
||||
|
||||
printf("%s: successfully executed input(s)\n", argv[0]);
|
||||
}
|
||||
|
||||
printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);
|
||||
|
||||
}
|
||||
|
||||
|
@ -133,10 +133,8 @@ extern s32
|
||||
|
||||
struct queue_entry {
|
||||
|
||||
u8 * fname; /* File name for the test case */
|
||||
u8 * fname_taint; /* File name for taint data */
|
||||
u8 *fname; /* File name for the test case */
|
||||
u32 len; /* Input length */
|
||||
struct queue_entry *prev; /* previous queue entry, if any */
|
||||
|
||||
u8 cal_failed, /* Calibration failed? */
|
||||
trim_done, /* Trimmed? */
|
||||
@ -150,10 +148,7 @@ struct queue_entry {
|
||||
is_ascii; /* Is the input just ascii text? */
|
||||
|
||||
u32 bitmap_size, /* Number of bits set in bitmap */
|
||||
fuzz_level, /* Number of fuzzing iterations */
|
||||
taint_bytes_all, /* Number of tainted bytes */
|
||||
taint_bytes_new, /* Number of new tainted bytes */
|
||||
taint_bytes_highest; /* highest offset in input */
|
||||
fuzz_level; /* Number of fuzzing iterations */
|
||||
|
||||
u64 exec_us, /* Execution time (us) */
|
||||
handicap, /* Number of queue cycles behind */
|
||||
@ -385,8 +380,6 @@ typedef struct afl_state {
|
||||
|
||||
char **argv; /* argv if needed */
|
||||
|
||||
char **argv_taint; /* argv for taint mode */
|
||||
|
||||
/* MOpt:
|
||||
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. */
|
||||
@ -438,9 +431,7 @@ typedef struct afl_state {
|
||||
*in_bitmap, /* Input bitmap */
|
||||
*file_extension, /* File extension */
|
||||
*orig_cmdline, /* Original command line */
|
||||
*infoexec, /* Command to execute on a new crash */
|
||||
*taint_input_file, /* fuzz_input_one input file */
|
||||
*taint_src, *taint_map;
|
||||
*infoexec; /* Command to execute on a new crash */
|
||||
|
||||
u32 hang_tmout; /* Timeout used for hang det (ms) */
|
||||
|
||||
@ -451,9 +442,7 @@ typedef struct afl_state {
|
||||
custom_only, /* Custom mutator only mode */
|
||||
python_only, /* Python-only mode */
|
||||
is_main_node, /* if this is the main node */
|
||||
is_secondary_node, /* if this is a secondary instance */
|
||||
taint_needs_splode, /* explode fuzz input */
|
||||
taint_mode;
|
||||
is_secondary_node; /* if this is a secondary instance */
|
||||
|
||||
u32 stats_update_freq; /* Stats update frequency (execs) */
|
||||
|
||||
@ -514,8 +503,7 @@ typedef struct afl_state {
|
||||
useless_at_start, /* Number of useless starting paths */
|
||||
var_byte_count, /* Bitmap bytes with var behavior */
|
||||
current_entry, /* Current queue entry ID */
|
||||
havoc_div, /* Cycle count divisor for havoc */
|
||||
taint_len, taint_count;
|
||||
havoc_div; /* Cycle count divisor for havoc */
|
||||
|
||||
u64 total_crashes, /* Total number of crashes */
|
||||
unique_crashes, /* Crashes with unique signatures */
|
||||
@ -602,9 +590,6 @@ typedef struct afl_state {
|
||||
char * cmplog_binary;
|
||||
afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */
|
||||
|
||||
/* Taint mode */
|
||||
afl_forkserver_t taint_fsrv; /* taint mode has its own little forkserver */
|
||||
|
||||
/* Custom mutators */
|
||||
struct custom_mutator *mutator;
|
||||
|
||||
@ -856,8 +841,7 @@ struct custom_mutator {
|
||||
|
||||
};
|
||||
|
||||
void afl_state_init_1(afl_state_t *, uint32_t map_size);
|
||||
void afl_state_init_2(afl_state_t *, uint32_t map_size);
|
||||
void afl_state_init(afl_state_t *, uint32_t map_size);
|
||||
void afl_state_deinit(afl_state_t *);
|
||||
|
||||
/* Set stop_soon flag on all childs, kill all childs */
|
||||
@ -903,7 +887,7 @@ void deinit_py(void *);
|
||||
void mark_as_det_done(afl_state_t *, struct queue_entry *);
|
||||
void mark_as_variable(afl_state_t *, struct queue_entry *);
|
||||
void mark_as_redundant(afl_state_t *, struct queue_entry *, u8);
|
||||
void add_to_queue(afl_state_t *, u8 *, u8 *, u32, struct queue_entry *, u8);
|
||||
void add_to_queue(afl_state_t *, u8 *, u32, u8);
|
||||
void destroy_queue(afl_state_t *);
|
||||
void update_bitmap_score(afl_state_t *, struct queue_entry *);
|
||||
void cull_queue(afl_state_t *);
|
||||
@ -913,9 +897,7 @@ u32 calculate_score(afl_state_t *, struct queue_entry *);
|
||||
|
||||
void write_bitmap(afl_state_t *);
|
||||
u32 count_bits(afl_state_t *, u8 *);
|
||||
u32 count_bits_len(afl_state_t *, u8 *, u32);
|
||||
u32 count_bytes(afl_state_t *, u8 *);
|
||||
u32 count_bytes_len(afl_state_t *, u8 *, u32);
|
||||
u32 count_non_255_bytes(afl_state_t *, u8 *);
|
||||
#ifdef WORD_SIZE_64
|
||||
void simplify_trace(afl_state_t *, u64 *);
|
||||
@ -993,8 +975,6 @@ void check_if_tty(afl_state_t *);
|
||||
void setup_signal_handlers(void);
|
||||
void save_cmdline(afl_state_t *, u32, char **);
|
||||
void read_foreign_testcases(afl_state_t *, int);
|
||||
void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname,
|
||||
u8 *mem, u32 len);
|
||||
|
||||
/* CmpLog */
|
||||
|
||||
|
@ -55,7 +55,6 @@ extern u8 *doc_path; /* path to documentation dir */
|
||||
@returns the path, allocating the string */
|
||||
|
||||
u8 *find_binary(u8 *fname);
|
||||
u8 *find_afl_binary(u8 *fname, u8 *own_loc);
|
||||
|
||||
/* Read a bitmap from file fname to memory
|
||||
This is for the -B option again. */
|
||||
|
@ -123,7 +123,6 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_SKIP_BIN_CHECK",
|
||||
"AFL_SKIP_CPUFREQ",
|
||||
"AFL_SKIP_CRASHES",
|
||||
"AFL_TAINT_INPUT",
|
||||
"AFL_TMIN_EXACT",
|
||||
"AFL_TMPDIR",
|
||||
"AFL_TOKEN_FILE",
|
||||
|
@ -80,8 +80,6 @@ typedef struct afl_forkserver {
|
||||
|
||||
u8 qemu_mode; /* if running in qemu mode or not */
|
||||
|
||||
u8 taint_mode; /* if running taint analysis or not */
|
||||
|
||||
u32 *shmem_fuzz_len; /* length of the fuzzing test case */
|
||||
|
||||
u8 *shmem_fuzz; /* allocated memory for fuzzing */
|
||||
|
@ -1,42 +0,0 @@
|
||||
# qemu_taint
|
||||
|
||||
First level taint implementation with qemu for linux user mode
|
||||
|
||||
**THIS IS NOT WORKING YET** **WIP**
|
||||
|
||||
## What is this for
|
||||
|
||||
On new queue entries (newly discovered paths into the target) this tainter
|
||||
is run with the new input and the data gathered which bytes in the input
|
||||
file are actually touched.
|
||||
|
||||
Only touched bytes are then fuzzed by afl-fuzz
|
||||
|
||||
## How to build
|
||||
|
||||
./build_qemu_taint.sh
|
||||
|
||||
## How to use
|
||||
|
||||
Add the -A flag to afl-fuzz
|
||||
|
||||
## Caveats
|
||||
|
||||
For some targets this is amazing and improves fuzzing a lot, but if a target
|
||||
copies all input bytes first (e.g. for creating a crc checksum or just to
|
||||
safely work with the data), then this is not helping at all.
|
||||
|
||||
## Future
|
||||
|
||||
Two fuzz modes for a queue entry which will be switched back and forth:
|
||||
|
||||
1. fuzz all touched bytes
|
||||
2. fuzz only bytes that are newly touched (compared to the one this queue
|
||||
entry is based on)
|
||||
|
||||
## TODO
|
||||
|
||||
* Direct trim: trim to highest touched byte, that is all we need to do
|
||||
* add 5-25% dummy bytes to the queue entries? (maybe create a 2nd one?)
|
||||
* Disable trim?
|
||||
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
test -d qemu || git clone https://github.com/vanhauser-thc/qemu_taint qemu || exit 1
|
||||
cd qemu || exit 1
|
||||
test -d .git && { git stash ; git pull ; }
|
||||
cp -fv ../../include/config.h ../../include/types.h . || exit 1
|
||||
./build.sh || exit 1
|
||||
cp -fv ./afl-qemu-taint ../..
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
rm -f afl-qemu-taint qemu/afl-qemu-taint ../afl-qemu-taint
|
||||
test -d qemu && { cd qemu ; ./clean.sh ; }
|
169
src/afl-common.c
169
src/afl-common.c
@ -138,59 +138,12 @@ void argv_cpy_free(char **argv) {
|
||||
|
||||
}
|
||||
|
||||
u8 *find_afl_binary(u8 *fname, u8 *own_loc) {
|
||||
|
||||
u8 *tmp, *rsl, *own_copy, *cp;
|
||||
|
||||
tmp = getenv("AFL_PATH");
|
||||
|
||||
if (tmp) {
|
||||
|
||||
cp = alloc_printf("%s/%s", tmp, fname);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
return cp;
|
||||
|
||||
}
|
||||
|
||||
if (own_loc) {
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
cp = alloc_printf("%s/%s", own_copy, fname);
|
||||
ck_free(own_copy);
|
||||
|
||||
if (!access(cp, X_OK)) { return cp; }
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cp = alloc_printf("%s/%s", BIN_PATH, fname);
|
||||
if (!access(cp, X_OK)) { return cp; }
|
||||
|
||||
ck_free(cp);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/* Rewrite argv for QEMU. */
|
||||
|
||||
char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
char **new_argv = ck_alloc(sizeof(char *) * (argc + 4));
|
||||
u8 * cp = NULL;
|
||||
u8 * tmp, *cp = NULL, *rsl, *own_copy;
|
||||
|
||||
memcpy(&new_argv[3], &argv[1], (int)(sizeof(char *)) * (argc - 1));
|
||||
new_argv[argc - 1] = NULL;
|
||||
@ -200,15 +153,51 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
/* Now we need to actually find the QEMU binary to put in argv[0]. */
|
||||
|
||||
cp = find_afl_binary("afl-qemu-trace", own_loc);
|
||||
tmp = getenv("AFL_PATH");
|
||||
|
||||
if (cp) {
|
||||
if (tmp) {
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", tmp);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", own_copy);
|
||||
ck_free(own_copy);
|
||||
|
||||
if (!access(cp, X_OK)) {
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
}
|
||||
|
||||
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
|
||||
|
||||
if (cp) { ck_free(cp); }
|
||||
*target_path_p = new_argv[0] = ck_strdup(BIN_PATH "/afl-qemu-trace");
|
||||
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Oops, unable to find the 'afl-qemu-trace' binary. The binary must be "
|
||||
"built\n"
|
||||
@ -236,7 +225,7 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
char **new_argv = ck_alloc(sizeof(char *) * (argc + 3));
|
||||
u8 * cp = NULL;
|
||||
u8 * tmp, *cp = NULL, *rsl, *own_copy;
|
||||
|
||||
memcpy(&new_argv[2], &argv[1], (int)(sizeof(char *)) * (argc - 1));
|
||||
new_argv[argc - 1] = NULL;
|
||||
@ -245,14 +234,41 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
/* Now we need to actually find the QEMU binary to put in argv[0]. */
|
||||
|
||||
cp = find_afl_binary("afl-qemu-trace", own_loc);
|
||||
tmp = getenv("AFL_PATH");
|
||||
|
||||
if (cp) {
|
||||
if (tmp) {
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", tmp);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
ck_free(cp);
|
||||
cp = find_afl_binary("afl-wine-trace", own_loc);
|
||||
|
||||
if (cp) {
|
||||
cp = alloc_printf("%s/afl-wine-trace", tmp);
|
||||
|
||||
if (access(cp, X_OK)) { FATAL("Unable to find '%s'", tmp); }
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
own_copy = ck_strdup(own_loc);
|
||||
rsl = strrchr(own_copy, '/');
|
||||
|
||||
if (rsl) {
|
||||
|
||||
*rsl = 0;
|
||||
|
||||
cp = alloc_printf("%s/afl-qemu-trace", own_copy);
|
||||
|
||||
if (cp && !access(cp, X_OK)) {
|
||||
|
||||
ck_free(cp);
|
||||
|
||||
cp = alloc_printf("%s/afl-wine-trace", own_copy);
|
||||
|
||||
if (!access(cp, X_OK)) {
|
||||
|
||||
*target_path_p = new_argv[0] = cp;
|
||||
return new_argv;
|
||||
@ -261,22 +277,49 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
|
||||
|
||||
}
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
} else {
|
||||
|
||||
ck_free(own_copy);
|
||||
|
||||
}
|
||||
|
||||
u8 *ncp = BIN_PATH "/afl-qemu-trace";
|
||||
|
||||
if (!access(ncp, X_OK)) {
|
||||
|
||||
ncp = BIN_PATH "/afl-wine-trace";
|
||||
|
||||
if (!access(ncp, X_OK)) {
|
||||
|
||||
*target_path_p = new_argv[0] = ck_strdup(ncp);
|
||||
return new_argv;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SAYF("\n" cLRD "[-] " cRST
|
||||
"Oops, unable to find the afl-qemu-trace and afl-wine-trace binaries.\n"
|
||||
"The afl-qemu-trace binary must be built separately by following the "
|
||||
"instructions\n"
|
||||
"in qemu_mode/README.md. If you already have the binary installed, you "
|
||||
"may need\n"
|
||||
"to specify the location via AFL_PATH in the environment.\n\n"
|
||||
"Oops, unable to find the '%s' binary. The binary must be "
|
||||
"built\n"
|
||||
" separately by following the instructions in "
|
||||
"qemu_mode/README.md. "
|
||||
"If you\n"
|
||||
" already have the binary installed, you may need to specify "
|
||||
"AFL_PATH in the\n"
|
||||
" environment.\n\n"
|
||||
|
||||
" Of course, even without QEMU, afl-fuzz can still work with "
|
||||
"binaries that are\n"
|
||||
" instrumented at compile time with afl-gcc. It is also possible to "
|
||||
"use it as a\n"
|
||||
" traditional non-instrumented fuzzer by specifying '-n' in the "
|
||||
"command "
|
||||
"line.\n");
|
||||
"line.\n",
|
||||
ncp);
|
||||
|
||||
FATAL("Failed to locate 'afl-qemu-trace' and 'afl-wine-trace'.");
|
||||
FATAL("Failed to locate '%s'.", ncp);
|
||||
|
||||
}
|
||||
|
||||
|
@ -498,21 +498,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
char pid_buf[16];
|
||||
sprintf(pid_buf, "%d", fsrv->fsrv_pid);
|
||||
|
||||
if (fsrv->taint_mode) {
|
||||
|
||||
setenv("__AFL_TARGET_PID3", pid_buf, 1);
|
||||
|
||||
} else if (fsrv->cmplog_binary) {
|
||||
|
||||
if (fsrv->cmplog_binary)
|
||||
setenv("__AFL_TARGET_PID2", pid_buf, 1);
|
||||
|
||||
} else {
|
||||
|
||||
else
|
||||
setenv("__AFL_TARGET_PID1", pid_buf, 1);
|
||||
|
||||
}
|
||||
|
||||
/* Close the unneeded endpoints. */
|
||||
|
||||
close(ctl_pipe[0]);
|
||||
@ -947,7 +937,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
|
||||
|
||||
} else {
|
||||
|
||||
s32 fd;
|
||||
s32 fd = fsrv->out_fd;
|
||||
|
||||
if (fsrv->out_file) {
|
||||
|
||||
@ -966,7 +956,6 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
|
||||
|
||||
} else {
|
||||
|
||||
fd = fsrv->out_fd;
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
}
|
||||
|
@ -177,40 +177,6 @@ u32 count_bits(afl_state_t *afl, u8 *mem) {
|
||||
|
||||
}
|
||||
|
||||
u32 count_bits_len(afl_state_t *afl, u8 *mem, u32 len) {
|
||||
|
||||
u32 *ptr = (u32 *)mem;
|
||||
u32 i = (len >> 2);
|
||||
u32 ret = 0;
|
||||
|
||||
(void)(afl);
|
||||
|
||||
if (len % 4) i++;
|
||||
|
||||
while (i--) {
|
||||
|
||||
u32 v = *(ptr++);
|
||||
|
||||
/* This gets called on the inverse, virgin bitmap; optimize for sparse
|
||||
data. */
|
||||
|
||||
if (v == 0xffffffff) {
|
||||
|
||||
ret += 32;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
v -= ((v >> 1) & 0x55555555);
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
|
||||
ret += (((v + (v >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24;
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Count the number of bytes set in the bitmap. Called fairly sporadically,
|
||||
mostly to update the status screen or calibrate and examine confirmed
|
||||
new paths. */
|
||||
@ -237,32 +203,6 @@ u32 count_bytes(afl_state_t *afl, u8 *mem) {
|
||||
|
||||
}
|
||||
|
||||
u32 count_bytes_len(afl_state_t *afl, u8 *mem, u32 len) {
|
||||
|
||||
u32 *ptr = (u32 *)mem;
|
||||
u32 i = (len >> 2);
|
||||
u32 ret = 0;
|
||||
|
||||
(void)(afl);
|
||||
|
||||
if (len % 4) i++;
|
||||
|
||||
while (i--) {
|
||||
|
||||
u32 v = *(ptr++);
|
||||
|
||||
if (!v) { continue; }
|
||||
if (v & 0x000000ff) { ++ret; }
|
||||
if (v & 0x0000ff00) { ++ret; }
|
||||
if (v & 0x00ff0000) { ++ret; }
|
||||
if (v & 0xff000000) { ++ret; }
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Count the number of non-255 bytes set in the bitmap. Used strictly for the
|
||||
status screen, several calls per second or so. */
|
||||
|
||||
@ -655,7 +595,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
|
||||
#endif /* ^!SIMPLE_FILES */
|
||||
|
||||
add_to_queue(afl, queue_fn, mem, len, afl->queue_top, 0);
|
||||
add_to_queue(afl, queue_fn, len, 0);
|
||||
|
||||
if (hnb == 2) {
|
||||
|
||||
|
@ -712,7 +712,7 @@ void read_testcases(afl_state_t *afl) {
|
||||
|
||||
if (!access(dfn, F_OK)) { passed_det = 1; }
|
||||
|
||||
add_to_queue(afl, fn2, NULL, st.st_size, NULL, passed_det);
|
||||
add_to_queue(afl, fn2, st.st_size, passed_det);
|
||||
|
||||
}
|
||||
|
||||
@ -771,13 +771,9 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
close(fd);
|
||||
|
||||
res = calibrate_case(afl, q, use_mem, 0, 1);
|
||||
|
||||
if (afl->stop_soon) {
|
||||
|
||||
ck_free(use_mem);
|
||||
return;
|
||||
|
||||
}
|
||||
if (afl->stop_soon) { return; }
|
||||
|
||||
if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) {
|
||||
|
||||
@ -964,10 +960,6 @@ void perform_dry_run(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
/* perform taint gathering on the input seed */
|
||||
if (afl->taint_mode) perform_taint_run(afl, q, q->fname, use_mem, q->len);
|
||||
ck_free(use_mem);
|
||||
|
||||
q = q->next;
|
||||
|
||||
}
|
||||
@ -1446,10 +1438,6 @@ static void handle_existing_out_dir(afl_state_t *afl) {
|
||||
|
||||
u8 *orig_q = alloc_printf("%s/queue", afl->out_dir);
|
||||
|
||||
u8 *fnt = alloc_printf("%s/taint", afl->out_dir);
|
||||
mkdir(fnt, 0755); // ignore errors
|
||||
ck_free(fnt);
|
||||
|
||||
afl->in_dir = alloc_printf("%s/_resume", afl->out_dir);
|
||||
|
||||
rename(orig_q, afl->in_dir); /* Ignore errors */
|
||||
@ -1506,20 +1494,6 @@ static void handle_existing_out_dir(afl_state_t *afl) {
|
||||
if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
|
||||
ck_free(fn);
|
||||
|
||||
if (afl->taint_mode) {
|
||||
|
||||
fn = alloc_printf("%s/taint", afl->out_dir);
|
||||
mkdir(fn, 0755); // ignore errors
|
||||
|
||||
u8 *fn2 = alloc_printf("%s/taint/.input", afl->out_dir);
|
||||
unlink(fn2); // ignore errors
|
||||
ck_free(fn2);
|
||||
|
||||
if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
|
||||
ck_free(fn);
|
||||
|
||||
}
|
||||
|
||||
/* All right, let's do <afl->out_dir>/crashes/id:* and
|
||||
* <afl->out_dir>/hangs/id:*. */
|
||||
|
||||
@ -1747,16 +1721,6 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
/* Taint directory if taint_mode. */
|
||||
|
||||
if (afl->taint_mode) {
|
||||
|
||||
tmp = alloc_printf("%s/taint", afl->out_dir);
|
||||
if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
|
||||
ck_free(tmp);
|
||||
|
||||
}
|
||||
|
||||
/* Top-level directory for queue metadata used for session
|
||||
resume and related tasks. */
|
||||
|
||||
|
@ -458,147 +458,6 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
u32 tmp_val = 0;
|
||||
|
||||
if (unlikely(afl->taint_mode)) {
|
||||
|
||||
tmp_val = afl->queue_cycle % 2; // starts with 1
|
||||
ret_val = 0;
|
||||
|
||||
if (unlikely(afl->queue_cur->cal_failed && !tmp_val)) goto abandon_entry;
|
||||
if (unlikely(!afl->skip_deterministic && !afl->queue_cur->passed_det &&
|
||||
!tmp_val))
|
||||
goto abandon_entry;
|
||||
if ((!afl->queue_cur->taint_bytes_new ||
|
||||
afl->queue_cur->taint_bytes_new == afl->queue_cur->len) &&
|
||||
!tmp_val)
|
||||
goto abandon_entry;
|
||||
|
||||
ret_val = 1;
|
||||
|
||||
s32 dst = 0, i;
|
||||
temp_len = len = afl->queue_cur->len;
|
||||
s32 j = 0; // tmp
|
||||
|
||||
fd = open(afl->queue_cur->fname, O_RDONLY);
|
||||
afl->taint_src = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
if (fd < 0 || (ssize_t)afl->taint_src == -1)
|
||||
FATAL("unable to open '%s'", afl->queue_cur->fname);
|
||||
close(fd);
|
||||
afl->taint_needs_splode = 1;
|
||||
|
||||
switch (tmp_val) {
|
||||
|
||||
case 1: // fuzz only tainted bytes
|
||||
|
||||
// special case: all or nothing tainted. in this case we act like
|
||||
// nothing is special. this is not the taint you are looking for ...
|
||||
if (!afl->queue_cur->taint_bytes_all ||
|
||||
afl->queue_cur->taint_bytes_all == (u32)len) {
|
||||
|
||||
orig_in = in_buf = afl->taint_src;
|
||||
afl->taint_needs_splode = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
fd = open(afl->taint_input_file, O_RDONLY);
|
||||
temp_len = len = afl->taint_len = afl->queue_cur->taint_bytes_all;
|
||||
orig_in = in_buf =
|
||||
mmap(0, len >= MAX_FILE - 65536 ? MAX_FILE : len + 65536,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
if (fd < 0 || (ssize_t)in_buf == -1)
|
||||
FATAL("unable to open '%s'", afl->taint_input_file);
|
||||
close(fd);
|
||||
|
||||
fd = open(afl->queue_cur->fname_taint, O_RDONLY);
|
||||
afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE, fd, 0);
|
||||
if (fd < 0 || (ssize_t)in_buf == -1)
|
||||
FATAL("unable to open '%s'", afl->queue_cur->fname_taint);
|
||||
close(fd);
|
||||
|
||||
for (i = 0; i < (s32)afl->queue_cur->len && dst < len; i++)
|
||||
if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i];
|
||||
|
||||
// FIXME DEBUG TODO XXX
|
||||
for (i = 0; i < (s32)afl->queue_cur->len; i++) {
|
||||
|
||||
switch (afl->taint_map[i]) {
|
||||
|
||||
case 0x0:
|
||||
break;
|
||||
case '!':
|
||||
j++;
|
||||
break;
|
||||
default:
|
||||
FATAL(
|
||||
"invalid taint map entry byte 0x%02x at position %d "
|
||||
"(passed_det:%d)\n",
|
||||
afl->taint_map[i], i, afl->queue_cur->passed_det);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (j != len)
|
||||
FATAL("different taint values in map vs in queue (%d != %d)", j, len);
|
||||
|
||||
break;
|
||||
|
||||
case 0: // fuzz only newly tainted bytes
|
||||
|
||||
fd = open(afl->taint_input_file, O_RDONLY);
|
||||
temp_len = len = afl->taint_len = afl->queue_cur->taint_bytes_new;
|
||||
orig_in = in_buf =
|
||||
mmap(0, len >= MAX_FILE - 65536 ? MAX_FILE : len + 65536,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
if (fd < 0 || (ssize_t)in_buf == -1)
|
||||
FATAL("unable to open '%s'", afl->taint_input_file);
|
||||
close(fd);
|
||||
|
||||
u8 *fn = alloc_printf("%s.new", afl->queue_cur->fname_taint);
|
||||
if (!fn) FATAL("OOM");
|
||||
fd = open(fn, O_RDWR);
|
||||
afl->taint_map = mmap(0, afl->queue_cur->len, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE, fd, 0);
|
||||
if (fd < 0 || (ssize_t)in_buf == -1)
|
||||
FATAL("unable to open '%s' for %u bytes", fn, len);
|
||||
close(fd);
|
||||
ck_free(fn);
|
||||
|
||||
for (i = 0; i < (s32)afl->queue_cur->len && dst < len; i++)
|
||||
if (afl->taint_map[i]) in_buf[dst++] = afl->taint_src[i];
|
||||
|
||||
// FIXME DEBUG TODO XXX
|
||||
for (i = 0; i < (s32)afl->queue_cur->len; i++) {
|
||||
|
||||
switch (afl->taint_map[i]) {
|
||||
|
||||
case 0x0:
|
||||
break;
|
||||
case '!':
|
||||
j++;
|
||||
break;
|
||||
default:
|
||||
FATAL(
|
||||
"invalid taint map entry byte 0x%02x at position %d "
|
||||
"(passed_det:%d)\n",
|
||||
afl->taint_map[i], i, afl->queue_cur->passed_det);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (j != len)
|
||||
FATAL("different taint values in map vs in queue (%d != %d)", j, len);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Map the test case into memory. */
|
||||
|
||||
fd = open(afl->queue_cur->fname, O_RDONLY);
|
||||
@ -621,8 +480,6 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
|
||||
close(fd);
|
||||
|
||||
}
|
||||
|
||||
/* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every
|
||||
single byte anyway, so it wouldn't give us any performance or memory usage
|
||||
benefits. */
|
||||
@ -645,12 +502,8 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
|
||||
afl->queue_cur->exec_cksum = 0;
|
||||
|
||||
if (unlikely(afl->taint_needs_splode))
|
||||
res = calibrate_case(afl, afl->queue_cur, afl->taint_src,
|
||||
afl->queue_cycle - 1, 0);
|
||||
else
|
||||
res = calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1,
|
||||
0);
|
||||
res =
|
||||
calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0);
|
||||
|
||||
if (unlikely(res == FSRV_RUN_ERROR)) {
|
||||
|
||||
@ -673,8 +526,8 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
* TRIMMING *
|
||||
************/
|
||||
|
||||
if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
|
||||
!afl->disable_trim && !afl->taint_needs_splode)) {
|
||||
if (!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
|
||||
!afl->disable_trim) {
|
||||
|
||||
u8 res = trim_case(afl, afl->queue_cur, in_buf);
|
||||
|
||||
@ -711,26 +564,13 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
|
||||
if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) {
|
||||
|
||||
int res;
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
if (input_to_state_stage(afl, in_buf, out_buf, len,
|
||||
afl->queue_cur->exec_cksum)) {
|
||||
|
||||
len = afl->queue_cur->len;
|
||||
memcpy(out_buf, afl->taint_src, len);
|
||||
res = input_to_state_stage(afl, afl->taint_src, out_buf, len,
|
||||
afl->queue_cur->exec_cksum);
|
||||
// just abandon as success
|
||||
ret_val = 0;
|
||||
res = 1;
|
||||
|
||||
} else {
|
||||
|
||||
res = input_to_state_stage(afl, in_buf, out_buf, len,
|
||||
afl->queue_cur->exec_cksum);
|
||||
goto abandon_entry;
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(res)) { goto abandon_entry; }
|
||||
|
||||
}
|
||||
|
||||
/* Skip right away if -d is given, if it has not been chosen sufficiently
|
||||
@ -2293,19 +2133,9 @@ havoc_stage:
|
||||
|
||||
if (actually_clone) {
|
||||
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
|
||||
clone_len = choose_block_len(afl, afl->queue_cur->len);
|
||||
clone_from =
|
||||
rand_below(afl, afl->queue_cur->len - clone_len + 1);
|
||||
|
||||
} else {
|
||||
|
||||
clone_len = choose_block_len(afl, temp_len);
|
||||
clone_from = rand_below(afl, temp_len - clone_len + 1);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
clone_len = choose_block_len(afl, HAVOC_BLK_XL);
|
||||
@ -2326,10 +2156,6 @@ havoc_stage:
|
||||
|
||||
if (actually_clone) {
|
||||
|
||||
if (unlikely(afl->taint_needs_splode))
|
||||
memcpy(new_buf + clone_to, afl->taint_src + clone_from,
|
||||
clone_len);
|
||||
else
|
||||
memcpy(new_buf + clone_to, out_buf + clone_from, clone_len);
|
||||
|
||||
} else {
|
||||
@ -2342,7 +2168,7 @@ havoc_stage:
|
||||
}
|
||||
|
||||
/* Tail */
|
||||
memmove(new_buf + clone_to + clone_len, out_buf + clone_to,
|
||||
memcpy(new_buf + clone_to + clone_len, out_buf + clone_to,
|
||||
temp_len - clone_to);
|
||||
|
||||
swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
|
||||
@ -2363,52 +2189,19 @@ havoc_stage:
|
||||
|
||||
if (temp_len < 2) { break; }
|
||||
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
|
||||
copy_len = choose_block_len(afl, afl->queue_cur->len - 1);
|
||||
copy_from = rand_below(afl, afl->queue_cur->len - copy_len + 1);
|
||||
copy_to = rand_below(afl, temp_len + 1);
|
||||
|
||||
} else {
|
||||
|
||||
copy_len = choose_block_len(afl, temp_len - 1);
|
||||
|
||||
copy_from = rand_below(afl, temp_len - copy_len + 1);
|
||||
copy_to = rand_below(afl, temp_len - copy_len + 1);
|
||||
|
||||
}
|
||||
|
||||
if (rand_below(afl, 4)) {
|
||||
|
||||
if (copy_from != copy_to) {
|
||||
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
|
||||
if (temp_len >= (s32)(copy_to + copy_len)) {
|
||||
|
||||
memcpy(out_buf + copy_to, afl->taint_src + copy_from,
|
||||
copy_len);
|
||||
|
||||
} else {
|
||||
|
||||
u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch),
|
||||
copy_to + copy_len);
|
||||
memcpy(new_buf, in_buf, copy_to);
|
||||
memcpy(new_buf + copy_to, afl->taint_src + copy_from,
|
||||
copy_len);
|
||||
swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
|
||||
out_buf = new_buf;
|
||||
temp_len = copy_to + copy_len;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
memmove(out_buf + copy_to, out_buf + copy_from, copy_len);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
memset(out_buf + copy_to,
|
||||
@ -2671,17 +2464,10 @@ havoc_stage:
|
||||
splices them together at some offset, then relies on the havoc
|
||||
code to mutate that blob. */
|
||||
|
||||
u32 saved_len;
|
||||
|
||||
if (unlikely(afl->taint_needs_splode))
|
||||
saved_len = afl->taint_len;
|
||||
else
|
||||
saved_len = afl->queue_cur->len;
|
||||
|
||||
retry_splicing:
|
||||
|
||||
if (afl->use_splicing && splice_cycle++ < SPLICE_CYCLES &&
|
||||
afl->queued_paths > 1 && saved_len > 1) {
|
||||
afl->queued_paths > 1 && afl->queue_cur->len > 1) {
|
||||
|
||||
struct queue_entry *target;
|
||||
u32 tid, split_at;
|
||||
@ -2694,7 +2480,7 @@ retry_splicing:
|
||||
if (in_buf != orig_in) {
|
||||
|
||||
in_buf = orig_in;
|
||||
len = saved_len;
|
||||
len = afl->queue_cur->len;
|
||||
|
||||
}
|
||||
|
||||
@ -2765,8 +2551,6 @@ retry_splicing:
|
||||
|
||||
ret_val = 0;
|
||||
|
||||
goto abandon_entry;
|
||||
|
||||
/* we are through with this queue entry - for this iteration */
|
||||
abandon_entry:
|
||||
|
||||
@ -2786,18 +2570,8 @@ abandon_entry:
|
||||
|
||||
++afl->queue_cur->fuzz_level;
|
||||
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
|
||||
munmap(afl->taint_src, afl->queue_cur->len);
|
||||
munmap(orig_in, afl->taint_len);
|
||||
munmap(afl->taint_map, afl->queue_cur->len);
|
||||
|
||||
} else {
|
||||
|
||||
munmap(orig_in, afl->queue_cur->len);
|
||||
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
|
||||
#undef FLIP_BIT
|
||||
|
@ -103,169 +103,6 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
|
||||
|
||||
}
|
||||
|
||||
void perform_taint_run(afl_state_t *afl, struct queue_entry *q, u8 *fname,
|
||||
u8 *mem, u32 len) {
|
||||
|
||||
u8 * ptr, *fn = fname;
|
||||
u32 bytes = 0, plen = len;
|
||||
struct queue_entry *prev = q->prev;
|
||||
|
||||
if (plen % 4) plen = plen + 4 - (len % 4);
|
||||
|
||||
if ((ptr = strrchr(fname, '/')) != NULL) fn = ptr + 1;
|
||||
q->fname_taint = alloc_printf("%s/taint/%s", afl->out_dir, fn);
|
||||
|
||||
if (q->fname_taint) {
|
||||
|
||||
u8 *save = ck_maybe_grow(BUF_PARAMS(out_scratch), afl->fsrv.map_size);
|
||||
memcpy(save, afl->taint_fsrv.trace_bits, afl->fsrv.map_size);
|
||||
|
||||
afl->taint_fsrv.map_size = plen; // speed :)
|
||||
write_to_testcase(afl, mem, len);
|
||||
if (afl_fsrv_run_target(&afl->taint_fsrv, afl->fsrv.exec_tmout * 4,
|
||||
&afl->stop_soon) == 0) {
|
||||
|
||||
bytes = q->taint_bytes_all =
|
||||
count_bytes_len(afl, afl->taint_fsrv.trace_bits, plen);
|
||||
if (afl->debug)
|
||||
fprintf(stderr, "Debug: tainted %u out of %u bytes\n", bytes, len);
|
||||
|
||||
/* DEBUG FIXME TODO XXX */
|
||||
u32 i;
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
if (afl->taint_fsrv.trace_bits[i] &&
|
||||
afl->taint_fsrv.trace_bits[i] != '!')
|
||||
FATAL("invalid taint map value %02x at pos %d",
|
||||
afl->taint_fsrv.trace_bits[i], i);
|
||||
|
||||
}
|
||||
|
||||
if (len < plen)
|
||||
for (i = len; i < plen; i++) {
|
||||
|
||||
if (afl->taint_fsrv.trace_bits[i])
|
||||
FATAL("invalid taint map value %02x in padding at pos %d",
|
||||
afl->taint_fsrv.trace_bits[i], i);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if all is tainted we do not need to write taint data away
|
||||
if (bytes && bytes < len) {
|
||||
|
||||
// save the bytes away
|
||||
int w = open(q->fname_taint, O_CREAT | O_WRONLY, 0644);
|
||||
if (w >= 0) {
|
||||
|
||||
ck_write(w, afl->taint_fsrv.trace_bits, len, q->fname_taint);
|
||||
close(w);
|
||||
|
||||
// find the highest tainted offset in the input (for trim opt)
|
||||
s32 i = len;
|
||||
while (i > 0 && !afl->taint_fsrv.trace_bits[i - 1])
|
||||
i--;
|
||||
q->taint_bytes_highest = i;
|
||||
|
||||
afl->taint_count++;
|
||||
|
||||
} else {
|
||||
|
||||
FATAL("could not create %s", q->fname_taint);
|
||||
q->taint_bytes_all = bytes = 0;
|
||||
|
||||
}
|
||||
|
||||
// it is possible that there is no main taint file - if the whole file
|
||||
// is tainted - but a .new taint file if it had new tainted bytes
|
||||
|
||||
// check if there is a previous queue entry and if it had taint
|
||||
if (bytes && prev && prev->taint_bytes_all &&
|
||||
prev->taint_bytes_all < prev->len) {
|
||||
|
||||
// check if there are new bytes in the taint vs the previous
|
||||
int r = open(prev->fname_taint, O_RDONLY);
|
||||
|
||||
if (r >= 0) {
|
||||
|
||||
u8 *bufr = mmap(0, prev->len, PROT_READ, MAP_PRIVATE, r, 0);
|
||||
|
||||
if ((ssize_t)bufr != -1) {
|
||||
|
||||
u32 i;
|
||||
u8 *tmp = ck_maybe_grow(BUF_PARAMS(in_scratch), plen);
|
||||
memset(tmp, 0, plen);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (afl->taint_fsrv.trace_bits[i] && (i >= prev->len || !bufr[i]))
|
||||
tmp[i] = '!';
|
||||
|
||||
q->taint_bytes_new = count_bytes_len(afl, tmp, plen);
|
||||
|
||||
if (afl->debug)
|
||||
fprintf(stderr, "Debug: %u new taint out of %u bytes\n", bytes,
|
||||
len);
|
||||
|
||||
if (q->taint_bytes_new) {
|
||||
|
||||
u8 *fnw = alloc_printf("%s.new", q->fname_taint);
|
||||
if (fnw) {
|
||||
|
||||
int w = open(fnw, O_CREAT | O_WRONLY, 0644);
|
||||
if (w >= 0) {
|
||||
|
||||
ck_write(w, tmp, plen, fnw);
|
||||
close(w);
|
||||
|
||||
} else {
|
||||
|
||||
FATAL("count not create '%s'", fnw);
|
||||
q->taint_bytes_new = 0;
|
||||
|
||||
}
|
||||
|
||||
ck_free(fnw);
|
||||
|
||||
} else {
|
||||
|
||||
q->taint_bytes_new = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
munmap(bufr, prev->len);
|
||||
|
||||
}
|
||||
|
||||
close(r);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
memcpy(afl->taint_fsrv.trace_bits, save, afl->fsrv.map_size);
|
||||
|
||||
}
|
||||
|
||||
if (!bytes) {
|
||||
|
||||
q->taint_bytes_highest = q->taint_bytes_all = q->taint_bytes_new = 0;
|
||||
|
||||
if (q->fname_taint) {
|
||||
|
||||
ck_free(q->fname_taint);
|
||||
q->fname_taint = NULL;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* check if ascii or UTF-8 */
|
||||
|
||||
static u8 check_if_text(struct queue_entry *q) {
|
||||
@ -375,12 +212,10 @@ static u8 check_if_text(struct queue_entry *q) {
|
||||
|
||||
/* Append new test case to the queue. */
|
||||
|
||||
void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len,
|
||||
struct queue_entry *prev_q, u8 passed_det) {
|
||||
void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
|
||||
|
||||
struct queue_entry *q = ck_alloc(sizeof(struct queue_entry));
|
||||
|
||||
q->prev = prev_q;
|
||||
q->fname = fname;
|
||||
q->len = len;
|
||||
q->depth = afl->cur_depth + 1;
|
||||
@ -419,13 +254,6 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len,
|
||||
|
||||
afl->last_path_time = get_cur_time();
|
||||
|
||||
/* trigger the tain gathering if this is not a dry run */
|
||||
if (afl->taint_mode && mem) { perform_taint_run(afl, q, fname, mem, len); }
|
||||
|
||||
/* only redqueen currently uses is_ascii */
|
||||
if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q);
|
||||
|
||||
/* run custom mutators afl_custom_queue_new_entry() */
|
||||
if (afl->custom_mutators_count) {
|
||||
|
||||
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
||||
@ -445,6 +273,9 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u8 *mem, u32 len,
|
||||
|
||||
}
|
||||
|
||||
/* only redqueen currently uses is_ascii */
|
||||
if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(q);
|
||||
|
||||
}
|
||||
|
||||
/* Destroy the entire queue. */
|
||||
|
@ -350,9 +350,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(afl->taint_mode))
|
||||
q->exec_cksum = 0;
|
||||
else if (q->exec_cksum) {
|
||||
if (q->exec_cksum) {
|
||||
|
||||
memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
|
||||
hnb = has_new_bits(afl, afl->virgin_bits);
|
||||
@ -755,10 +753,6 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
|
||||
while (remove_pos < q->len) {
|
||||
|
||||
u32 trim_avail = MIN(remove_len, q->len - remove_pos);
|
||||
|
||||
if (likely((!q->taint_bytes_highest) ||
|
||||
(q->len - trim_avail > q->taint_bytes_highest))) {
|
||||
|
||||
u64 cksum;
|
||||
|
||||
write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail);
|
||||
@ -805,15 +799,10 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
|
||||
}
|
||||
|
||||
/* Since this can be slow, update the screen every now and then. */
|
||||
|
||||
if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); }
|
||||
++afl->stage_cur;
|
||||
|
||||
} else {
|
||||
|
||||
remove_pos += remove_len;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
remove_len >>= 1;
|
||||
@ -866,8 +855,6 @@ abort_trimming:
|
||||
|
||||
}
|
||||
|
||||
#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
|
||||
|
||||
/* Write a modified test case, run program, process results. Handle
|
||||
error conditions, returning 1 if it's time to bail out. This is
|
||||
a helper function for fuzz_one(). */
|
||||
@ -877,32 +864,6 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
|
||||
|
||||
u8 fault;
|
||||
|
||||
if (unlikely(afl->taint_needs_splode)) {
|
||||
|
||||
s32 new_len = afl->queue_cur->len + len - afl->taint_len;
|
||||
if (new_len < 4)
|
||||
new_len = 4;
|
||||
else if (new_len > MAX_FILE)
|
||||
new_len = MAX_FILE;
|
||||
u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), new_len);
|
||||
|
||||
u32 i, taint = 0;
|
||||
for (i = 0; i < (u32)new_len; i++) {
|
||||
|
||||
if (i >= afl->taint_len || i >= afl->queue_cur->len || afl->taint_map[i])
|
||||
new_buf[i] = out_buf[taint++];
|
||||
else
|
||||
new_buf[i] = afl->taint_src[i];
|
||||
|
||||
}
|
||||
|
||||
swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
|
||||
|
||||
out_buf = new_buf;
|
||||
len = new_len;
|
||||
|
||||
}
|
||||
|
||||
write_to_testcase(afl, out_buf, len);
|
||||
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
@ -950,5 +911,3 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
|
||||
|
||||
}
|
||||
|
||||
#undef BUF_PARAMS
|
||||
|
||||
|
@ -75,7 +75,7 @@ static list_t afl_states = {.element_prealloc_count = 0};
|
||||
|
||||
/* Initializes an afl_state_t. */
|
||||
|
||||
void afl_state_init_1(afl_state_t *afl, uint32_t map_size) {
|
||||
void afl_state_init(afl_state_t *afl, uint32_t map_size) {
|
||||
|
||||
/* thanks to this memset, growing vars like out_buf
|
||||
and out_size are NULL/0 by default. */
|
||||
@ -100,6 +100,16 @@ void afl_state_init_1(afl_state_t *afl, uint32_t map_size) {
|
||||
afl->cpu_aff = -1; /* Selected CPU core */
|
||||
#endif /* HAVE_AFFINITY */
|
||||
|
||||
afl->virgin_bits = ck_alloc(map_size);
|
||||
afl->virgin_tmout = ck_alloc(map_size);
|
||||
afl->virgin_crash = ck_alloc(map_size);
|
||||
afl->var_bytes = ck_alloc(map_size);
|
||||
afl->top_rated = ck_alloc(map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_alloc(map_size);
|
||||
afl->clean_trace_custom = ck_alloc(map_size);
|
||||
afl->first_trace = ck_alloc(map_size);
|
||||
afl->map_tmp_buf = ck_alloc(map_size);
|
||||
|
||||
afl->fsrv.use_stdin = 1;
|
||||
afl->fsrv.map_size = map_size;
|
||||
// afl_state_t is not available in forkserver.c
|
||||
@ -151,24 +161,6 @@ void afl_state_init_1(afl_state_t *afl, uint32_t map_size) {
|
||||
|
||||
}
|
||||
|
||||
void afl_state_init_2(afl_state_t *afl, uint32_t map_size) {
|
||||
|
||||
afl->shm.map_size = map_size ? map_size : MAP_SIZE;
|
||||
|
||||
afl->virgin_bits = ck_alloc(map_size);
|
||||
afl->virgin_tmout = ck_alloc(map_size);
|
||||
afl->virgin_crash = ck_alloc(map_size);
|
||||
afl->var_bytes = ck_alloc(map_size);
|
||||
afl->top_rated = ck_alloc(map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_alloc(map_size);
|
||||
afl->clean_trace_custom = ck_alloc(map_size);
|
||||
afl->first_trace = ck_alloc(map_size);
|
||||
afl->map_tmp_buf = ck_alloc(map_size);
|
||||
|
||||
afl->fsrv.map_size = map_size;
|
||||
|
||||
}
|
||||
|
||||
/*This sets up the environment variables for afl-fuzz into the afl_state
|
||||
* struct*/
|
||||
|
||||
|
@ -116,7 +116,6 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
|
||||
"edges_found : %u\n"
|
||||
"var_byte_count : %u\n"
|
||||
"havoc_expansion : %u\n"
|
||||
"tainted_inputs : %u\n"
|
||||
"afl_banner : %s\n"
|
||||
"afl_version : " VERSION
|
||||
"\n"
|
||||
@ -150,8 +149,8 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
|
||||
#else
|
||||
-1,
|
||||
#endif
|
||||
t_bytes, afl->var_byte_count, afl->expand_havoc, afl->taint_count,
|
||||
afl->use_banner, afl->unicorn_mode ? "unicorn" : "",
|
||||
t_bytes, afl->var_byte_count, afl->expand_havoc, afl->use_banner,
|
||||
afl->unicorn_mode ? "unicorn" : "",
|
||||
afl->fsrv.qemu_mode ? "qemu " : "",
|
||||
afl->non_instrumented_mode ? " non_instrumented " : "",
|
||||
afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "",
|
||||
|
123
src/afl-fuzz.c
123
src/afl-fuzz.c
@ -53,9 +53,6 @@ static void at_exit() {
|
||||
ptr = getenv("__AFL_TARGET_PID2");
|
||||
if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
|
||||
|
||||
ptr = getenv("__AFL_TARGET_PID3");
|
||||
if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
|
||||
|
||||
i = 0;
|
||||
while (list[i] != NULL) {
|
||||
|
||||
@ -92,8 +89,6 @@ static void usage(u8 *argv0, int more_help) {
|
||||
" -o dir - output directory for fuzzer findings\n\n"
|
||||
|
||||
"Execution control settings:\n"
|
||||
" -A - use first level taint analysis (see "
|
||||
"qemu_taint/README.md)\n"
|
||||
" -p schedule - power schedules compute a seed's performance score. "
|
||||
"<explore\n"
|
||||
" (default), fast, coe, lin, quad, exploit, mmopt, "
|
||||
@ -246,8 +241,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
s32 opt;
|
||||
u64 prev_queued = 0;
|
||||
u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE,
|
||||
real_map_size = 0;
|
||||
u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE;
|
||||
u8 * extras_dir = 0;
|
||||
u8 mem_limit_given = 0, exit_1 = 0, debug = 0;
|
||||
char **use_argv;
|
||||
@ -263,7 +257,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (get_afl_env("AFL_DEBUG")) { debug = afl->debug = 1; }
|
||||
|
||||
map_size = get_map_size();
|
||||
afl_state_init_1(afl, map_size);
|
||||
afl_state_init(afl, map_size);
|
||||
afl->debug = debug;
|
||||
afl_fsrv_init(&afl->fsrv);
|
||||
|
||||
@ -283,15 +277,10 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
while ((opt = getopt(
|
||||
argc, argv,
|
||||
"+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QANUWe:p:s:V:E:L:hRP:")) > 0) {
|
||||
"+b:c:i:I:o:f:F:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
case 'A':
|
||||
afl->taint_mode = 1;
|
||||
if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; }
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
afl->infoexec = optarg;
|
||||
break;
|
||||
@ -499,7 +488,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (!optarg) { FATAL("Wrong usage of -m"); }
|
||||
|
||||
if (!strcmp(optarg, "none") || !strcmp(optarg, "0")) {
|
||||
if (!strcmp(optarg, "none")) {
|
||||
|
||||
afl->fsrv.mem_limit = 0;
|
||||
break;
|
||||
@ -829,15 +818,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->taint_mode && afl->fsrv.map_size < MAX_FILE) {
|
||||
|
||||
real_map_size = map_size;
|
||||
map_size = MAX_FILE;
|
||||
|
||||
}
|
||||
|
||||
afl_state_init_2(afl, map_size);
|
||||
|
||||
if (!mem_limit_given && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
|
||||
|
||||
OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
|
||||
@ -845,7 +825,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
OKF("afl++ is open source, get it at "
|
||||
"https://github.com/AFLplusplus/AFLplusplus");
|
||||
OKF("Power schedules from github.com/mboehme/aflfast");
|
||||
OKF("Python Mutator from github.com/choller/afl");
|
||||
OKF("Python Mutator and llvm_mode instrument file list from "
|
||||
"github.com/choller/afl");
|
||||
OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL");
|
||||
|
||||
if (afl->sync_id && afl->is_main_node &&
|
||||
@ -891,19 +872,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); }
|
||||
if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); }
|
||||
if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); }
|
||||
if (afl->taint_mode) { FATAL("-A and -n are mutually exclusive"); }
|
||||
|
||||
}
|
||||
|
||||
if (afl->limit_time_sig != 0 && afl->taint_mode) {
|
||||
|
||||
FATAL("-A and -L are mutually exclusive");
|
||||
|
||||
}
|
||||
|
||||
if (afl->unicorn_mode != 0 && afl->taint_mode) {
|
||||
|
||||
FATAL("-A and -U are mutually exclusive");
|
||||
|
||||
}
|
||||
|
||||
@ -1004,7 +972,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (afl->afl_env.afl_preload) {
|
||||
|
||||
if (afl->fsrv.qemu_mode || afl->taint_mode) {
|
||||
if (afl->fsrv.qemu_mode) {
|
||||
|
||||
u8 *qemu_preload = getenv("QEMU_SET_ENV");
|
||||
u8 *afl_preload = getenv("AFL_PRELOAD");
|
||||
@ -1100,13 +1068,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
|
||||
|
||||
if (real_map_size && map_size != real_map_size) {
|
||||
|
||||
afl->fsrv.map_size = real_map_size;
|
||||
if (afl->cmplog_binary) afl->cmplog_fsrv.map_size = real_map_size;
|
||||
|
||||
}
|
||||
|
||||
if (!afl->in_bitmap) { memset(afl->virgin_bits, 255, afl->fsrv.map_size); }
|
||||
memset(afl->virgin_tmout, 255, afl->fsrv.map_size);
|
||||
memset(afl->virgin_crash, 255, afl->fsrv.map_size);
|
||||
@ -1262,6 +1223,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
ACTF("Spawning cmplog forkserver");
|
||||
afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv);
|
||||
// TODO: this is semi-nice
|
||||
afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
|
||||
afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
|
||||
afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
|
||||
@ -1272,70 +1234,6 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->taint_mode) {
|
||||
|
||||
ACTF("Spawning qemu_taint forkserver");
|
||||
|
||||
u8 *disable = getenv("AFL_DISABLE_LLVM_INSTRUMENTATION");
|
||||
setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0);
|
||||
|
||||
afl_fsrv_init_dup(&afl->taint_fsrv, &afl->fsrv);
|
||||
afl->taint_fsrv.taint_mode = 1;
|
||||
afl->taint_fsrv.trace_bits = afl->fsrv.trace_bits;
|
||||
|
||||
ck_free(afl->taint_fsrv.target_path);
|
||||
afl->argv_taint = ck_alloc(sizeof(char *) * (argc + 4 - optind));
|
||||
afl->taint_fsrv.target_path = find_afl_binary("afl-qemu-taint", argv[0]);
|
||||
afl->argv_taint[0] = find_afl_binary("afl-qemu-taint", argv[0]);
|
||||
if (!afl->argv_taint[0])
|
||||
FATAL(
|
||||
"Cannot find 'afl-qemu-taint', read qemu_taint/README.md on how to "
|
||||
"build it.");
|
||||
u32 idx = optind - 1, offset = 0;
|
||||
do {
|
||||
|
||||
idx++;
|
||||
offset++;
|
||||
afl->argv_taint[offset] = argv[idx];
|
||||
|
||||
} while (argv[idx] != NULL);
|
||||
|
||||
if (afl->fsrv.use_stdin)
|
||||
unsetenv("AFL_TAINT_INPUT");
|
||||
else
|
||||
setenv("AFL_TAINT_INPUT", afl->fsrv.out_file, 1);
|
||||
afl_fsrv_start(&afl->taint_fsrv, afl->argv_taint, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child_output);
|
||||
|
||||
afl->taint_input_file = alloc_printf("%s/taint/.input", afl->out_dir);
|
||||
int fd = open(afl->taint_input_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
|
||||
if (fd < 0)
|
||||
FATAL("Cannot create taint inpu file '%s'", afl->taint_input_file);
|
||||
lseek(fd, MAX_FILE, SEEK_SET);
|
||||
ck_write(fd, "\0", 1, afl->taint_input_file);
|
||||
|
||||
if (!disable) unsetenv("AFL_DISABLE_LLVM_INSTRUMENTATION");
|
||||
|
||||
OKF("Taint forkserver successfully started");
|
||||
|
||||
const rlim_t kStackSize = 128L * 1024L * 1024L; // min stack size = 128 Mb
|
||||
struct rlimit rl;
|
||||
rl.rlim_cur = kStackSize;
|
||||
if (getrlimit(RLIMIT_STACK, &rl) != 0)
|
||||
WARNF("Setting a higher stack size failed!");
|
||||
|
||||
#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
|
||||
u8 *tmp1 = ck_maybe_grow(BUF_PARAMS(eff), MAX_FILE + 4096);
|
||||
u8 *tmp2 = ck_maybe_grow(BUF_PARAMS(ex), MAX_FILE + 4096);
|
||||
u8 *tmp3 = ck_maybe_grow(BUF_PARAMS(in_scratch), MAX_FILE + 4096);
|
||||
u8 *tmp4 = ck_maybe_grow(BUF_PARAMS(out), MAX_FILE + 4096);
|
||||
u8 *tmp5 = ck_maybe_grow(BUF_PARAMS(out_scratch), MAX_FILE + 4096);
|
||||
#undef BUF_PARAMS
|
||||
if (!tmp1 || !tmp2 || !tmp3 || !tmp4 || !tmp5)
|
||||
FATAL("memory issues. me hungry, feed me!");
|
||||
|
||||
}
|
||||
|
||||
perform_dry_run(afl);
|
||||
|
||||
cull_queue(afl);
|
||||
@ -1410,7 +1308,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
break;
|
||||
case 1:
|
||||
if (afl->limit_time_sig == 0 && !afl->custom_only &&
|
||||
!afl->python_only && !afl->taint_mode) {
|
||||
!afl->python_only) {
|
||||
|
||||
afl->limit_time_sig = -1;
|
||||
afl->limit_time_puppet = 0;
|
||||
@ -1598,11 +1496,8 @@ stop_fuzzing:
|
||||
|
||||
}
|
||||
|
||||
if (afl->cmplog_binary) afl_fsrv_deinit(&afl->cmplog_fsrv);
|
||||
if (afl->taint_mode) afl_fsrv_deinit(&afl->taint_fsrv);
|
||||
afl_fsrv_deinit(&afl->fsrv);
|
||||
if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); }
|
||||
if (afl->argv_taint) { ck_free(afl->argv_taint); }
|
||||
ck_free(afl->fsrv.target_path);
|
||||
ck_free(afl->fsrv.out_file);
|
||||
ck_free(afl->sync_id);
|
||||
|
Reference in New Issue
Block a user