Initial import unicornafl
This commit is contained in:
49
include/afl/afl-common.h
Normal file
49
include/afl/afl-common.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
american fuzzy lop++ - unicorn instrumentation
|
||||
----------------------------------------------
|
||||
|
||||
Originally written by Andrew Griffiths <agriffiths@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
Adapted for afl-unicorn by Dominik Maier <mail@dmnk.co>
|
||||
|
||||
CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
<andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is a shim patched into the separately-distributed source
|
||||
code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality
|
||||
to implement AFL-style instrumentation and to take care of the remaining
|
||||
parts of the AFL fork server logic.
|
||||
|
||||
The resulting libunicorn binary is essentially a standalone instrumentation
|
||||
tool; for an example of how to leverage it for other purposes, you can
|
||||
have a look at afl-showmap.c.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
/* NeverZero */
|
||||
|
||||
#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO)
|
||||
#define INC_AFL_AREA(loc) \
|
||||
asm volatile( \
|
||||
"addb $1, (%0, %1, 1)\n" \
|
||||
"adcb $0, (%0, %1, 1)\n" \
|
||||
: /* no out */ \
|
||||
: "r"(afl_area_ptr), "r"(loc) \
|
||||
: "memory", "eax")
|
||||
#else
|
||||
#define INC_AFL_AREA(loc) afl_area_ptr[loc]++
|
||||
#endif
|
||||
|
521
include/afl/afl-cpu-inl.h
Normal file
521
include/afl/afl-cpu-inl.h
Normal file
@ -0,0 +1,521 @@
|
||||
/*
|
||||
american fuzzy lop++ - unicorn instrumentation
|
||||
----------------------------------------------
|
||||
|
||||
Originally written by Andrew Griffiths <agriffiths@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
Adapted for afl-unicorn by Dominik Maier <mail@dmnk.co>
|
||||
|
||||
CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
<andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is a shim patched into the separately-distributed source
|
||||
code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality
|
||||
to implement AFL-style instrumentation and to take care of the remaining
|
||||
parts of the AFL fork server logic.
|
||||
|
||||
The resulting libunicorn binary is essentially a standalone instrumentation
|
||||
tool; for an example of how to leverage it for other purposes, you can
|
||||
have a look at afl-showmap.c.
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/shm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unicorn.h>
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "afl-common.h"
|
||||
|
||||
/* We use one additional file descriptor to relay "needs translation"
|
||||
or "child done" messages between the child and the fork server. */
|
||||
|
||||
#define FF16 (0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
/* Copied from aflpp/types.h to talk to forkserver */
|
||||
#define FS_OPT_ENABLED 0x80000001
|
||||
#define FS_OPT_SHDMEM_FUZZ 0x01000000
|
||||
|
||||
/**
|
||||
* The correct fds for reading and writing pipes
|
||||
*/
|
||||
|
||||
#define _R(pipe) ((pipe)[0])
|
||||
#define _W(pipe) ((pipe)[1])
|
||||
|
||||
/* Function declarations. */
|
||||
|
||||
static void afl_setup(struct uc_struct*);
|
||||
static inline uc_afl_ret afl_forkserver(CPUState*);
|
||||
static int afl_find_wifsignaled_id(void);
|
||||
|
||||
static enum afl_child_ret afl_handle_child_requests(CPUState*);
|
||||
static void afl_request_tsl(CPUState *cpu, target_ulong, target_ulong, uint64_t, uint32_t);
|
||||
static uc_afl_ret afl_request_next(struct uc_struct* uc, bool found_crash);
|
||||
|
||||
// static TranslationBlock* tb_find_slow(CPUArchState*, target_ulong, target_ulong, uint64_t);
|
||||
|
||||
/* Data structure passed around by the translate handlers: */
|
||||
|
||||
struct afl_tsl {
|
||||
|
||||
target_ulong pc;
|
||||
target_ulong cs_base;
|
||||
uint64_t flags;
|
||||
uint32_t cf_mask;
|
||||
#if defined(TARGET_MIPS)
|
||||
TCGv_i32 hflags;
|
||||
TCGv_i32 btarget;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/* Current state, as forwarded from forkserver child to parent */
|
||||
|
||||
enum afl_child_ret {
|
||||
|
||||
// Persistent
|
||||
AFL_CHILD_NEXT,
|
||||
// Crash discovered but still alive in persistent mode
|
||||
AFL_CHILD_FOUND_CRASH,
|
||||
// Read again, one afl_tsl struct.
|
||||
AFL_CHILD_TSL_REQUEST,
|
||||
// Child no longer there. Read status code.
|
||||
AFL_CHILD_EXITED,
|
||||
|
||||
};
|
||||
|
||||
static int wifsignaled;
|
||||
|
||||
/*************************
|
||||
* ACTUAL IMPLEMENTATION *
|
||||
*************************/
|
||||
|
||||
/* Set up SHM region and initialize other stuff. */
|
||||
|
||||
static void afl_setup(struct uc_struct* uc) {
|
||||
|
||||
char *id_str = getenv(SHM_ENV_VAR);
|
||||
char *inst_r = getenv("AFL_INST_RATIO");
|
||||
|
||||
// A value we can use to tell AFL our persistent mode found a crash
|
||||
wifsignaled = afl_find_wifsignaled_id();
|
||||
|
||||
int shm_id;
|
||||
|
||||
if (inst_r) {
|
||||
|
||||
unsigned int r;
|
||||
|
||||
r = atoi(inst_r);
|
||||
|
||||
if (r > 100) r = 100;
|
||||
if (!r) r = 1;
|
||||
|
||||
uc->afl_inst_rms = MAP_SIZE * r / 100;
|
||||
|
||||
} else {
|
||||
|
||||
uc->afl_inst_rms = MAP_SIZE;
|
||||
|
||||
}
|
||||
|
||||
if (id_str) {
|
||||
|
||||
shm_id = atoi(id_str);
|
||||
uc->afl_area_ptr = shmat(shm_id, NULL, 0);
|
||||
uc->afl_prev_loc = 0;
|
||||
uc->afl_area_ptr[0] = 1;
|
||||
|
||||
if (uc->afl_area_ptr == (void*)-1) exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* Maintain for compatibility */
|
||||
if (getenv("AFL_QEMU_COMPCOV")) { uc->afl_compcov_level = 1; }
|
||||
if (getenv("AFL_COMPCOV_LEVEL")) {
|
||||
|
||||
uc->afl_compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL"));
|
||||
|
||||
}
|
||||
#if defined(AFL_DEBUG)
|
||||
if (uc->afl_compcov_level) {
|
||||
printf("[d] USING AFL_COMPCOV_LEVEL %d\n", uc->afl_compcov_level);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Some dirty hack to come up with a valid statuscode that AFL will just accept.
|
||||
|
||||
static int afl_find_wifsignaled_id(void) {
|
||||
|
||||
int ret = 0; // A faux status code that AFL will accept as signaled/crashed. 1 on linux.
|
||||
while (!(WIFSIGNALED(ret))) ret++;
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] wifsignaled is %d (WIFSIGNALED(x)=%d)\n", ret, WIFSIGNALED(ret));
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Fork server logic, invoked by calling uc_afl_forkserver_start.
|
||||
Roughly follows https://github.com/vanhauser-thc/AFLplusplus/blob/c83e8e1e6255374b085292ba8673efdca7388d76/llvm_mode/afl-llvm-rt.o.c#L130
|
||||
*/
|
||||
|
||||
static inline uc_afl_ret afl_forkserver(CPUState* cpu) {
|
||||
|
||||
unsigned char tmp[4] = {0};
|
||||
pid_t child_pid;
|
||||
enum afl_child_ret child_ret = AFL_CHILD_EXITED;
|
||||
bool first_round = true;
|
||||
u32 status = 0;
|
||||
|
||||
if (!cpu->uc->afl_area_ptr) return UC_AFL_RET_NO_AFL;
|
||||
|
||||
if (cpu->uc->afl_testcase_ptr) {
|
||||
/* Parent supports testcases via shared map - and the user wants to use it. Tell AFL. */
|
||||
status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
|
||||
}
|
||||
|
||||
/* Phone home and tell the parent that we're OK. If parent isn't there,
|
||||
assume we're not running in forkserver mode and just execute program. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) return UC_AFL_RET_NO_AFL;
|
||||
|
||||
/* afl tells us in an extra message if it accepted this option or not */
|
||||
if (cpu->uc->afl_testcase_ptr && getenv(SHM_FUZZ_ENV_VAR)) {
|
||||
if (read(FORKSRV_FD, &status, 4) != 4) {
|
||||
fprintf(stderr, "[!] AFL parent exited before forkserver was up\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
if (status != (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
|
||||
fprintf(stderr, "[!] Unexpected response from AFL++ on forkserver setup\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
} else {
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] AFL++ sharedmap fuzzing not supported/SHM_FUZZ_ENV_VAR not set\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] Entering forkserver loop\n");
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
|
||||
uint32_t was_killed;
|
||||
int status;
|
||||
|
||||
/* Wait for parent by reading from the pipe. Abort if read fails. */
|
||||
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) return UC_AFL_RET_FINISHED;
|
||||
|
||||
/* If we stopped the child in persistent mode, but there was a race
|
||||
condition and afl-fuzz already issued SIGKILL, write off the old
|
||||
process. */
|
||||
|
||||
if ((child_ret != AFL_CHILD_EXITED) && was_killed) {
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] Child was killed by AFL in the meantime.\n");
|
||||
#endif
|
||||
|
||||
child_ret = AFL_CHILD_EXITED;
|
||||
if (waitpid(child_pid, &status, 0) < 0) {
|
||||
perror("[!] Error waiting for child!");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (child_ret == AFL_CHILD_EXITED) {
|
||||
|
||||
/* Child dead. Establish new a channel with child to grab translation commands.
|
||||
We'll read from _R(afl_child_pipe), child will write to _W(afl_child_pipe). */
|
||||
|
||||
/* close the read fd of previous round. */
|
||||
|
||||
if (_R(cpu->uc->afl_child_pipe)) {
|
||||
close(_R(cpu->uc->afl_child_pipe));
|
||||
close(_W(cpu->uc->afl_parent_pipe));
|
||||
}
|
||||
|
||||
if (pipe(cpu->uc->afl_child_pipe)) {
|
||||
perror("[!] Error creating pipe to child");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
if (pipe(cpu->uc->afl_parent_pipe)) {
|
||||
perror("[!] Error creating pipe to parent");
|
||||
close(_R(cpu->uc->afl_child_pipe));
|
||||
close(_W(cpu->uc->afl_child_pipe));
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
|
||||
/* Create a clone of our process. */
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid < 0) {
|
||||
perror("[!] Could not fork! ");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
|
||||
/* In child process: close fds, resume execution. */
|
||||
|
||||
if (!child_pid) { // New child
|
||||
|
||||
signal(SIGCHLD, old_sigchld_handler);
|
||||
// FORKSRV_FD is for communication with AFL, we don't need it in the child.
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
close(_R(cpu->uc->afl_child_pipe));
|
||||
close(_W(cpu->uc->afl_parent_pipe));
|
||||
cpu->uc->afl_child_request_next = afl_request_next;
|
||||
|
||||
memset(cpu->uc->afl_area_ptr, 0, MAP_SIZE);
|
||||
MEM_BARRIER(); // Make very sure everything has been written to the map at this point
|
||||
|
||||
if (!first_round) {
|
||||
|
||||
// For persistent mode: Clear the map manually after forks.
|
||||
memset(cpu->uc->afl_area_ptr, 0, MAP_SIZE);
|
||||
|
||||
} else {
|
||||
// For persistent mode: Clear the map manually after forks.
|
||||
//memset(env->uc->afl_area_ptr, 0, MAP_SIZE);
|
||||
|
||||
first_round = false;
|
||||
}
|
||||
|
||||
cpu->uc->afl_prev_loc = 0;
|
||||
// Tell AFL we're alive
|
||||
cpu->uc->afl_area_ptr[0] = 1;
|
||||
|
||||
return UC_AFL_RET_CHILD;
|
||||
|
||||
} else { // parent for new child
|
||||
|
||||
/* If we don't close this in parent, we don't get notified on afl_child_pipe once child is gone. */
|
||||
|
||||
close(_W(cpu->uc->afl_child_pipe));
|
||||
close(_R(cpu->uc->afl_parent_pipe));
|
||||
|
||||
}
|
||||
|
||||
} else { // parent, in persistent mode
|
||||
|
||||
/* Special handling for persistent mode: if the child is alive but
|
||||
currently stopped, simply restart it with a write to afl_parent_pipe.
|
||||
In case we fuzz using shared map, use this method to forward the size
|
||||
of the current testcase to the child without cost. */
|
||||
|
||||
if (write(_W(cpu->uc->afl_parent_pipe), tmp, 4) != 4) {
|
||||
|
||||
fprintf(stderr,"[!] Child died when we tried to resume it\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* In parent process: write PID to AFL. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) {
|
||||
return UC_AFL_RET_FINISHED;
|
||||
}
|
||||
|
||||
/* Collect translation requests until child finishes a run or dies */
|
||||
|
||||
child_ret = afl_handle_child_requests(cpu);
|
||||
|
||||
if (child_ret == AFL_CHILD_NEXT) {
|
||||
|
||||
/* Child asks for next in persistent mode */
|
||||
|
||||
status = 0;
|
||||
|
||||
} else if (child_ret == AFL_CHILD_FOUND_CRASH) {
|
||||
|
||||
/* WIFSIGNALED(wifsignaled) == 1 -> tells AFL the child crashed (even though it's still alive for persistent mode) */
|
||||
|
||||
status = wifsignaled;
|
||||
|
||||
} else if (child_ret == AFL_CHILD_EXITED) {
|
||||
|
||||
/* If child exited, get and relay exit status to parent through waitpid. */
|
||||
|
||||
if (waitpid(child_pid, &status, 0) < 0) {
|
||||
|
||||
// Zombie Child could not be collected. Scary!
|
||||
perror("[!] The child's exit code could not be determined. ");
|
||||
return UC_AFL_RET_ERROR;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Relay wait status to AFL pipe, then loop back. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) return UC_AFL_RET_FINISHED;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This code is invoked whenever Unicorn decides that it doesn't have a
|
||||
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
|
||||
cached copy. */
|
||||
|
||||
static inline void afl_request_tsl(CPUState *cpu, target_ulong pc, target_ulong cb, uint64_t flags, uint32_t cf_mask) {
|
||||
|
||||
/* Dual use: if this func is not set, we're not a child process */
|
||||
|
||||
struct uc_struct* uc = cpu->uc;
|
||||
if (uc->afl_child_request_next == NULL) return;
|
||||
enum afl_child_ret tsl_req = AFL_CHILD_TSL_REQUEST;
|
||||
|
||||
struct afl_tsl t = {
|
||||
.pc = pc,
|
||||
.cs_base = cb,
|
||||
.flags = flags,
|
||||
.cf_mask = cf_mask,
|
||||
#if defined(TARGET_MIPS)
|
||||
.hflags = cpu->uc->tcg_ctx->hflags,
|
||||
.btarget = cpu->uc->tcg_ctx->btarget,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("Requesting tsl, pc=0x%llx, cb=0x%llx, flags=0x%llx\n", (unsigned long long) pc, (unsigned long long) cb, (unsigned long long) flags);
|
||||
#endif
|
||||
|
||||
// We write tsl requests in two steps but that's fine since cache requests are not very common over the time of fuzzing.
|
||||
|
||||
if ((write(_W(uc->afl_child_pipe), &tsl_req, sizeof(enum afl_child_ret)) != sizeof(enum afl_child_ret))
|
||||
|| write(_W(uc->afl_child_pipe), &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) {
|
||||
|
||||
fprintf(stderr, "Error writing to child pipe. Parent dead?\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This code is invoked whenever the child decides that it is done with one fuzz-case. */
|
||||
|
||||
static uc_afl_ret afl_request_next(struct uc_struct* uc, bool crash_found) {
|
||||
|
||||
enum afl_child_ret msg = crash_found? AFL_CHILD_FOUND_CRASH : AFL_CHILD_NEXT;
|
||||
char tmp[4];
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] request next. crash found: %s\n", crash_found ? "true": "false");
|
||||
#endif
|
||||
|
||||
MEM_BARRIER(); // Make very sure everything has been written to the map at this point
|
||||
|
||||
if (write(_W(uc->afl_child_pipe), &msg, sizeof(msg)) != sizeof(msg)) {
|
||||
|
||||
fprintf(stderr, "[!] Error writing to parent pipe. Parent dead?\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
|
||||
}
|
||||
|
||||
// Once the parent has written something, the next persistent loop starts.
|
||||
// The parent itself will wait for AFL to signal the new testcases is available.
|
||||
// This blocks until the next testcase is ready.
|
||||
if (read(_R(uc->afl_parent_pipe), tmp, 4) != 4) {
|
||||
|
||||
fprintf(stderr, "[!] Error reading from parent pipe. Parent dead?\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
|
||||
}
|
||||
|
||||
/* For shared map fuzzing, the forkserver parent forwards the size of the current testcase. */
|
||||
memset(uc->afl_area_ptr, 0, MAP_SIZE);
|
||||
MEM_BARRIER(); // Also make sure nothing read before this point.
|
||||
|
||||
// Start with a clean slate.
|
||||
uc->afl_prev_loc = 0;
|
||||
uc->afl_area_ptr[0] = 1;
|
||||
|
||||
return UC_AFL_RET_CHILD;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* This is the reading side of afl_child_pipe. It will handle persistent mode and (tsl) cache requests.
|
||||
Since timeouts are handled by afl-fuzz simply killing the child, we can just wait until the pipe breaks.
|
||||
For persistent mode, we will also receive child responses over this chanel.
|
||||
For persistent mode, if child is still alive, this will return if the child crashed or not */
|
||||
|
||||
static enum afl_child_ret afl_handle_child_requests(CPUState* cpu) {
|
||||
|
||||
enum afl_child_ret child_msg;
|
||||
struct afl_tsl t;
|
||||
|
||||
while (1) {
|
||||
|
||||
/* Broken pipe means it's time to return to the fork server routine. */
|
||||
|
||||
if (read(_R(cpu->uc->afl_child_pipe), &child_msg, sizeof(enum afl_child_ret)) != sizeof(enum afl_child_ret)) return AFL_CHILD_EXITED; // child is dead.
|
||||
|
||||
if (child_msg == AFL_CHILD_NEXT || child_msg == AFL_CHILD_FOUND_CRASH) {
|
||||
|
||||
// Forward if child found a crash or not, for persistent mode.
|
||||
return child_msg;
|
||||
|
||||
} else if (child_msg == AFL_CHILD_TSL_REQUEST) {
|
||||
|
||||
// TODO: Add option to disable cache for self-modifying code? // Ignore code that has not been loaded?
|
||||
|
||||
// Child will send a tsl request next, that we have to cache.
|
||||
if (read(_R(cpu->uc->afl_child_pipe), &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) return AFL_CHILD_EXITED; // child is dead.
|
||||
|
||||
// Prepare hflags for delay slot
|
||||
#if defined(TARGET_MIPS)
|
||||
struct afl_tsl tmp;
|
||||
tmp.hflags = cpu->uc->tcg_ctx->hflags;
|
||||
tmp.btarget = cpu->uc->tcg_ctx->btarget;
|
||||
cpu->uc->tcg_ctx->hflags = t.hflags;
|
||||
cpu->uc->tcg_ctx->btarget = t.btarget;
|
||||
#endif
|
||||
|
||||
// Cache.
|
||||
//tb_find_slow(env, t.pc, t.cs_base, t.flags);
|
||||
|
||||
// TODO: Caching! tb = tb_find(cpu, last_tb, tb_exit, t.cflags);
|
||||
|
||||
// Restore hflags
|
||||
#if defined(TARGET_MIPS)
|
||||
cpu->uc->tcg_ctx->hflags = tmp.hflags;
|
||||
cpu->uc->tcg_ctx->btarget = tmp.btarget;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "[!] Unexpected response by child! %d. Please report this as bug for unicornafl.\n"
|
||||
" Expected one of {AFL_CHILD_NEXT: %d, AFL_CHILD_FOUND_CRASH: %d, AFL_CHILD_TSL_REQUEST: %d}.\n",
|
||||
child_msg, AFL_CHILD_NEXT, AFL_CHILD_FOUND_CRASH, AFL_CHILD_TSL_REQUEST);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
81
include/afl/afl-cpu-translate-inl.h
Normal file
81
include/afl/afl-cpu-translate-inl.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
american fuzzy lop++ - unicorn instrumentation
|
||||
----------------------------------------------
|
||||
|
||||
Originally written by Andrew Griffiths <agriffiths@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
Adapted for afl-unicorn by Dominik Maier <mail@dmnk.co>
|
||||
|
||||
CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
<andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is a shim patched into the separately-distributed source
|
||||
code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality
|
||||
to implement AFL-style instrumentation and to take care of the remaining
|
||||
parts of the AFL fork server logic.
|
||||
|
||||
The resulting libunicorn binary is essentially a standalone instrumentation
|
||||
tool; for an example of how to leverage it for other purposes, you can
|
||||
have a look at afl-showmap.c.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
/* These are executed on code generation. Execution is in afl-unicorn-tcg-runtime-inl.h */
|
||||
/* Roughly afl_gen_maybe_log -> gen_afl_maybe_log -> emit HELPER(afl_maybe_log) -> call afl_maybe_log */
|
||||
|
||||
static void afl_gen_maybe_log(TCGContext *s, uint64_t cur_loc) {
|
||||
|
||||
if (!s->uc->afl_area_ptr) return;
|
||||
|
||||
/* "Hash" */
|
||||
|
||||
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
|
||||
cur_loc &= MAP_SIZE - 7;
|
||||
|
||||
/* Implement probabilistic instrumentation by looking at scrambled block
|
||||
address. This keeps the instrumented locations stable across runs. */
|
||||
|
||||
if (cur_loc >= s->uc->afl_inst_rms) return;
|
||||
|
||||
gen_afl_maybe_log(s, cur_loc);
|
||||
|
||||
}
|
||||
|
||||
// Currently only arm32 and x86. We undefine it for others to silence unused func compiler warnings.
|
||||
#if defined(ARCH_HAS_COMPCOV)
|
||||
static void afl_gen_compcov(TCGContext *s, uint64_t cur_loc, TCGv arg1,
|
||||
TCGv arg2, TCGMemOp ot, int is_imm) {
|
||||
|
||||
if (!s->uc->afl_compcov_level || !s->uc->afl_area_ptr) return;
|
||||
|
||||
if (!is_imm && s->uc->afl_compcov_level < 2) return;
|
||||
|
||||
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
|
||||
cur_loc &= MAP_SIZE - 7;
|
||||
|
||||
if (cur_loc >= s->uc->afl_inst_rms) return;
|
||||
|
||||
switch (ot) {
|
||||
|
||||
case MO_64: gen_afl_compcov_log_64(s, cur_loc, (TCGv_i64)arg1, (TCGv_i64)arg2); break;
|
||||
case MO_32: gen_afl_compcov_log_32(s, cur_loc, (TCGv_i32)arg1, (TCGv_i32)arg2); break;
|
||||
case MO_16: gen_afl_compcov_log_16(s, cur_loc, (TCGv_i32)arg1, (TCGv_i32)arg2); break;
|
||||
default: return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
76
include/afl/afl-tcg-op-inl.h
Normal file
76
include/afl/afl-tcg-op-inl.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
american fuzzy lop++ - unicorn instrumentation
|
||||
----------------------------------------------
|
||||
|
||||
Originally written by Andrew Griffiths <agriffiths@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
Adapted for afl-unicorn by Dominik Maier <mail@dmnk.co>
|
||||
|
||||
CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
<andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is a shim patched into the separately-distributed source
|
||||
code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality
|
||||
to implement AFL-style instrumentation and to take care of the remaining
|
||||
parts of the AFL fork server logic.
|
||||
|
||||
The resulting libunicorn binary is essentially a standalone instrumentation
|
||||
tool; for an example of how to leverage it for other purposes, you can
|
||||
have a look at afl-showmap.c.
|
||||
|
||||
*/
|
||||
|
||||
static inline void gen_afl_maybe_log(TCGContext *tcg_ctx, uint64_t cur_loc) {
|
||||
|
||||
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
|
||||
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
|
||||
gen_helper_afl_maybe_log(tcg_ctx, tuc, tcur_loc);
|
||||
|
||||
}
|
||||
|
||||
static inline void gen_afl_compcov_log_16(TCGContext *tcg_ctx, uint64_t cur_loc,
|
||||
TCGv_i32 arg1, TCGv_i32 arg2) {
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] Emitting 16 bit COMPCOV instrumentation for loc 0x%lx\n", cur_loc);
|
||||
#endif
|
||||
|
||||
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
|
||||
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
|
||||
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,
|
||||
TCGv_i32 arg1, TCGv_i32 arg2) {
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] Emitting 32 bit COMPCOV instrumentation for loc 0x%lux\n", cur_loc);
|
||||
#endif
|
||||
|
||||
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
|
||||
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
|
||||
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,
|
||||
TCGv_i64 arg1, TCGv_i64 arg2) {
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] Emitting 64 bit COMPCOV instrumentation for loc 0x%lux\n", cur_loc);
|
||||
#endif
|
||||
|
||||
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
|
||||
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
|
||||
gen_helper_afl_compcov_log_64(tcg_ctx, tuc, tcur_loc, arg1, arg2);
|
||||
|
||||
}
|
||||
|
123
include/afl/afl-tcg-runtime-inl.h
Normal file
123
include/afl/afl-tcg-runtime-inl.h
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
american fuzzy lop++ - unicorn instrumentation
|
||||
----------------------------------------------
|
||||
|
||||
Originally written by Andrew Griffiths <agriffiths@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
Adapted for afl-unicorn by Dominik Maier <mail@dmnk.co>
|
||||
|
||||
CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
<andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is a shim patched into the separately-distributed source
|
||||
code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality
|
||||
to implement AFL-style instrumentation and to take care of the remaining
|
||||
parts of the AFL fork server logic.
|
||||
|
||||
The resulting libunicorn binary is essentially a standalone instrumentation
|
||||
tool; for an example of how to leverage it for other purposes, you can
|
||||
have a look at afl-showmap.c.
|
||||
|
||||
*/
|
||||
|
||||
#include "uc_priv.h"
|
||||
#include "afl-common.h"
|
||||
|
||||
/* This is the main instrumentation function, patched in at translate.
|
||||
cur_loc has already been shifted in afl-unicorn-translate-inl.h at this point.
|
||||
Also this helper will only be emitted if running instrumented. */
|
||||
|
||||
void HELPER(afl_maybe_log)(void* uc_ptr, uint64_t cur_loc) {
|
||||
|
||||
struct uc_struct* uc = (struct uc_struct*) uc_ptr;
|
||||
u8* afl_area_ptr = uc->afl_area_ptr; // Don't remove, it's used by INC_AFL_AREA implicitly;
|
||||
|
||||
register uintptr_t afl_idx = cur_loc ^ uc->afl_prev_loc;
|
||||
|
||||
INC_AFL_AREA(afl_idx);
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] At loc 0x%llx: prev: 0x%llx, afl_idx: %lu, map[afl_idx]: %d\n", (unsigned long long) cur_loc, (unsigned long long) uc->afl_prev_loc, (unsigned long) afl_idx, afl_area_ptr[afl_idx]);
|
||||
#endif
|
||||
|
||||
uc->afl_prev_loc = cur_loc >> 1;
|
||||
|
||||
}
|
||||
|
||||
void HELPER(afl_compcov_log_16)(void* uc_ptr, uint64_t cur_loc, uint32_t arg1,
|
||||
uint32_t arg2) {
|
||||
|
||||
u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr;
|
||||
|
||||
if ((arg1 & 0xff00) == (arg2 & 0xff00)) { INC_AFL_AREA(cur_loc); }
|
||||
|
||||
}
|
||||
|
||||
void HELPER(afl_compcov_log_32)(void* uc_ptr, uint64_t cur_loc, uint32_t arg1,
|
||||
uint32_t arg2) {
|
||||
|
||||
u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr;
|
||||
|
||||
if ((arg1 & 0xff000000) == (arg2 & 0xff000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 2);
|
||||
if ((arg1 & 0xff0000) == (arg2 & 0xff0000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 1);
|
||||
if ((arg1 & 0xff00) == (arg2 & 0xff00)) { INC_AFL_AREA(cur_loc); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HELPER(afl_compcov_log_64)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1,
|
||||
uint64_t arg2) {
|
||||
|
||||
u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr;
|
||||
|
||||
if ((arg1 & 0xff00000000000000) == (arg2 & 0xff00000000000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 6);
|
||||
if ((arg1 & 0xff000000000000) == (arg2 & 0xff000000000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 5);
|
||||
if ((arg1 & 0xff0000000000) == (arg2 & 0xff0000000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 4);
|
||||
if ((arg1 & 0xff00000000) == (arg2 & 0xff00000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 3);
|
||||
if ((arg1 & 0xff000000) == (arg2 & 0xff000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 2);
|
||||
if ((arg1 & 0xff0000) == (arg2 & 0xff0000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 1);
|
||||
if ((arg1 & 0xff00) == (arg2 & 0xff00)) { INC_AFL_AREA(cur_loc); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
452
include/afl/config.h
Normal file
452
include/afl/config.h
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
american fuzzy lop++ - vaguely configurable bits
|
||||
------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HAVE_CONFIG_H
|
||||
#define _HAVE_CONFIG_H
|
||||
|
||||
/* Version string: */
|
||||
|
||||
// c = release, d = volatile github dev, e = experimental branch
|
||||
#define VERSION "++3.01a"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
* Settings that may be of interest to power users: *
|
||||
* *
|
||||
******************************************************/
|
||||
|
||||
/* console output colors: There are three ways to configure its behavior
|
||||
* 1. default: colored outputs fixed on: defined USE_COLOR && defined
|
||||
* ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect
|
||||
* 2. defined USE_COLOR && !defined ALWAYS_COLORED
|
||||
* -> depending on env var AFL_NO_COLOR=1 colors can be switched off
|
||||
* at run-time. Default is to use colors.
|
||||
* 3. colored outputs fixed off: !defined USE_COLOR
|
||||
* The env var. AFL_NO_COLOR will have no effect
|
||||
*/
|
||||
|
||||
/* Comment out to disable terminal colors (note that this makes afl-analyze
|
||||
a lot less nice): */
|
||||
|
||||
#define USE_COLOR
|
||||
|
||||
#ifdef USE_COLOR
|
||||
/* Comment in to always enable terminal colors */
|
||||
/* Comment out to enable runtime controlled terminal colors via AFL_NO_COLOR
|
||||
*/
|
||||
#define ALWAYS_COLORED 1
|
||||
#endif
|
||||
|
||||
/* StatsD config
|
||||
Config can be adjusted via AFL_STATSD_HOST and AFL_STATSD_PORT environment
|
||||
variable.
|
||||
*/
|
||||
#define STATSD_UPDATE_SEC 1
|
||||
#define STATSD_DEFAULT_PORT 8125
|
||||
#define STATSD_DEFAULT_HOST "127.0.0.1"
|
||||
|
||||
/* If you want to have the original afl internal memory corruption checks.
|
||||
Disabled by default for speed. it is better to use "make ASAN_BUILD=1". */
|
||||
|
||||
//#define _WANT_ORIGINAL_AFL_ALLOC
|
||||
|
||||
/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */
|
||||
|
||||
#ifndef ANDROID_DISABLE_FANCY // Fancy boxes are ugly from adb
|
||||
#define FANCY_BOXES
|
||||
#endif
|
||||
|
||||
/* Default timeout for fuzzed code (milliseconds). This is the upper bound,
|
||||
also used for detecting hangs; the actual value is auto-scaled: */
|
||||
|
||||
#define EXEC_TIMEOUT 1000U
|
||||
|
||||
/* Timeout rounding factor when auto-scaling (milliseconds): */
|
||||
|
||||
#define EXEC_TM_ROUND 20U
|
||||
|
||||
/* 64bit arch MACRO */
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__))
|
||||
#define WORD_SIZE_64 1
|
||||
#endif
|
||||
|
||||
/* Default memory limit for child process (MB) 0 = disabled : */
|
||||
|
||||
#define MEM_LIMIT 0U
|
||||
|
||||
/* Default memory limit when running in QEMU mode (MB) 0 = disabled : */
|
||||
|
||||
#define MEM_LIMIT_QEMU 0U
|
||||
|
||||
/* Default memory limit when running in Unicorn mode (MB) 0 = disabled : */
|
||||
|
||||
#define MEM_LIMIT_UNICORN 0U
|
||||
|
||||
/* Number of calibration cycles per every new test case (and for test
|
||||
cases that show variable behavior): */
|
||||
|
||||
#define CAL_CYCLES 8U
|
||||
#define CAL_CYCLES_LONG 40U
|
||||
|
||||
/* Number of subsequent timeouts before abandoning an input file: */
|
||||
|
||||
#define TMOUT_LIMIT 250U
|
||||
|
||||
/* Maximum number of unique hangs or crashes to record: */
|
||||
|
||||
#define KEEP_UNIQUE_HANG 500U
|
||||
#define KEEP_UNIQUE_CRASH 5000U
|
||||
|
||||
/* Baseline number of random tweaks during a single 'havoc' stage: */
|
||||
|
||||
#define HAVOC_CYCLES 256U
|
||||
#define HAVOC_CYCLES_INIT 1024U
|
||||
|
||||
/* Maximum multiplier for the above (should be a power of two, beware
|
||||
of 32-bit int overflows): */
|
||||
|
||||
#define HAVOC_MAX_MULT 64U
|
||||
#define HAVOC_MAX_MULT_MOPT 64U
|
||||
|
||||
/* Absolute minimum number of havoc cycles (after all adjustments): */
|
||||
|
||||
#define HAVOC_MIN 12U
|
||||
|
||||
/* Power Schedule Divisor */
|
||||
#define POWER_BETA 1U
|
||||
#define MAX_FACTOR (POWER_BETA * 32)
|
||||
|
||||
/* Maximum stacking for havoc-stage tweaks. The actual value is calculated
|
||||
like this:
|
||||
|
||||
n = random between 1 and HAVOC_STACK_POW2
|
||||
stacking = 2^n
|
||||
|
||||
In other words, the default (n = 4) produces 2, 4, 8, 16
|
||||
stacked tweaks: */
|
||||
|
||||
#define HAVOC_STACK_POW2 4U
|
||||
|
||||
/* Caps on block sizes for cloning and deletion operations. Each of these
|
||||
ranges has a 33% probability of getting picked, except for the first
|
||||
two cycles where smaller blocks are favored: */
|
||||
|
||||
#define HAVOC_BLK_SMALL 32U
|
||||
#define HAVOC_BLK_MEDIUM 128U
|
||||
#define HAVOC_BLK_LARGE 1500U
|
||||
|
||||
/* Extra-large blocks, selected very rarely (<5% of the time): */
|
||||
|
||||
#define HAVOC_BLK_XL 32768U
|
||||
|
||||
/* Probabilities of skipping non-favored entries in the queue, expressed as
|
||||
percentages: */
|
||||
|
||||
#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_NEW_PROB 75 /* ...no new favs, cur entry not fuzzed yet */
|
||||
|
||||
/* Splicing cycle count: */
|
||||
|
||||
#define SPLICE_CYCLES 15
|
||||
|
||||
/* Nominal per-splice havoc cycle length: */
|
||||
|
||||
#define SPLICE_HAVOC 32
|
||||
|
||||
/* Maximum offset for integer addition / subtraction stages: */
|
||||
|
||||
#define ARITH_MAX 35
|
||||
|
||||
/* Limits for the test case trimmer. The absolute minimum chunk size; and
|
||||
the starting and ending divisors for chopping up the input file: */
|
||||
|
||||
#define TRIM_MIN_BYTES 4
|
||||
#define TRIM_START_STEPS 16
|
||||
#define TRIM_END_STEPS 1024
|
||||
|
||||
/* Maximum size of input file, in bytes (keep under 100MB, default 1MB):
|
||||
(note that if this value is changed, several areas in afl-cc.c, afl-fuzz.c
|
||||
and afl-fuzz-state.c have to be changed as well! */
|
||||
|
||||
#define MAX_FILE (1 * 1024 * 1024U)
|
||||
|
||||
/* The same, for the test case minimizer: */
|
||||
|
||||
#define TMIN_MAX_FILE (10 * 1024 * 1024)
|
||||
|
||||
/* Block normalization steps for afl-tmin: */
|
||||
|
||||
#define TMIN_SET_MIN_SIZE 4
|
||||
#define TMIN_SET_STEPS 128
|
||||
|
||||
/* Maximum dictionary token size (-x), in bytes: */
|
||||
|
||||
#define MAX_DICT_FILE 128
|
||||
|
||||
/* Length limits for auto-detected dictionary tokens: */
|
||||
|
||||
#define MIN_AUTO_EXTRA 3
|
||||
#define MAX_AUTO_EXTRA 32
|
||||
|
||||
/* Maximum number of user-specified dictionary tokens to use in deterministic
|
||||
steps; past this point, the "extras/user" step will be still carried out,
|
||||
but with proportionally lower odds: */
|
||||
|
||||
#define MAX_DET_EXTRAS 256
|
||||
|
||||
/* 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
|
||||
higher than the former. */
|
||||
|
||||
#define USE_AUTO_EXTRAS 128
|
||||
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 64)
|
||||
|
||||
/* Scaling factor for the effector map used to skip some of the more
|
||||
expensive deterministic steps. The actual divisor is set to
|
||||
2^EFF_MAP_SCALE2 bytes: */
|
||||
|
||||
#define EFF_MAP_SCALE2 3
|
||||
|
||||
/* Minimum input file length at which the effector logic kicks in: */
|
||||
|
||||
#define EFF_MIN_LEN 128
|
||||
|
||||
/* Maximum effector density past which everything is just fuzzed
|
||||
unconditionally (%): */
|
||||
|
||||
#define EFF_MAX_PERC 90
|
||||
|
||||
/* UI refresh frequency (Hz): */
|
||||
|
||||
#define UI_TARGET_HZ 5
|
||||
|
||||
/* Fuzzer stats file and plot update intervals (sec): */
|
||||
|
||||
#define STATS_UPDATE_SEC 60
|
||||
#define PLOT_UPDATE_SEC 5
|
||||
|
||||
/* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */
|
||||
|
||||
#define AVG_SMOOTHING 16
|
||||
|
||||
/* Sync interval (every n havoc cycles): */
|
||||
|
||||
#define SYNC_INTERVAL 8
|
||||
|
||||
/* Output directory reuse grace period (minutes): */
|
||||
|
||||
#define OUTPUT_GRACE 25
|
||||
|
||||
/* Uncomment to use simple file names (id_NNNNNN): */
|
||||
|
||||
// #define SIMPLE_FILES
|
||||
|
||||
/* List of interesting values to use in fuzzing. */
|
||||
|
||||
#define INTERESTING_8 \
|
||||
-128, /* Overflow signed 8-bit when decremented */ \
|
||||
-1, /* */ \
|
||||
0, /* */ \
|
||||
1, /* */ \
|
||||
16, /* One-off with common buffer size */ \
|
||||
32, /* One-off with common buffer size */ \
|
||||
64, /* One-off with common buffer size */ \
|
||||
100, /* One-off with common buffer size */ \
|
||||
127 /* Overflow signed 8-bit when incremented */
|
||||
|
||||
#define INTERESTING_8_LEN 9
|
||||
|
||||
#define INTERESTING_16 \
|
||||
-32768, /* Overflow signed 16-bit when decremented */ \
|
||||
-129, /* Overflow signed 8-bit */ \
|
||||
128, /* Overflow signed 8-bit */ \
|
||||
255, /* Overflow unsig 8-bit when incremented */ \
|
||||
256, /* Overflow unsig 8-bit */ \
|
||||
512, /* One-off with common buffer size */ \
|
||||
1000, /* One-off with common buffer size */ \
|
||||
1024, /* One-off with common buffer size */ \
|
||||
4096, /* One-off with common buffer size */ \
|
||||
32767 /* Overflow signed 16-bit when incremented */
|
||||
|
||||
#define INTERESTING_16_LEN 10
|
||||
|
||||
#define INTERESTING_32 \
|
||||
-2147483648LL, /* Overflow signed 32-bit when decremented */ \
|
||||
-100663046, /* Large negative number (endian-agnostic) */ \
|
||||
-32769, /* Overflow signed 16-bit */ \
|
||||
32768, /* Overflow signed 16-bit */ \
|
||||
65535, /* Overflow unsig 16-bit when incremented */ \
|
||||
65536, /* Overflow unsig 16 bit */ \
|
||||
100663045, /* Large positive number (endian-agnostic) */ \
|
||||
2147483647 /* Overflow signed 32-bit when incremented */
|
||||
|
||||
#define INTERESTING_32_LEN 8
|
||||
|
||||
/***********************************************************
|
||||
* *
|
||||
* Really exotic stuff you probably don't want to touch: *
|
||||
* *
|
||||
***********************************************************/
|
||||
|
||||
/* Call count interval between reseeding the libc PRNG from /dev/urandom: */
|
||||
|
||||
#define RESEED_RNG 100000
|
||||
|
||||
/* The default maximum testcase cache size in MB, 0 = disable.
|
||||
A value between 50 and 250 is a good default value. Note that the
|
||||
number of entries will be auto assigned if not specified via the
|
||||
AFL_TESTCACHE_ENTRIES env variable */
|
||||
|
||||
#define TESTCASE_CACHE_SIZE 50
|
||||
|
||||
/* Maximum line length passed from GCC to 'as' and used for parsing
|
||||
configuration files: */
|
||||
|
||||
#define MAX_LINE 8192
|
||||
|
||||
/* Environment variable used to pass SHM ID to the called program. */
|
||||
|
||||
#define SHM_ENV_VAR "__AFL_SHM_ID"
|
||||
|
||||
/* Environment variable used to pass SHM FUZZ ID to the called program. */
|
||||
|
||||
#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
|
||||
|
||||
/* Other less interesting, internal-only variables. */
|
||||
|
||||
#define CLANG_ENV_VAR "__AFL_CLANG_MODE"
|
||||
#define AS_LOOP_ENV_VAR "__AFL_AS_LOOPCHECK"
|
||||
#define PERSIST_ENV_VAR "__AFL_PERSISTENT"
|
||||
#define DEFER_ENV_VAR "__AFL_DEFER_FORKSRV"
|
||||
|
||||
/* In-code signatures for deferred and persistent mode. */
|
||||
|
||||
#define PERSIST_SIG "##SIG_AFL_PERSISTENT##"
|
||||
#define DEFER_SIG "##SIG_AFL_DEFER_FORKSRV##"
|
||||
|
||||
/* Distinctive bitmap signature used to indicate failed execution: */
|
||||
|
||||
#define EXEC_FAIL_SIG 0xfee1dead
|
||||
|
||||
/* Distinctive exit code used to indicate MSAN trip condition: */
|
||||
|
||||
#define MSAN_ERROR 86
|
||||
|
||||
/* Designated file descriptors for forkserver commands (the application will
|
||||
use FORKSRV_FD and FORKSRV_FD + 1): */
|
||||
|
||||
#define FORKSRV_FD 198
|
||||
|
||||
/* Fork server init timeout multiplier: we'll wait the user-selected
|
||||
timeout plus this much for the fork server to spin up. */
|
||||
|
||||
#define FORK_WAIT_MULT 10
|
||||
|
||||
/* Calibration timeout adjustments, to be a bit more generous when resuming
|
||||
fuzzing sessions or trying to calibrate already-added internal finds.
|
||||
The first value is a percentage, the other is in milliseconds: */
|
||||
|
||||
#define CAL_TMOUT_PERC 125
|
||||
#define CAL_TMOUT_ADD 50
|
||||
|
||||
/* Number of chances to calibrate a case before giving up: */
|
||||
|
||||
#define CAL_CHANCES 3
|
||||
|
||||
/* 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
|
||||
(adjusting AFL_INST_RATIO when compiling is probably a better way to solve
|
||||
problems with complex programs). You need to recompile the target binary
|
||||
after changing this - otherwise, SEGVs may ensue. */
|
||||
|
||||
#define MAP_SIZE_POW2 16
|
||||
#define MAP_SIZE (1U << MAP_SIZE_POW2)
|
||||
|
||||
/* Maximum allocator request size (keep well under INT_MAX): */
|
||||
|
||||
#define MAX_ALLOC 0x40000000
|
||||
|
||||
/* A made-up hashing seed: */
|
||||
|
||||
#define HASH_CONST 0xa5b35705
|
||||
|
||||
/* Constants for afl-gotcpu to control busy loop timing: */
|
||||
|
||||
#define CTEST_TARGET_MS 5000
|
||||
#define CTEST_CORE_TRG_MS 1000
|
||||
#define CTEST_BUSY_CYCLES (10 * 1000 * 1000)
|
||||
|
||||
/* Enable NeverZero counters in QEMU mode */
|
||||
|
||||
#define AFL_QEMU_NOT_ZERO
|
||||
|
||||
/* AFL RedQueen */
|
||||
|
||||
#define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID"
|
||||
|
||||
/* CPU Affinity lockfile env var */
|
||||
|
||||
#define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE"
|
||||
|
||||
/* Uncomment this to use inferior block-coverage-based instrumentation. Note
|
||||
that you need to recompile the target binary for this to have any effect: */
|
||||
|
||||
// #define COVERAGE_ONLY
|
||||
|
||||
/* Uncomment this to ignore hit counts and output just one bit per tuple.
|
||||
As with the previous setting, you will need to recompile the target
|
||||
binary: */
|
||||
|
||||
// #define SKIP_COUNTS
|
||||
|
||||
/* Uncomment this to use instrumentation data to record newly discovered paths,
|
||||
but do not use them as seeds for fuzzing. This is useful for conveniently
|
||||
measuring coverage that could be attained by a "dumb" fuzzing algorithm: */
|
||||
|
||||
// #define IGNORE_FINDS
|
||||
|
||||
/* Text mutations */
|
||||
|
||||
/* Minimum length of a queue input to be evaluated for "is_ascii"? */
|
||||
|
||||
#define AFL_TXT_MIN_LEN 12
|
||||
|
||||
/* What is the minimum percentage of ascii characters present to be classifed
|
||||
as "is_ascii"? */
|
||||
|
||||
#define AFL_TXT_MIN_PERCENT 94
|
||||
|
||||
/* How often to perform ASCII mutations 0 = disable, 1-8 are good values */
|
||||
|
||||
#define AFL_TXT_BIAS 6
|
||||
|
||||
/* Maximum length of a string to tamper with */
|
||||
|
||||
#define AFL_TXT_STRING_MAX_LEN 1024
|
||||
|
||||
/* Maximum mutations on a string */
|
||||
|
||||
#define AFL_TXT_STRING_MAX_MUTATIONS 6
|
||||
|
||||
#endif /* ! _HAVE_CONFIG_H */
|
||||
|
193
include/afl/types.h
Normal file
193
include/afl/types.h
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
american fuzzy lop++ - type definitions and minor macros
|
||||
--------------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HAVE_TYPES_H
|
||||
#define _HAVE_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
#ifdef WORD_SIZE_64
|
||||
typedef unsigned __int128 uint128_t;
|
||||
typedef uint128_t u128;
|
||||
#endif
|
||||
|
||||
/* Extended forkserver option values */
|
||||
|
||||
/* Reporting errors */
|
||||
#define FS_OPT_ERROR 0xf800008f
|
||||
#define FS_OPT_GET_ERROR(x) ((x & 0x00ffff00) >> 8)
|
||||
#define FS_OPT_SET_ERROR(x) ((x & 0x0000ffff) << 8)
|
||||
#define FS_ERROR_MAP_SIZE 1
|
||||
#define FS_ERROR_MAP_ADDR 2
|
||||
#define FS_ERROR_SHM_OPEN 4
|
||||
#define FS_ERROR_SHMAT 8
|
||||
#define FS_ERROR_MMAP 16
|
||||
|
||||
/* Reporting options */
|
||||
#define FS_OPT_ENABLED 0x80000001
|
||||
#define FS_OPT_MAPSIZE 0x40000000
|
||||
#define FS_OPT_SNAPSHOT 0x20000000
|
||||
#define FS_OPT_AUTODICT 0x10000000
|
||||
#define FS_OPT_SHDMEM_FUZZ 0x01000000
|
||||
#define FS_OPT_OLD_AFLPP_WORKAROUND 0x0f000000
|
||||
// FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22
|
||||
#define FS_OPT_MAX_MAPSIZE ((0x00fffffeU >> 1) + 1)
|
||||
#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
|
||||
#define FS_OPT_SET_MAPSIZE(x) \
|
||||
(x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
|
||||
|
||||
typedef unsigned long long u64;
|
||||
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
#ifdef WORD_SIZE_64
|
||||
typedef __int128 int128_t;
|
||||
typedef int128_t s128;
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) \
|
||||
({ \
|
||||
\
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a < _b ? _a : _b; \
|
||||
\
|
||||
})
|
||||
|
||||
#define MAX(a, b) \
|
||||
({ \
|
||||
\
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a > _b ? _a : _b; \
|
||||
\
|
||||
})
|
||||
|
||||
#endif /* !MIN */
|
||||
|
||||
#define SWAP16(_x) \
|
||||
({ \
|
||||
\
|
||||
u16 _ret = (_x); \
|
||||
(u16)((_ret << 8) | (_ret >> 8)); \
|
||||
\
|
||||
})
|
||||
|
||||
#define SWAP32(_x) \
|
||||
({ \
|
||||
\
|
||||
u32 _ret = (_x); \
|
||||
(u32)((_ret << 24) | (_ret >> 24) | ((_ret << 8) & 0x00FF0000) | \
|
||||
((_ret >> 8) & 0x0000FF00)); \
|
||||
\
|
||||
})
|
||||
|
||||
#define SWAP64(_x) \
|
||||
({ \
|
||||
\
|
||||
u64 _ret = (_x); \
|
||||
_ret = \
|
||||
(_ret & 0x00000000FFFFFFFF) << 32 | (_ret & 0xFFFFFFFF00000000) >> 32; \
|
||||
_ret = \
|
||||
(_ret & 0x0000FFFF0000FFFF) << 16 | (_ret & 0xFFFF0000FFFF0000) >> 16; \
|
||||
_ret = \
|
||||
(_ret & 0x00FF00FF00FF00FF) << 8 | (_ret & 0xFF00FF00FF00FF00) >> 8; \
|
||||
_ret; \
|
||||
\
|
||||
})
|
||||
|
||||
// It is impossible to define 128 bit constants, so ...
|
||||
#ifdef WORD_SIZE_64
|
||||
#define SWAPN(_x, _l) \
|
||||
({ \
|
||||
\
|
||||
u128 _res = (_x), _ret; \
|
||||
char *d = (char *)&_ret, *s = (char *)&_res; \
|
||||
int i; \
|
||||
for (i = 0; i < 16; i++) \
|
||||
d[15 - i] = s[i]; \
|
||||
u32 sr = 128U - ((_l) << 3U); \
|
||||
(_ret >>= sr); \
|
||||
(u128) _ret; \
|
||||
\
|
||||
})
|
||||
#endif
|
||||
|
||||
#define SWAPNN(_x, _y, _l) \
|
||||
({ \
|
||||
\
|
||||
char *d = (char *)(_x), *s = (char *)(_y); \
|
||||
u32 i, l = (_l)-1; \
|
||||
for (i = 0; i <= l; i++) \
|
||||
d[l - i] = s[i]; \
|
||||
\
|
||||
})
|
||||
|
||||
#ifdef AFL_LLVM_PASS
|
||||
#if defined(__linux__) || !defined(__ANDROID__)
|
||||
#define AFL_SR(s) (srandom(s))
|
||||
#define AFL_R(x) (random() % (x))
|
||||
#else
|
||||
#define AFL_SR(s) ((void)s)
|
||||
#define AFL_R(x) (arc4random_uniform(x))
|
||||
#endif
|
||||
#else
|
||||
#if defined(__linux__) || !defined(__ANDROID__)
|
||||
#define SR(s) (srandom(s))
|
||||
#define R(x) (random() % (x))
|
||||
#else
|
||||
#define SR(s) ((void)s)
|
||||
#define R(x) (arc4random_uniform(x))
|
||||
#endif
|
||||
#endif /* ^AFL_LLVM_PASS */
|
||||
|
||||
#define STRINGIFY_INTERNAL(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
|
||||
|
||||
#define MEM_BARRIER() __asm__ volatile("" ::: "memory")
|
||||
|
||||
#if __GNUC__ < 6
|
||||
#ifndef likely
|
||||
#define likely(_x) (_x)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(_x) (_x)
|
||||
#endif
|
||||
#else
|
||||
#ifndef likely
|
||||
#define likely(_x) __builtin_expect(!!(_x), 1)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(_x) __builtin_expect(!!(_x), 0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* ! _HAVE_TYPES_H */
|
||||
|
@ -15,14 +15,26 @@
|
||||
|
||||
// These are masks of supported modes for each cpu/arch.
|
||||
// They should be updated when changes are made to the uc_mode enum typedef.
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
#define UC_MODE_ARM_MASK (UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_LITTLE_ENDIAN|UC_MODE_MCLASS \
|
||||
|UC_MODE_ARM926|UC_MODE_ARM946|UC_MODE_ARM1176|UC_MODE_BIG_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_X86_MASK (UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_MIPS_MASK (UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_PPC_MASK (UC_MODE_PPC32|UC_MODE_PPC64|UC_MODE_BIG_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_SPARC_MASK (UC_MODE_SPARC32|UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_RISCV_MASK (UC_MODE_RISCV32|UC_MODE_RISCV64|UC_MODE_LITTLE_ENDIAN|UC_MODE_AFL)
|
||||
#else
|
||||
#define UC_MODE_ARM_MASK (UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_LITTLE_ENDIAN|UC_MODE_MCLASS \
|
||||
|UC_MODE_ARM926|UC_MODE_ARM946|UC_MODE_ARM1176|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_MIPS_MASK (UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_X86_MASK (UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN)
|
||||
#define UC_MODE_MIPS_MASK (UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_PPC_MASK (UC_MODE_PPC32|UC_MODE_PPC64|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_SPARC_MASK (UC_MODE_SPARC32|UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_RISCV_MASK (UC_MODE_RISCV32|UC_MODE_RISCV64|UC_MODE_LITTLE_ENDIAN)
|
||||
#endif
|
||||
|
||||
|
||||
#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
@ -95,6 +107,20 @@ typedef void (*uc_softfloat_initialize)(void);
|
||||
// tcg flush softmmu tlb
|
||||
typedef void (*uc_tcg_flush_tlb)(struct uc_struct *uc);
|
||||
|
||||
typedef enum uc_afl_ret {
|
||||
UC_AFL_RET_ERROR = 0, // Something went horribly wrong in the parent
|
||||
UC_AFL_RET_CHILD, // Fork worked. we are a child
|
||||
UC_AFL_RET_NO_AFL, // No AFL, no need to fork.
|
||||
UC_AFL_RET_CALLED_TWICE, // AFL has already been started before.
|
||||
UC_AFL_RET_FINISHED, // We forked before but now AFL is gone (parent)
|
||||
} uc_afl_ret;
|
||||
|
||||
// we use this as shortcut deep inside uc_afl for the arch specific uc_afl_next(uc, bool)
|
||||
typedef uc_afl_ret(*uc_afl_ret_uc_bool_t)(struct uc_struct*, bool);
|
||||
|
||||
// afl_forkserver_start
|
||||
typedef int (*uc_afl_forkserver_t)(struct uc_struct*);
|
||||
|
||||
struct hook {
|
||||
int type; // UC_HOOK_*
|
||||
int insn; // instruction for HOOK_INSN
|
||||
@ -282,6 +308,22 @@ struct uc_struct {
|
||||
bool first_tb; // is this the first Translation-Block ever generated since uc_emu_start()?
|
||||
struct list saved_contexts; // The contexts saved by this uc_struct.
|
||||
bool no_exit_request; // Disable check_exit_request temporarily. A workaround to treat the IT block as a whole block.
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
uc_afl_forkserver_t afl_forkserver_start; // function to start afl forkserver
|
||||
uc_afl_ret_uc_bool_t afl_child_request_next; // function from child to ask for new testcase (if in child)
|
||||
int afl_child_pipe[2]; // pipe used to send information from child process to forkserver
|
||||
int afl_parent_pipe[2]; // pipe used to send information from parent to child in forkserver
|
||||
uint8_t *afl_area_ptr; // map, shared with afl, to report coverage feedback etc. during runs
|
||||
uint64_t afl_prev_loc; // previous location
|
||||
int afl_compcov_level; // how much compcove we want
|
||||
unsigned int afl_inst_rms;
|
||||
size_t exit_count; // number of exits set in afl_fuzz or afl_forkserver
|
||||
uint64_t *exits; // pointer to the actual exits
|
||||
char *afl_testcase_ptr; // map, shared with afl, to get testcases delivered from for each run
|
||||
uint32_t *afl_testcase_size_p; // size of the current testcase, if using shared map fuzzing with afl.
|
||||
void *afl_data_ptr; // Pointer for various (bindings-related) uses.
|
||||
#endif
|
||||
};
|
||||
|
||||
// Metadata stub for the variable-size cpu context used with uc_context_*()
|
||||
|
@ -105,6 +105,7 @@ typedef enum uc_arch {
|
||||
typedef enum uc_mode {
|
||||
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
|
||||
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
|
||||
UC_MODE_AFL = 1 << 29,
|
||||
|
||||
// arm / arm64
|
||||
UC_MODE_ARM = 0, // ARM mode
|
||||
@ -171,6 +172,10 @@ typedef enum uc_err {
|
||||
UC_ERR_HOOK_EXIST, // hook for this event already existed
|
||||
UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start()
|
||||
UC_ERR_EXCEPTION, // Unhandled CPU exception
|
||||
UC_ERR_AFL_RET_ERROR, // Something went horribly wrong in the parent
|
||||
UC_ERR_AFL_RET_NO_AFL, // No AFL, no need to fork.
|
||||
UC_ERR_AFL_RET_CALLED_TWICE, // AFL has already been started before.
|
||||
UC_ERR_AFL_RET_FINISHED, // We forked before but now AFL is gone (parent)
|
||||
} uc_err;
|
||||
|
||||
|
||||
@ -568,6 +573,82 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size);
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count);
|
||||
|
||||
/* Callback function called for each input from AFL.
|
||||
This function is mandatory.
|
||||
It's purpose is to place the input at the right place in unicorn.
|
||||
@uc: Unicorn instance
|
||||
@input: The current input we're working on. Place this somewhere in unicorn's memory now.
|
||||
@input_len: length of the input
|
||||
@persistent_round: which round we are currently crashing in, if using persistent mode.
|
||||
@data: Data pointer passed to uc_afl_fuzz(...).
|
||||
@return:
|
||||
If you return is true, all is well. Fuzzing starts.
|
||||
If you return false, the input is rejected; we will continue with the next input.
|
||||
*/
|
||||
typedef bool (*uc_afl_cb_place_input_t)(uc_engine *uc, char *input, size_t input_len, uint32_t persistent_round, void *data);
|
||||
|
||||
/* Callback function called after a non-UC_ERR_OK returncode was returned by Unicorn.
|
||||
This function is not mandatory (pass NULL).
|
||||
@uc: Unicorn instance
|
||||
@unicorn_result: The error state returned by the current testcase
|
||||
@input: The current input we're workin with.
|
||||
@input_len: length of the input
|
||||
@persistent_round: which round we are currently crashing in, if using persistent mode.
|
||||
@data: Data pointer passed to uc_afl_fuzz(...).
|
||||
@Return:
|
||||
If you return false, the crash is considered invalid and not reported to AFL.
|
||||
If return is true, the crash is reported.
|
||||
-> The child will die and the forkserver will spawn a new child.
|
||||
*/
|
||||
typedef bool (*uc_afl_cb_validate_crash_t)(uc_engine *uc, uc_err unicorn_result, char *input, int input_len, int persistent_round, void *data);
|
||||
|
||||
/*
|
||||
The main fuzzer.
|
||||
Starts uc_afl_forkserver(), then beginns a persistent loop.
|
||||
Reads input, calls the place_input callback, emulates, uc_afl_next(...), repeats.
|
||||
If unicorn errors out, will call the validate_crash_callback, if set.
|
||||
Will only retrun in the parent after the whole fuzz thing has been finished and afl died.
|
||||
The child processes never return from here.
|
||||
|
||||
Note: This API is not supported on Windows.
|
||||
|
||||
@uc: handle returned by uc_open()
|
||||
@input_file: filename/path to the (AFL) inputfile. Usualy suplied on the commandline.
|
||||
@place_input_callback: Callback function that will be called before each test runs.
|
||||
This function needs to write the input from afl to the correct position on the unicorn object.
|
||||
@exits: address list of exits where fuzzing should stop (len == exit_count)
|
||||
@exit_count: number of exits where fuzzing should stop
|
||||
@validate_crash_callback: Optional callback (if not needed, pass NULL), that determines
|
||||
if a non-OK uc_err is an actual error. If false is returned, the test-case will not crash.
|
||||
@always_validate: If false, validate_crash_callback will only be called for crashes.
|
||||
@persistent_iters:
|
||||
The amount of loop iterations in persistent mode before restarteing with a new forked child.
|
||||
If your target cannot be fuzzed using persistent mode (global state changes a lot),
|
||||
set persistent_iters = 1 for the normal fork-server experience.
|
||||
Else, the default is usually around 1000.
|
||||
If your target is super stable (and unicorn is, too - not sure about that one),
|
||||
you may pass persistent_iter = 0 for that an infinite fuzz loop.
|
||||
@data: Your very own data pointer. This will passed into every callback.
|
||||
@return uc_afl_ret:
|
||||
>UC_AFL_RET_ERROR = 0, // Something went horribly wrong in the parent
|
||||
>UC_AFL_RET_CHILD, // Can never happen, the child will loop happily or exit.
|
||||
>UC_AFL_RET_NO_AFL, // No AFL, we ran the testacse once and are done.
|
||||
>UC_AFL_RET_FINISHED, // We forked before but now AFL is gone (parent)
|
||||
>> We're retuning after having fuzzed. We may now pack our bags and exit.
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_afl_fuzz(
|
||||
uc_engine *uc,
|
||||
char* input_file,
|
||||
uc_afl_cb_place_input_t place_input_callback,
|
||||
uint64_t *exits,
|
||||
size_t exit_count,
|
||||
uc_afl_cb_validate_crash_t validate_crash_callback,
|
||||
bool always_validate,
|
||||
uint32_t persistent_iters,
|
||||
void *data
|
||||
);
|
||||
|
||||
/*
|
||||
Stop emulation (which was started by uc_emu_start() API.
|
||||
This is typically called from callback functions registered via tracing APIs.
|
||||
|
Reference in New Issue
Block a user