Merge branch 'debug' into taint

This commit is contained in:
van Hauser
2020-08-11 03:40:12 +02:00
committed by GitHub
15 changed files with 187 additions and 84 deletions

View File

@ -98,7 +98,7 @@ ifneq "$(shell uname -m)" "x86_64"
endif endif
CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT) CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT)
override CFLAGS += -g -Wno-pointer-sign \ override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \
-I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \ -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
-DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
@ -198,6 +198,7 @@ else
endif endif
ifneq "$(filter Linux GNU%,$(shell uname))" "" ifneq "$(filter Linux GNU%,$(shell uname))" ""
override CFLAGS += -D_FORTIFY_SOURCE=2
LDFLAGS += -ldl -lrt LDFLAGS += -ldl -lrt
endif endif

View File

@ -71,18 +71,18 @@ only new bytes in the other cycle.
Android support and much, much, much more. Android support and much, much, much more.
| Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode | | Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode |
| ------------------------ |:-------:|:---------:|:----------:|:----------------:|:------------:| | -------------------------|:-------:|:---------:|:----------:|:----------------:|:------------:|
| NeverZero | x | x(1) | (2) | x | x | | NeverZero | x86[_64]| x(1) | (2) | x | x |
| Persistent mode | | x | x | x86[_64]/arm[64] | x | | Persistent Mode | | x | x | x86[_64]/arm[64] | x |
| LAF-Intel / CompCov | | x | | x86[_64]/arm[64] | x86[_64]/arm | | LAF-Intel / CompCov | | x | | x86[_64]/arm[64] | x86[_64]/arm |
| CmpLog | | x | | x86[_64]/arm[64] | | | CmpLog | | x | | x86[_64]/arm[64] | |
| Selective instrumentation| | x | x | (x)(3) | | | Selective Instrumentation| | x | x | (x)(3) | |
| Non-colliding coverage | | x(4) | | (x)(5) | | | Non-Colliding Coverage | | x(4) | | (x)(5) | |
| InsTrim | | x | | | | | InsTrim | | x | | | |
| Ngram prev_loc coverage | | x(6) | | | | | Ngram prev_loc Coverage | | x(6) | | | |
| Context coverage | | x | | | | | Context Coverage | | x | | | |
| Auto dictionary | | x(7) | | | | | Auto Dictionary | | x(7) | | | |
| Snapshot LKM support | | x | | (x)(5) | | | Snapshot LKM Support | | x | | (x)(5) | |
1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8
2. GCC creates non-performant code, hence it is disabled in gcc_plugin 2. GCC creates non-performant code, hence it is disabled in gcc_plugin

View File

@ -28,6 +28,9 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
sancov, and also supports function matching! sancov, and also supports function matching!
- fixes for laf-intel float splitting (thanks to mark-griffin for - fixes for laf-intel float splitting (thanks to mark-griffin for
reporting) reporting)
- LTO: switch default to the dynamic memory map, set AFL_LLVM_MAP_ADDR
for a fixed map address (eg. 0x10000)
- LTO: skipping ctors and ifuncs in fix map address instrumentation
- LTO: autodictionary mode is a default - LTO: autodictionary mode is a default
- LTO: instrim instrumentation disabled, only classic support used - LTO: instrim instrumentation disabled, only classic support used
as it is always better as it is always better

View File

@ -670,6 +670,7 @@ typedef struct afl_state {
struct custom_mutator { struct custom_mutator {
const char *name; const char *name;
char * name_short;
void * dh; void * dh;
u8 * post_process_buf; u8 * post_process_buf;
size_t post_process_size; size_t post_process_size;

View File

@ -28,11 +28,6 @@
#include "types.h" #include "types.h"
#include "config.h" #include "config.h"
/* __FUNCTION__ is non-iso */
#ifdef __func__
#define __FUNCTION__ __func__
#endif
/******************* /*******************
* Terminal colors * * Terminal colors *
*******************/ *******************/
@ -223,43 +218,43 @@
/* Die with a verbose non-OS fatal error message. */ /* Die with a verbose non-OS fatal error message. */
#define FATAL(x...) \ #define FATAL(x...) \
do { \ do { \
\ \
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
"\n[-] PROGRAM ABORT : " cRST x); \ "\n[-] PROGRAM ABORT : " cRST x); \
SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __FUNCTION__, \ SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __func__, \
__FILE__, __LINE__); \ __FILE__, __LINE__); \
exit(1); \ exit(1); \
\ \
} while (0) } while (0)
/* Die by calling abort() to provide a core dump. */ /* Die by calling abort() to provide a core dump. */
#define ABORT(x...) \ #define ABORT(x...) \
do { \ do { \
\ \
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
"\n[-] PROGRAM ABORT : " cRST x); \ "\n[-] PROGRAM ABORT : " cRST x); \
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __FUNCTION__, \ SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __func__, \
__FILE__, __LINE__); \ __FILE__, __LINE__); \
abort(); \ abort(); \
\ \
} while (0) } while (0)
/* Die while also including the output of perror(). */ /* Die while also including the output of perror(). */
#define PFATAL(x...) \ #define PFATAL(x...) \
do { \ do { \
\ \
fflush(stdout); \ fflush(stdout); \
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \
"\n[-] SYSTEM ERROR : " cRST x); \ "\n[-] SYSTEM ERROR : " cRST x); \
SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __FUNCTION__, \ SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __func__, \
__FILE__, __LINE__); \ __FILE__, __LINE__); \
SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \ SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \
exit(1); \ exit(1); \
\ \
} while (0) } while (0)
/* Die with FATAL() or PFATAL() depending on the value of res (used to /* Die with FATAL() or PFATAL() depending on the value of res (used to

View File

@ -17,9 +17,6 @@ This version requires a current llvm 11+ compiled from the github master.
5. If any problems arise be sure to set `AR=llvm-ar RANLIB=llvm-ranlib`. 5. If any problems arise be sure to set `AR=llvm-ar RANLIB=llvm-ranlib`.
Some targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`. Some targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`.
6. If a target uses _init functions or early constructors then additionally
set `AFL_LLVM_MAP_DYNAMIC=1` as your target will crash otherwise!
## Introduction and problem description ## Introduction and problem description
A big issue with how afl/afl++ works is that the basic block IDs that are A big issue with how afl/afl++ works is that the basic block IDs that are
@ -128,14 +125,14 @@ on start. This improves coverage statistically by 5-10% :)
## Fixed memory map ## Fixed memory map
To speed up fuzzing, the shared memory map is hard set to a specific address, To speed up fuzzing, it is possible to set a fixed shared memory map.
by default 0x10000. In most cases this will work without any problems. Recommened is the value 0x10000.
In most cases this will work without any problems. However if a target uses
early constructors, ifuncs or a deferred forkserver this can crash the target.
On unusual operating systems/processors/kernels or weird libraries this might On unusual operating systems/processors/kernels or weird libraries this might
fail so to change the fixed address at compile time set fail so to change the fixed address at compile time set
AFL_LLVM_MAP_ADDR with a better value (a value of 0 or empty sets the map address AFL_LLVM_MAP_ADDR with a better value (a value of 0 or empty sets the map address
to be dynamic - the original afl way, which is slower). to be dynamic - the original afl way, which is slower).
AFL_LLVM_MAP_DYNAMIC can be set so the shared memory address is dynamic (which
is safer but also slower).
## Document edge IDs ## Document edge IDs
@ -262,15 +259,6 @@ If this succeeeds then there is an issue with afl-clang-lto. Please report at
Even some targets where clang-12 fails can be build if the fail is just in Even some targets where clang-12 fails can be build if the fail is just in
`./configure`, see `Solving difficult targets` above. `./configure`, see `Solving difficult targets` above.
### Target crashes immediately
If the target is using early constructors (priority values smaller than 6)
or have their own _init/.init functions and these are instrumented then the
target will likely crash when started. This can be avoided by compiling with
`AFL_LLVM_MAP_DYNAMIC=1` .
This can e.g. happen with OpenSSL.
## History ## History
This was originally envisioned by hexcoder- in Summer 2019, however we saw no This was originally envisioned by hexcoder- in Summer 2019, however we saw no

View File

@ -49,6 +49,7 @@
#include "llvm/Analysis/MemorySSAUpdater.h" #include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/ValueTracking.h"
#include "llvm/Pass.h" #include "llvm/Pass.h"
#include "llvm/IR/Constants.h"
#include "afl-llvm-common.h" #include "afl-llvm-common.h"
@ -135,7 +136,10 @@ bool AFLLTOPass::runOnModule(Module &M) {
if (getenv("AFL_LLVM_LTO_AUTODICTIONARY")) autodictionary = 1; if (getenv("AFL_LLVM_LTO_AUTODICTIONARY")) autodictionary = 1;
if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0; // we make this the default as the fixed map has problems with
// defered forkserver, early constructors, ifuncs and maybe more
/*if (getenv("AFL_LLVM_MAP_DYNAMIC"))*/
map_addr = 0;
if (getenv("AFL_LLVM_SKIPSINGLEBLOCK")) function_minimum_size = 2; if (getenv("AFL_LLVM_SKIPSINGLEBLOCK")) function_minimum_size = 2;
@ -196,7 +200,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
ConstantInt *One = ConstantInt::get(Int8Ty, 1); ConstantInt *One = ConstantInt::get(Int8Ty, 1);
/* This dumps all inialized global strings - might be useful in the future // This dumps all inialized global strings - might be useful in the future
/*
for (auto G=M.getGlobalList().begin(); G!=M.getGlobalList().end(); G++) { for (auto G=M.getGlobalList().begin(); G!=M.getGlobalList().end(); G++) {
GlobalVariable &GV=*G; GlobalVariable &GV=*G;
@ -212,7 +217,79 @@ bool AFLLTOPass::runOnModule(Module &M) {
} }
*/ */
std::vector<std::string> module_block_list;
if (map_addr) {
for (GlobalIFunc &IF : M.ifuncs()) {
StringRef ifunc_name = IF.getName();
Constant *r = IF.getResolver();
StringRef r_name = cast<Function>(r->getOperand(0))->getName();
if (!be_quiet)
fprintf(stderr,
"Warning: Found an ifunc with name %s that points to resolver "
"function %s, we cannot instrument this, putting it into a "
"block list.\n",
ifunc_name.str().c_str(), r_name.str().c_str());
module_block_list.push_back(r_name.str());
}
GlobalVariable *GV = M.getNamedGlobal("llvm.global_ctors");
if (GV && !GV->isDeclaration() && !GV->hasLocalLinkage()) {
ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
if (InitList) {
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
if (ConstantStruct *CS =
dyn_cast<ConstantStruct>(InitList->getOperand(i))) {
if (CS->getNumOperands() >= 2) {
if (CS->getOperand(1)->isNullValue())
break; // Found a null terminator, stop here.
ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
int Priority = CI ? CI->getSExtValue() : 0;
Constant *FP = CS->getOperand(1);
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
if (CE->isCast()) FP = CE->getOperand(0);
if (Function *F = dyn_cast<Function>(FP)) {
if (!F->isDeclaration() &&
strncmp(F->getName().str().c_str(), "__afl", 5) != 0 &&
Priority <= 5) {
if (!be_quiet)
fprintf(stderr,
"Warning: Found constructor function %s with prio "
"%u, we cannot instrument this, putting it into a "
"block list.\n",
F->getName().str().c_str(), Priority);
module_block_list.push_back(F->getName().str());
}
}
}
}
}
}
}
}
/* Instrument all the things! */ /* Instrument all the things! */
@ -220,12 +297,36 @@ bool AFLLTOPass::runOnModule(Module &M) {
for (auto &F : M) { for (auto &F : M) {
// fprintf(stderr, "DEBUG: Module %s Function %s\n", /*For debugging
// M.getName().str().c_str(), F.getName().str().c_str()); AttributeSet X = F.getAttributes().getFnAttributes();
fprintf(stderr, "DEBUG: Module %s Function %s attributes %u\n",
M.getName().str().c_str(), F.getName().str().c_str(),
X.getNumAttributes());
*/
if (F.size() < function_minimum_size) continue; if (F.size() < function_minimum_size) continue;
if (isIgnoreFunction(&F)) continue; if (isIgnoreFunction(&F)) continue;
if (module_block_list.size()) {
for (auto bname : module_block_list) {
std::string fname = F.getName().str();
if (fname.compare(bname) == 0) {
if (!be_quiet)
WARNF(
"Skipping instrumentation of dangerous early running function "
"%s",
fname.c_str());
}
}
}
// the instrument file list check // the instrument file list check
AttributeList Attrs = F.getAttributes(); AttributeList Attrs = F.getAttributes();
if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) { if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) {

View File

@ -329,10 +329,13 @@ static void __afl_map_shm(void) {
id_str = getenv(CMPLOG_SHM_ENV_VAR); id_str = getenv(CMPLOG_SHM_ENV_VAR);
if (getenv("AFL_DEBUG")) if (getenv("AFL_DEBUG")) {
fprintf(stderr, "DEBUG: cmplog id_str %s\n", fprintf(stderr, "DEBUG: cmplog id_str %s\n",
id_str == NULL ? "<null>" : id_str); id_str == NULL ? "<null>" : id_str);
}
if (id_str) { if (id_str) {
#ifdef USEMMAP #ifdef USEMMAP
@ -404,9 +407,12 @@ static void __afl_start_snapshots(void) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
if (getenv("AFL_DEBUG")) if (getenv("AFL_DEBUG")) {
fprintf(stderr, "target forkserver recv: %08x\n", was_killed); fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
}
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) == if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) { (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
@ -613,9 +619,12 @@ static void __afl_start_forkserver(void) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
if (getenv("AFL_DEBUG")) if (getenv("AFL_DEBUG")) {
fprintf(stderr, "target forkserver recv: %08x\n", was_killed); fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
}
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) == if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) { (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
@ -936,8 +945,12 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
u32 inst_ratio = 100; u32 inst_ratio = 100;
char *x; char *x;
fprintf(stderr, "Running __sanitizer_cov_trace_pc_guard_init: %p-%p\n", start, if (getenv("AFL_DEBUG")) {
stop);
fprintf(stderr, "Running __sanitizer_cov_trace_pc_guard_init: %p-%p\n",
start, stop);
}
if (start == stop || *start) return; if (start == stop || *start) return;

View File

@ -293,8 +293,8 @@ static void report_error_and_exit(int error) {
FATAL( FATAL(
"the fuzzing target reports that hardcoded map address might be the " "the fuzzing target reports that hardcoded map address might be the "
"reason the mmap of the shared memory failed. Solution: recompile " "reason the mmap of the shared memory failed. Solution: recompile "
"the target with either afl-clang-lto and the environment variable " "the target with either afl-clang-lto and do not set "
"AFL_LLVM_MAP_DYNAMIC set or recompile with afl-clang-fast."); "AFL_LLVM_MAP_ADDR or recompile with afl-clang-fast.");
break; break;
case FS_ERROR_SHM_OPEN: case FS_ERROR_SHM_OPEN:
FATAL("the fuzzing target reports that the shm_open() call failed."); FATAL("the fuzzing target reports that the shm_open() call failed.");
@ -838,8 +838,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
SAYF("\n" cLRD "[-] " cRST SAYF("\n" cLRD "[-] " cRST
"Hmm, looks like the target binary terminated before we could" "Hmm, looks like the target binary terminated before we could"
" complete a handshake with the injected code.\n" " complete a handshake with the injected code.\n"
"If the target was compiled with afl-clang-lto then recompiling with" "If the target was compiled with afl-clang-lto and AFL_LLVM_MAP_ADDR"
" AFL_LLVM_MAP_DYNAMIC might solve your problem.\n" " then recompiling without this parameter.\n"
"Otherwise there is a horrible bug in the fuzzer.\n" "Otherwise there is a horrible bug in the fuzzer.\n"
"Poke <afl-users@googlegroups.com> for troubleshooting tips.\n"); "Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
@ -870,9 +870,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - the target was compiled with afl-clang-lto and a constructor " " - the target was compiled with afl-clang-lto and a constructor "
"was\n" "was\n"
" instrumented, recompiling with AFL_LLVM_MAP_DYNAMIC might solve " " instrumented, recompiling without AFL_LLVM_MAP_ADDR might solve "
"your\n" "your problem\n\n"
" problem\n\n"
" - Less likely, there is a horrible bug in the fuzzer. If other " " - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n" "options\n"

View File

@ -29,10 +29,6 @@
#include "afl-fuzz.h" #include "afl-fuzz.h"
#include "cmplog.h" #include "cmplog.h"
typedef struct cmplog_data {
} cmplog_data_t;
void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) {
setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);

View File

@ -142,6 +142,7 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator)); struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator));
mutator->name = fn; mutator->name = fn;
mutator->name_short = strrchr(fn, '/') + 1;
ACTF("Loading custom mutator library from '%s'...", fn); ACTF("Loading custom mutator library from '%s'...", fn);
dh = dlopen(fn, RTLD_NOW); dh = dlopen(fn, RTLD_NOW);

View File

@ -1764,6 +1764,8 @@ custom_mutator_stage:
has_custom_fuzz = true; has_custom_fuzz = true;
afl->stage_short = el->name_short;
for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max;
++afl->stage_cur) { ++afl->stage_cur) {

View File

@ -138,7 +138,7 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
/* The same, but with an adjustable gap. Used for trimming. */ /* The same, but with an adjustable gap. Used for trimming. */
static void write_with_gap(afl_state_t *afl, void *mem, u32 len, u32 skip_at, static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at,
u32 skip_len) { u32 skip_len) {
s32 fd = afl->fsrv.out_fd; s32 fd = afl->fsrv.out_fd;

View File

@ -300,9 +300,12 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->cpu_to_bind != -1) FATAL("Multiple -b options not supported"); if (afl->cpu_to_bind != -1) FATAL("Multiple -b options not supported");
if (sscanf(optarg, "%u", &afl->cpu_to_bind) < 0 || optarg[0] == '-') if (sscanf(optarg, "%d", &afl->cpu_to_bind) < 0) {
FATAL("Bad syntax used for -b"); FATAL("Bad syntax used for -b");
}
break; break;
} }

View File

@ -120,7 +120,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
} }
} || { } || {
$ECHO "$YELLOW[-] not an intel platform, cannot test afl-gcc" $ECHO "$YELLOW[-] not an intel platform, cannot test afl-gcc"
INCOMPLETE=1 #this is not incomplete as this feature doesnt exist, so all good
} }
. ./test-post.sh . ./test-post.sh