diff options
-rw-r--r-- | .clang-format | 148 | ||||
-rwxr-xr-x | .custom-format.py | 119 | ||||
-rw-r--r-- | Makefile | 45 | ||||
-rw-r--r-- | TODO | 8 | ||||
-rw-r--r-- | docs/ChangeLog | 4 | ||||
-rw-r--r-- | include/afl-as.h (renamed from afl-as.h) | 0 | ||||
-rw-r--r-- | include/alloc-inl.h (renamed from alloc-inl.h) | 26 | ||||
-rw-r--r-- | include/common.h (renamed from afl-common.h) | 0 | ||||
-rw-r--r-- | include/config.h | 359 | ||||
-rw-r--r-- | include/debug.h (renamed from debug.h) | 6 | ||||
-rw-r--r-- | include/forkserver.h | 25 | ||||
-rw-r--r-- | include/hash.h (renamed from hash.h) | 0 | ||||
-rw-r--r-- | include/sharedmem.h (renamed from sharedmem.h) | 5 | ||||
-rw-r--r-- | include/types.h | 91 | ||||
-rw-r--r-- | libdislocator/Makefile | 2 | ||||
-rw-r--r-- | libdislocator/libdislocator.so.c | 4 | ||||
-rw-r--r-- | libtokencap/Makefile | 2 | ||||
-rw-r--r-- | llvm_mode/LLVMInsTrim.so.cc | 4 | ||||
-rw-r--r-- | llvm_mode/Makefile | 4 | ||||
-rw-r--r-- | llvm_mode/afl-clang-fast.c | 8 | ||||
-rw-r--r-- | llvm_mode/afl-llvm-pass.so.cc | 4 | ||||
-rw-r--r-- | llvm_mode/afl-llvm-rt.o.c | 4 | ||||
-rw-r--r-- | qemu_mode/libcompcov/Makefile | 2 | ||||
-rw-r--r-- | qemu_mode/libcompcov/libcompcov.so.c | 4 | ||||
-rw-r--r-- | src/afl-analyze.c (renamed from afl-analyze.c) | 6 | ||||
-rw-r--r-- | src/afl-as.c (renamed from afl-as.c) | 0 | ||||
-rw-r--r-- | src/afl-common.c (renamed from afl-common.c) | 3 | ||||
-rw-r--r-- | src/afl-forkserver.c | 401 | ||||
-rw-r--r-- | src/afl-fuzz.c (renamed from afl-fuzz.c) | 483 | ||||
-rw-r--r-- | src/afl-gcc.c (renamed from afl-gcc.c) | 0 | ||||
-rw-r--r-- | src/afl-gotcpu.c (renamed from afl-gotcpu.c) | 4 | ||||
-rw-r--r-- | src/afl-sharedmem.c (renamed from sharedmem.c) | 0 | ||||
-rw-r--r-- | src/afl-showmap.c (renamed from afl-showmap.c) | 4 | ||||
-rw-r--r-- | src/afl-tmin.c (renamed from afl-tmin.c) | 132 | ||||
l---------[-rw-r--r--] | types.h | 92 |
35 files changed, 1383 insertions, 616 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..ef4cb190 --- /dev/null +++ b/.clang-format @@ -0,0 +1,148 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: true +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^<ext/.*\.h>' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Right +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + CanonicalDelimiter: '' + BasedOnStyle: google +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 8 +UseTab: Never +... + diff --git a/.custom-format.py b/.custom-format.py new file mode 100755 index 00000000..32b8f7c9 --- /dev/null +++ b/.custom-format.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 + +import subprocess +import sys +import os +import re + +# string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # future use + +with open(".clang-format") as f: + fmt = f.read() + +CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN") +if CLANG_FORMAT_BIN is None: + p = subprocess.Popen(["clang-format", "--version"], stdout=subprocess.PIPE) + o, _ = p.communicate() + o = str(o, "utf-8") + o = o[len("clang-format version "):].strip() + o = o[:o.find(".")] + o = int(o) + if o < 7: + if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0: + CLANG_FORMAT_BIN = 'clang-format-7' + elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0: + CLANG_FORMAT_BIN = 'clang-format-8' + elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0: + CLANG_FORMAT_BIN = 'clang-format-9' + elif subprocess.call(['which', 'clang-format-10'], stdout=subprocess.PIPE) == 0: + CLANG_FORMAT_BIN = 'clang-format-10' + else: + print ("clang-format 7 or above is needed. Aborted.") + exit(1) + else: + CLANG_FORMAT_BIN = 'clang-format' + +COLUMN_LIMIT = 80 +for line in fmt.split("\n"): + line = line.split(":") + if line[0].strip() == "ColumnLimit": + COLUMN_LIMIT = int(line[1].strip()) + + +def custom_format(filename): + p = subprocess.Popen([CLANG_FORMAT_BIN, filename], stdout=subprocess.PIPE) + src, _ = p.communicate() + src = str(src, "utf-8") + + macro_indent = 0 + in_define = False + last_line = None + out = "" + + for line in src.split("\n"): + if line.startswith("#"): + i = macro_indent + if line.startswith("#end") and macro_indent > 0: + macro_indent -= 1 + i -= 1 + elif line.startswith("#el") and macro_indent > 0: + i -= 1 + elif line.startswith("#if") and not (line.startswith("#ifndef") and (line.endswith("_H") or line.endswith("H_"))): + macro_indent += 1 + elif line.startswith("#define"): + in_define = True + r = "#" + (i * " ") + line[1:] + if i != 0 and line.endswith("\\"): + r = r[:-1] + while r[-1].isspace() and len(r) != (len(line)-1): + r = r[:-1] + r += "\\" + if len(r) <= COLUMN_LIMIT: + line = r + + elif "/*" in line and not line.strip().startswith("/*") and line.endswith("*/") and len(line) < (COLUMN_LIMIT-2): + cmt_start = line.rfind("/*") + line = line[:cmt_start] + " " * (COLUMN_LIMIT-2 - len(line)) + line[cmt_start:] + + define_padding = 0 + if last_line is not None and in_define and last_line.endswith("\\"): + last_line = last_line[:-1] + define_padding = max(0, len(last_line[last_line.rfind("\n")+1:])) + + if last_line is not None and last_line.strip().endswith("{") and line.strip() != "": + line = (" " * define_padding + "\\" if in_define else "") + "\n" + line + elif last_line is not None and last_line.strip().startswith("}") and line.strip() != "": + line = (" " * define_padding + "\\" if in_define else "") + "\n" + line + elif line.strip().startswith("}") and last_line is not None and last_line.strip() != "": + line = (" " * define_padding + "\\" if in_define else "") + "\n" + line + + if not line.endswith("\\"): + in_define = False + + out += line + "\n" + last_line = line + + return (out) + +args = sys.argv[1:] +if len(args) == 0: + print ("Usage: ./format.py [-i] <filename>") + print () + print (" The -i option, if specified, let the script to modify in-place") + print (" the source files. By default the results are written to stdout.") + print() + exit(1) + +in_place = False +if args[0] == "-i": + in_place = True + args = args[1:] + +for filename in args: + code = custom_format(filename) + if in_place: + with open(filename, "w") as f: + f.write(code) + else: + print(code) + diff --git a/Makefile b/Makefile index e6e3af85..9699a0ad 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ #TEST_MMAP=1 PROGNAME = afl -VERSION = $(shell grep '^\#define VERSION ' config.h | cut -d '"' -f2) +VERSION = $(shell grep '^\#define VERSION ' include/config.h | cut -d '"' -f2) PREFIX ?= /usr/local BIN_PATH = $(PREFIX)/bin @@ -31,7 +31,7 @@ PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze SH_PROGS = afl-plot afl-cmin afl-whatsup afl-system-config CFLAGS ?= -O3 -funroll-loops -CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \ +CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ \ -DAFL_PATH=\"$(HELPER_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" \ -DBIN_PATH=\"$(BIN_PATH)\" @@ -47,7 +47,7 @@ else TEST_CC = afl-clang endif -COMM_HDR = alloc-inl.h config.h debug.h types.h +COMM_HDR = include/alloc-inl.h include/config.h include/debug.h include/types.h ifeq "$(shell echo '\#include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) -x c - -o .test -I$(PYTHON_INCLUDE) -lpython2.7 2>/dev/null && echo 1 || echo 0 )" "1" @@ -123,34 +123,37 @@ endif ready: @echo "[+] Everything seems to be working, ready to compile." -afl-gcc: afl-gcc.c $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) +afl-gcc: src/afl-gcc.c $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS) set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done -afl-as: afl-as.c afl-as.h $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) +afl-as: src/afl-as.c include/afl-as.h $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS) ln -sf afl-as as -afl-common.o : afl-common.c - $(CC) $(CFLAGS) -c afl-common.c +afl-common.o : src/afl-common.c include/common.h + $(CC) $(CFLAGS) -c src/afl-common.c -sharedmem.o : sharedmem.c - $(CC) $(CFLAGS) -c sharedmem.c +afl-forkserver.o : src/afl-forkserver.c include/forkserver.h + $(CC) $(CFLAGS) -c src/afl-forkserver.c -afl-fuzz: afl-fuzz.c afl-common.o sharedmem.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $@.c afl-common.o sharedmem.o -o $@ $(LDFLAGS) $(PYFLAGS) +afl-sharedmem.o : src/afl-sharedmem.c include/sharedmem.h + $(CC) $(CFLAGS) -c src/afl-sharedmem.c -afl-showmap: afl-showmap.c afl-common.o sharedmem.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $@.c afl-common.o sharedmem.o -o $@ $(LDFLAGS) +afl-fuzz: src/afl-fuzz.c afl-common.o afl-sharedmem.o afl-forkserver.o $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) src/$@.c afl-common.o afl-sharedmem.o afl-forkserver.o -o $@ $(LDFLAGS) $(PYFLAGS) -afl-tmin: afl-tmin.c afl-common.o sharedmem.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $@.c afl-common.o sharedmem.o -o $@ $(LDFLAGS) +afl-showmap: src/afl-showmap.c afl-common.o afl-sharedmem.o $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) src/$@.c afl-common.o afl-sharedmem.o -o $@ $(LDFLAGS) -afl-analyze: afl-analyze.c afl-common.o sharedmem.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $@.c afl-common.o sharedmem.o -o $@ $(LDFLAGS) +afl-tmin: src/afl-tmin.c afl-common.o afl-sharedmem.o afl-forkserver.o $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) src/$@.c afl-common.o afl-sharedmem.o afl-forkserver.o -o $@ $(LDFLAGS) -afl-gotcpu: afl-gotcpu.c $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) +afl-analyze: src/afl-analyze.c afl-common.o afl-sharedmem.o $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) src/$@.c afl-common.o afl-sharedmem.o -o $@ $(LDFLAGS) + +afl-gotcpu: src/afl-gotcpu.c $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) src/$@.c -o $@ $(LDFLAGS) ifndef AFL_NO_X86 diff --git a/TODO b/TODO index cb95f899..c2cf10a5 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,9 @@ Roadmap 2.53d: ============== - - indent all the code: .clang-format - - update docs/sister_projects.txt +all: + - indent all the code: .clang-format? + (vh: tried, the variable definion look very ugly then, what to do?) afl-fuzz: - put mutator, scheduler, forkserver and input channels in individual files @@ -18,8 +19,9 @@ gcc_plugin: - neverZero qemu_mode: + - update to 4.x - deferred mode with AFL_DEFERRED_QEMU=0xaddress - @andrea - dont we have that already with AFL_ENTRYPOINT? + (vh: @andrea - dont we have that already with AFL_ENTRYPOINT?) unit testing / or large testcase campaign diff --git a/docs/ChangeLog b/docs/ChangeLog index 6d4c4792..782320d6 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -21,10 +21,12 @@ Version ++2.53d (dev): - Android is now supported (thank to JoeyJiao!) - still need to modify the Makefile though - fix building qemu on some Ubuntus (thanks to floyd!) - custom mutator by a loaded library is now supported (thanks to kyakdan!) + - more support for *BSD (thanks to devnexen!) + - fix building on *BSD (thanks to tobias.kortkamp for the patch) - fix for a few features to support different map sized than 2^16 - afl-showmap: new option -r now shows the real values in the buckets (stock afl never did), plus shows tuple content summary information now - - fix building on *BSD (thanks to tobias.kortkamp for the patch) + - the forkserver is now in its own C file to be easily integratable - small docu updates - NeverZero counters for QEMU - NeverZero counters for Unicorn diff --git a/afl-as.h b/include/afl-as.h index 4748eda7..4748eda7 100644 --- a/afl-as.h +++ b/include/afl-as.h diff --git a/alloc-inl.h b/include/alloc-inl.h index 04f56d0d..2f98da0e 100644 --- a/alloc-inl.h +++ b/include/alloc-inl.h @@ -112,7 +112,7 @@ static inline void* DFL_ck_alloc_nozero(u32 size) { - void* ret; + u8* ret; if (!size) return NULL; @@ -126,7 +126,7 @@ static inline void* DFL_ck_alloc_nozero(u32 size) { ALLOC_S(ret) = size; ALLOC_C2(ret) = ALLOC_MAGIC_C2; - return ret; + return (void *)ret; } @@ -163,7 +163,8 @@ static inline void DFL_ck_free(void* mem) { ALLOC_C1(mem) = ALLOC_MAGIC_F; - free(mem - ALLOC_OFF_HEAD); + u8 *realStart = mem; + free(realStart - ALLOC_OFF_HEAD); } @@ -174,7 +175,7 @@ static inline void DFL_ck_free(void* mem) { static inline void* DFL_ck_realloc(void* orig, u32 size) { - void* ret; + u8* ret; u32 old_size = 0; if (!size) { @@ -193,7 +194,9 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) { #endif /* !DEBUG_BUILD */ old_size = ALLOC_S(orig); - orig -= ALLOC_OFF_HEAD; + u8 *origu8 = orig; + origu8 -= ALLOC_OFF_HEAD; + orig = origu8; ALLOC_CHECK_SIZE(old_size); @@ -216,10 +219,11 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) { if (orig) { - memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size)); - memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size); + u8 *origu8 = orig; + memcpy(ret + ALLOC_OFF_HEAD, origu8 + ALLOC_OFF_HEAD, MIN(size, old_size)); + memset(origu8 + ALLOC_OFF_HEAD, 0xFF, old_size); - ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F; + ALLOC_C1(origu8 + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F; free(orig); @@ -236,7 +240,7 @@ static inline void* DFL_ck_realloc(void* orig, u32 size) { if (size > old_size) memset(ret + old_size, 0, size - old_size); - return ret; + return (void *)ret; } @@ -269,7 +273,7 @@ static inline void* DFL_ck_realloc_block(void* orig, u32 size) { static inline u8* DFL_ck_strdup(u8* str) { - void* ret; + u8* ret; u32 size; if (!str) return NULL; @@ -296,7 +300,7 @@ static inline u8* DFL_ck_strdup(u8* str) { static inline void* DFL_ck_memdup(void* mem, u32 size) { - void* ret; + u8* ret; if (!mem || !size) return NULL; diff --git a/afl-common.h b/include/common.h index 161caa39..161caa39 100644 --- a/afl-common.h +++ b/include/common.h diff --git a/include/config.h b/include/config.h new file mode 100644 index 00000000..37a2a794 --- /dev/null +++ b/include/config.h @@ -0,0 +1,359 @@ +/* + american fuzzy lop plus plus - vaguely configurable bits + ---------------------------------------------- + + Written and maintained by Michal Zalewski <lcamtuf@google.com> + + Copyright 2013, 2014, 2015, 2016 Google Inc. 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 + +#include "types.h" + +/* Version string: */ + +#define VERSION "++2.53d" // c = release, d = volatile github dev + +/****************************************************** + * * + * Settings that may be of interest to power users: * + * * + ******************************************************/ + +/* Comment out to disable terminal colors (note that this makes afl-analyze + a lot less nice): */ + +#define USE_COLOR + +/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */ + +#define FANCY_BOXES + +/* 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 1000 + +/* Timeout rounding factor when auto-scaling (milliseconds): */ + +#define EXEC_TM_ROUND 20 + +/* Default memory limit for child process (MB): */ + +#ifndef __x86_64__ +# define MEM_LIMIT 25 +#else +# define MEM_LIMIT 50 +#endif /* ^!__x86_64__ */ + +/* Default memory limit when running in QEMU mode (MB): */ + +#define MEM_LIMIT_QEMU 200 + +/* Default memory limit when running in Unicorn mode (MB): */ + +#define MEM_LIMIT_UNICORN 200 + +/* Number of calibration cycles per every new test case (and for test + cases that show variable behavior): */ + +#define CAL_CYCLES 8 +#define CAL_CYCLES_LONG 40 + +/* Number of subsequent timeouts before abandoning an input file: */ + +#define TMOUT_LIMIT 250 + +/* Maximum number of unique hangs or crashes to record: */ + +#define KEEP_UNIQUE_HANG 500 +#define KEEP_UNIQUE_CRASH 5000 + +/* Baseline number of random tweaks during a single 'havoc' stage: */ + +#define HAVOC_CYCLES 256 +#define HAVOC_CYCLES_INIT 1024 + +/* Maximum multiplier for the above (should be a power of two, beware + of 32-bit int overflows): */ + +#define HAVOC_MAX_MULT 16 +#define HAVOC_MAX_MULT_MOPT 32 + +/* Absolute minimum number of havoc cycles (after all adjustments): */ + +#define HAVOC_MIN 16 + +/* Power Schedule Divisor */ +#define POWER_BETA 1 +#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 = 7) produces 2, 4, 8, 16, 32, 64, or + 128 stacked tweaks: */ + +#define HAVOC_STACK_POW2 7 + +/* 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 32 +#define HAVOC_BLK_MEDIUM 128 +#define HAVOC_BLK_LARGE 1500 + +/* Extra-large blocks, selected very rarely (<5% of the time): */ + +#define HAVOC_BLK_XL 32768 + +/* 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): */ + +#define MAX_FILE (1 * 1024 * 1024) + +/* 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 200 + +/* 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 50 +#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10) + +/* 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 5 + +/* 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_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_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 */ + +/*********************************************************** + * * + * Really exotic stuff you probably don't want to touch: * + * * + ***********************************************************/ + +/* Call count interval between reseeding the libc PRNG from /dev/urandom: */ + +#define RESEED_RNG 10000 + +/* 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" + +/* 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 (1 << 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) + +/* 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 + +#endif /* ! _HAVE_CONFIG_H */ diff --git a/debug.h b/include/debug.h index a943a573..349aa650 100644 --- a/debug.h +++ b/include/debug.h @@ -199,7 +199,7 @@ #define FATAL(x...) do { \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] PROGRAM ABORT : " \ cBRI x); \ - SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", \ + SAYF(cLRD "\n Location : " cRST "%s(), %s:%d\n\n", \ __FUNCTION__, __FILE__, __LINE__); \ exit(1); \ } while (0) @@ -209,7 +209,7 @@ #define ABORT(x...) do { \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] PROGRAM ABORT : " \ cBRI x); \ - SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", \ + SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%d\n\n", \ __FUNCTION__, __FILE__, __LINE__); \ abort(); \ } while (0) @@ -220,7 +220,7 @@ fflush(stdout); \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] SYSTEM ERROR : " \ cBRI x); \ - SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", \ + SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%d\n", \ __FUNCTION__, __FILE__, __LINE__); \ SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \ exit(1); \ diff --git a/include/forkserver.h b/include/forkserver.h new file mode 100644 index 00000000..fa40d9c6 --- /dev/null +++ b/include/forkserver.h @@ -0,0 +1,25 @@ +#ifndef __AFL_FORKSERVER_H +#define __AFL_FORKSERVER_H + +void handle_timeout(int sig); +void init_forkserver(char **argv); + +#ifdef __APPLE__ +#define MSG_FORK_ON_APPLE \ + " - On MacOS X, the semantics of fork() syscalls are non-standard and " \ + "may\n" \ + " break afl-fuzz performance optimizations when running " \ + "platform-specific\n" \ + " targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n" +#else +#define MSG_FORK_ON_APPLE "" +#endif + +#ifdef RLIMIT_AS + #define MSG_ULIMIT_USAGE " ( ulimit -Sv $[%llu << 10];" +#else + #define MSG_ULIMIT_USAGE " ( ulimit -Sd $[%llu << 10];" +#endif /* ^RLIMIT_AS */ + + +#endif diff --git a/hash.h b/include/hash.h index f39a8257..f39a8257 100644 --- a/hash.h +++ b/include/hash.h diff --git a/sharedmem.h b/include/sharedmem.h index 53a85fcb..9aa44d0e 100644 --- a/sharedmem.h +++ b/include/sharedmem.h @@ -1,6 +1,7 @@ -#ifndef __SHAREDMEM_H -#define __SHAREDMEM_H +#ifndef __AFL_SHAREDMEM_H +#define __AFL_SHAREDMEM_H void setup_shm(unsigned char dumb_mode); void remove_shm(void); + #endif diff --git a/include/types.h b/include/types.h new file mode 100644 index 00000000..7606d4ed --- /dev/null +++ b/include/types.h @@ -0,0 +1,91 @@ +/* + american fuzzy lop - type definitions and minor macros + ------------------------------------------------------ + + Written and maintained by Michal Zalewski <lcamtuf@google.com> + + Copyright 2013, 2014, 2015 Google Inc. 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> + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; + +/* + + Ugh. There is an unintended compiler / glibc #include glitch caused by + combining the u64 type an %llu in format strings, necessitating a workaround. + + In essence, the compiler is always looking for 'unsigned long long' for %llu. + On 32-bit systems, the u64 type (aliased to uint64_t) is expanded to + 'unsigned long long' in <bits/types.h>, so everything checks out. + + But on 64-bit systems, it is #ifdef'ed in the same file as 'unsigned long'. + Now, it only happens in circumstances where the type happens to have the + expected bit width, *but* the compiler does not know that... and complains + about 'unsigned long' being unsafe to pass to %llu. + + */ + +#ifdef __x86_64__ +typedef unsigned long long u64; +#else +typedef uint64_t u64; +#endif /* ^__x86_64__ */ + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +#ifndef MIN +# define MIN(_a,_b) ((_a) > (_b) ? (_b) : (_a)) +# define MAX(_a,_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)); \ + }) + +#ifdef AFL_LLVM_PASS +# define AFL_R(x) (random() % (x)) +#else +# define R(x) (random() % (x)) +#endif /* ^AFL_LLVM_PASS */ + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + +#define MEM_BARRIER() \ + __asm__ volatile("" ::: "memory") + +#if __GNUC__ < 6 + #define likely(_x) (_x) + #define unlikely(_x) (_x) +#else + #define likely(_x) __builtin_expect(!!(_x), 1) + #define unlikely(_x) __builtin_expect(!!(_x), 0) +#endif + +#endif /* ! _HAVE_TYPES_H */ diff --git a/libdislocator/Makefile b/libdislocator/Makefile index a4116780..236667ec 100644 --- a/libdislocator/Makefile +++ b/libdislocator/Makefile @@ -18,7 +18,7 @@ HELPER_PATH = $(PREFIX)/lib/afl VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2) -CFLAGS ?= -O3 -funroll-loops +CFLAGS ?= -O3 -funroll-loops -I ../include/ CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign all: libdislocator.so diff --git a/libdislocator/libdislocator.so.c b/libdislocator/libdislocator.so.c index 043480a6..71620b17 100644 --- a/libdislocator/libdislocator.so.c +++ b/libdislocator/libdislocator.so.c @@ -25,8 +25,8 @@ #include <limits.h> #include <sys/mman.h> -#include "../config.h" -#include "../types.h" +#include "config.h" +#include "types.h" #ifndef PAGE_SIZE # define PAGE_SIZE 4096 diff --git a/libtokencap/Makefile b/libtokencap/Makefile index a464f76d..ec4c8f95 100644 --- a/libtokencap/Makefile +++ b/libtokencap/Makefile @@ -18,7 +18,7 @@ HELPER_PATH = $(PREFIX)/lib/afl VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2) -CFLAGS ?= -O3 -funroll-loops +CFLAGS ?= -O3 -funroll-loops -I ../include/ CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign all: libtokencap.so diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc index 0a15680d..95b52d48 100644 --- a/llvm_mode/LLVMInsTrim.so.cc +++ b/llvm_mode/LLVMInsTrim.so.cc @@ -24,8 +24,8 @@ #include <string> #include <fstream> -#include "../config.h" -#include "../debug.h" +#include "config.h" +#include "debug.h" #include "MarkNodes.h" diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index 160a8fe6..e51803c8 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -40,7 +40,7 @@ ifeq "$(LLVM_MAJOR)" "9" endif CFLAGS ?= -O3 -funroll-loops -CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \ +CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I ../include/ \ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ -DVERSION=\"$(VERSION)\" ifdef AFL_TRACE_PC @@ -48,7 +48,7 @@ ifdef AFL_TRACE_PC endif CXXFLAGS ?= -O3 -funroll-loops -CXXFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g \ +CXXFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -I ../include/ \ -DVERSION=\"$(VERSION)\" -Wno-variadic-macros CLANG_CFL = `$(LLVM_CONFIG) --cxxflags` -Wl,-znodelete -fno-rtti -fpic $(CXXFLAGS) diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index a4bb7539..1b810edf 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -23,10 +23,10 @@ #define AFL_MAIN -#include "../config.h" -#include "../types.h" -#include "../debug.h" -#include "../alloc-inl.h" +#include "config.h" +#include "types.h" +#include "debug.h" +#include "alloc-inl.h" #include <stdio.h> #include <unistd.h> diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index bdad835f..b242163e 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -24,8 +24,8 @@ #define AFL_LLVM_PASS -#include "../config.h" -#include "../debug.h" +#include "config.h" +#include "debug.h" #include <stdio.h> #include <stdlib.h> diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 67208454..e6d9b993 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -22,8 +22,8 @@ #ifdef __ANDROID__ #include "android-ashmem.h" #endif -#include "../config.h" -#include "../types.h" +#include "config.h" +#include "types.h" #include <stdio.h> #include <stdlib.h> diff --git a/qemu_mode/libcompcov/Makefile b/qemu_mode/libcompcov/Makefile index c984588b..a1f4e31f 100644 --- a/qemu_mode/libcompcov/Makefile +++ b/qemu_mode/libcompcov/Makefile @@ -18,7 +18,7 @@ HELPER_PATH = $(PREFIX)/lib/afl VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2) -CFLAGS ?= -O3 -funroll-loops +CFLAGS ?= -O3 -funroll-loops -I ../../include/ CFLAGS += -Wall -Wno-unused-result -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign LDFLAGS += -ldl diff --git a/qemu_mode/libcompcov/libcompcov.so.c b/qemu_mode/libcompcov/libcompcov.so.c index 0ccda927..9e44067e 100644 --- a/qemu_mode/libcompcov/libcompcov.so.c +++ b/qemu_mode/libcompcov/libcompcov.so.c @@ -27,8 +27,8 @@ #include <sys/types.h> #include <sys/shm.h> -#include "../../types.h" -#include "../../config.h" +#include "types.h" +#include "config.h" #include "pmparser.h" diff --git a/afl-analyze.c b/src/afl-analyze.c index 0e8c9fb0..5bb96154 100644 --- a/afl-analyze.c +++ b/src/afl-analyze.c @@ -30,7 +30,7 @@ #include "alloc-inl.h" #include "hash.h" #include "sharedmem.h" -#include "afl-common.h" +#include "common.h" #include <stdio.h> #include <unistd.h> @@ -741,8 +741,8 @@ static void usage(u8* argv0) { "Execution control settings:\n\n" " -f file - input file read by the tested program (stdin)\n" - " -t msec - timeout for each run (%u ms)\n" - " -m megs - memory limit for child process (%u MB)\n" + " -t msec - timeout for each run (%d ms)\n" + " -m megs - memory limit for child process (%d MB)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use unicorn-based instrumentation (Unicorn mode)\n\n" diff --git a/afl-as.c b/src/afl-as.c index 94595f24..94595f24 100644 --- a/afl-as.c +++ b/src/afl-as.c diff --git a/afl-common.c b/src/afl-common.c index 1c5e5bfe..f3bbdfb4 100644 --- a/afl-common.c +++ b/src/afl-common.c @@ -15,6 +15,8 @@ #ifndef __glibc__ #include <unistd.h> #endif + + void detect_file_args(char** argv, u8* prog_in) { u32 i = 0; @@ -28,6 +30,7 @@ void detect_file_args(char** argv, u8* prog_in) { cwd = getcwd(buf, (size_t)size); /* portable version */ } else { PFATAL("getcwd() failed"); + cwd = 0; /* for dumb compilers */ } #endif diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c new file mode 100644 index 00000000..0051f6b0 --- /dev/null +++ b/src/afl-forkserver.c @@ -0,0 +1,401 @@ +#include "config.h" +#include "types.h" +#include "debug.h" +#include "forkserver.h" + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <sys/resource.h> + +/* a program that includes afl-forkserver needs to define these */ +extern u8 uses_asan; +extern u8 *trace_bits; +extern s32 forksrv_pid, child_pid, fsrv_ctl_fd, fsrv_st_fd; +extern s32 out_fd, out_dir_fd, dev_urandom_fd, dev_null_fd; /* initialize these with -1 */ +extern u32 exec_tmout; +extern u64 mem_limit; +extern u8 *out_file, *target_path, *doc_path; +extern FILE *plot_file; + +/* we need this internally but can be defined and read extern in the main source */ +u8 child_timed_out; + + +/* Describe integer as memory size. */ + +u8* forkserver_DMS(u64 val) { + + static u8 tmp[12][16]; + static u8 cur; + +#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) do { \ + if (val < (_divisor) * (_limit_mult)) { \ + sprintf(tmp[cur], _fmt, ((_cast)val) / (_divisor)); \ + return tmp[cur]; \ + } \ + } while (0) + + + cur = (cur + 1) % 12; + + /* 0-9999 */ + CHK_FORMAT(1, 10000, "%llu B", u64); + + /* 10.0k - 99.9k */ + CHK_FORMAT(1024, 99.95, "%0.01f kB", double); + + /* 100k - 999k */ + CHK_FORMAT(1024, 1000, "%llu kB", u64); + + /* 1.00M - 9.99M */ + CHK_FORMAT(1024 * 1024, 9.995, "%0.02f MB", double); + + /* 10.0M - 99.9M */ + CHK_FORMAT(1024 * 1024, 99.95, "%0.01f MB", double); + + /* 100M - 999M */ + CHK_FORMAT(1024 * 1024, 1000, "%llu MB", u64); + + /* 1.00G - 9.99G */ + CHK_FORMAT(1024LL * 1024 * 1024, 9.995, "%0.02f GB", double); + + /* 10.0G - 99.9G */ + CHK_FORMAT(1024LL * 1024 * 1024, 99.95, "%0.01f GB", double); + + /* 100G - 999G */ + CHK_FORMAT(1024LL * 1024 * 1024, 1000, "%llu GB", u64); + + /* 1.00T - 9.99G */ + CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 9.995, "%0.02f TB", double); + + /* 10.0T - 99.9T */ + CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 99.95, "%0.01f TB", double); + +#undef CHK_FORMAT + + /* 100T+ */ + strcpy(tmp[cur], "infty"); + return tmp[cur]; + +} + + + +/* the timeout handler */ + +void handle_timeout(int sig) { + if (child_pid > 0) { + child_timed_out = 1; + kill(child_pid, SIGKILL); + } else if (child_pid == -1 && forksrv_pid > 0) { + child_timed_out = 1; + kill(forksrv_pid, SIGKILL); + } +} + + +/* Spin up fork server (instrumented mode only). The idea is explained here: + + http://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html + + In essence, the instrumentation allows us to skip execve(), and just keep + cloning a stopped child. So, we just execute once, and then send commands + through a pipe. The other part of this logic is in afl-as.h / llvm_mode */ + +void init_forkserver(char **argv) { + + static struct itimerval it; + int st_pipe[2], ctl_pipe[2]; + int status; + s32 rlen; + + ACTF("Spinning up the fork server..."); + + if (pipe(st_pipe) || pipe(ctl_pipe)) + PFATAL("pipe() failed"); + + child_timed_out = 0; + forksrv_pid = fork(); + + if (forksrv_pid < 0) + PFATAL("fork() failed"); + + if (!forksrv_pid) { + + /* CHILD PROCESS */ + + struct rlimit r; + + /* Umpf. On OpenBSD, the default fd limit for root users is set to + soft 128. Let's try to fix that... */ + + if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) { + r.rlim_cur = FORKSRV_FD + 2; + setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */ + } + + if (mem_limit) { + r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; + +#ifdef RLIMIT_AS + setrlimit(RLIMIT_AS, &r); /* Ignore errors */ +#else + /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but + according to reliable sources, RLIMIT_DATA covers anonymous + maps - so we should be getting good protection against OOM bugs. */ + + setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ +#endif /* ^RLIMIT_AS */ + } + + /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered + before the dump is complete. */ + +// r.rlim_max = r.rlim_cur = 0; +// setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + + /* Isolate the process and configure standard descriptors. If out_file is + specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ + + setsid(); + + if (!getenv("AFL_DEBUG_CHILD_OUTPUT")) { + dup2(dev_null_fd, 1); + dup2(dev_null_fd, 2); + } + + if (out_file) { + dup2(dev_null_fd, 0); + } else { + dup2(out_fd, 0); + close(out_fd); + } + + /* Set up control and status pipes, close the unneeded original fds. */ + + if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) + PFATAL("dup2() failed"); + if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) + PFATAL("dup2() failed"); + + close(ctl_pipe[0]); + close(ctl_pipe[1]); + close(st_pipe[0]); + close(st_pipe[1]); + + close(out_dir_fd); + close(dev_null_fd); + close(dev_urandom_fd); + close(plot_file == NULL ? -1 : fileno(plot_file)); + + /* This should improve performance a bit, since it stops the linker from + doing extra work post-fork(). */ + + if (!getenv("LD_BIND_LAZY")) + setenv("LD_BIND_NOW", "1", 0); + + /* Set sane defaults for ASAN if nothing else specified. */ + + setenv("ASAN_OPTIONS", + "abort_on_error=1:" + "detect_leaks=0:" + "symbolize=0:" + "allocator_may_return_null=1", + 0); + + /* MSAN is tricky, because it doesn't support abort_on_error=1 at this + point. So, we do this in a very hacky way. */ + + setenv("MSAN_OPTIONS", + "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" + "abort_on_error=1:" + "allocator_may_return_null=1:" + "msan_track_origins=0", + 0); + + execv(target_path, argv); + + /* Use a distinctive bitmap signature to tell the parent about execv() + falling through. */ + + *(u32 *)trace_bits = EXEC_FAIL_SIG; + exit(0); + } + + /* PARENT PROCESS */ + + /* Close the unneeded endpoints. */ + + close(ctl_pipe[0]); + close(st_pipe[1]); + + fsrv_ctl_fd = ctl_pipe[1]; + fsrv_st_fd = st_pipe[0]; + + /* Wait for the fork server to come up, but don't wait too long. */ + + if (exec_tmout) { + it.it_value.tv_sec = ((exec_tmout * FORK_WAIT_MULT) / 1000); + it.it_value.tv_usec = ((exec_tmout * FORK_WAIT_MULT) % 1000) * 1000; + } + + setitimer(ITIMER_REAL, &it, NULL); + + rlen = read(fsrv_st_fd, &status, 4); + + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 0; + + setitimer(ITIMER_REAL, &it, NULL); + + /* If we have a four-byte "hello" message from the server, we're all set. + Otherwise, try to figure out what went wrong. */ + + if (rlen == 4) { + OKF("All right - fork server is up."); + return; + } + + if (child_timed_out) + FATAL("Timeout while initializing fork server (adjusting -t may help)"); + + if (waitpid(forksrv_pid, &status, 0) <= 0) + PFATAL("waitpid() failed"); + + if (WIFSIGNALED(status)) { + + if (mem_limit && mem_limit < 500 && uses_asan) { + + SAYF("\n" cLRD "[-] " cRST "Whoops, the target binary crashed suddenly, " + "before receiving any input\n" + " from the fuzzer! Since it seems to be built with ASAN and you " + "have a\n" + " restrictive memory limit configured, this is expected; please " + "read\n" + " %s/notes_for_asan.txt for help.\n", + doc_path); + + } else if (!mem_limit) { + + SAYF("\n" cLRD "[-] " cRST "Whoops, the target binary crashed suddenly, " + "before receiving any input\n" + " from the fuzzer! There are several probable explanations:\n\n" + + " - The binary is just buggy and explodes entirely on its own. " + "If so, you\n" + " need to fix the underlying problem or find a better " + "replacement.\n\n" + + MSG_FORK_ON_APPLE + + " - Less likely, there is a horrible bug in the fuzzer. If other " + "options\n" + " fail, poke <afl-users@googlegroups.com> for troubleshooting " + "tips.\n"); + + } else { + + SAYF("\n" cLRD "[-] " cRST "Whoops, the target binary crashed suddenly, " + "before receiving any input\n" + " from the fuzzer! There are several probable explanations:\n\n" + + " - The current memory limit (%s) is too restrictive, causing " + "the\n" + " target to hit an OOM condition in the dynamic linker. Try " + "bumping up\n" + " the limit with the -m setting in the command line. A simple " + "way confirm\n" + " this diagnosis would be:\n\n" + + MSG_ULIMIT_USAGE " /path/to/fuzzed_app )\n\n" + + " Tip: you can use http://jwilk.net/software/recidivm to " + "quickly\n" + " estimate the required amount of virtual memory for the " + "binary.\n\n" + + " - The binary is just buggy and explodes entirely on its own. " + "If so, you\n" + " need to fix the underlying problem or find a better " + "replacement.\n\n" + + MSG_FORK_ON_APPLE + + " - Less likely, there is a horrible bug in the fuzzer. If other " + "options\n" + " fail, poke <afl-users@googlegroups.com> for troubleshooting " + "tips.\n", + forkserver_DMS(mem_limit << 20), mem_limit - 1); + } + + FATAL("Fork server crashed with signal %d", WTERMSIG(status)); + } + + if (*(u32 *)trace_bits == EXEC_FAIL_SIG) + FATAL("Unable to execute target application ('%s')", argv[0]); + + if (mem_limit && mem_limit < 500 && uses_asan) { + + SAYF("\n" cLRD "[-] " cRST "Hmm, looks like the target binary terminated " + "before we could complete a\n" + " handshake with the injected code. Since it seems to be built " + "with ASAN and\n" + " you have a restrictive memory limit configured, this is " + "expected; please\n" + " read %s/notes_for_asan.txt for help.\n", + doc_path); + + } else if (!mem_limit) { + + SAYF("\n" cLRD "[-] " cRST "Hmm, looks like the target binary terminated " + "before we could complete a\n" + " handshake with the injected code. Perhaps there is a horrible " + "bug in the\n" + " fuzzer. Poke <afl-users@googlegroups.com> for troubleshooting " + "tips.\n"); + + } else { + + SAYF( + "\n" cLRD "[-] " cRST "Hmm, looks like the target binary terminated " + "before we could complete a\n" + " handshake with the injected code. There are %s probable " + "explanations:\n\n" + + "%s" + " - The current memory limit (%s) is too restrictive, causing an " + "OOM\n" + " fault in the dynamic linker. This can be fixed with the -m " + "option. A\n" + " simple way to confirm the diagnosis may be:\n\n" + + MSG_ULIMIT_USAGE " /path/to/fuzzed_app )\n\n" + + " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" + " estimate the required amount of virtual memory for the " + "binary.\n\n" + + " - Less likely, there is a horrible bug in the fuzzer. If other " + "options\n" + " fail, poke <afl-users@googlegroups.com> for troubleshooting " + "tips.\n", + getenv(DEFER_ENV_VAR) ? "three" : "two", + getenv(DEFER_ENV_VAR) + ? " - You are using deferred forkserver, but __AFL_INIT() is " + "never\n" + " reached before the program terminates.\n\n" + : "", + forkserver_DMS(mem_limit << 20), mem_limit - 1); + } + + FATAL("Fork server handshake failed"); +} + diff --git a/afl-fuzz.c b/src/afl-fuzz.c index 0e252bea..1e8c5777 100644 --- a/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -31,13 +31,15 @@ #ifdef __ANDROID__ #include "android-ashmem.h" #endif + #include "config.h" #include "types.h" #include "debug.h" #include "alloc-inl.h" #include "hash.h" #include "sharedmem.h" -#include "afl-common.h" +#include "forkserver.h" +#include "common.h" #include <stdio.h> #include <unistd.h> @@ -148,7 +150,6 @@ double period_pilot_tmp = 5000.0; int key_lv = 0; EXP_ST u8 *in_dir, /* Input directory with test cases */ - *out_file, /* File to fuzz, if any */ *out_dir, /* Working & output directory */ *tmp_dir , /* Temporary directory for input */ *sync_dir, /* Synchronization directory */ @@ -156,15 +157,16 @@ EXP_ST u8 *in_dir, /* Input directory with test cases */ *power_name, /* Power schedule name */ *use_banner, /* Display banner */ *in_bitmap, /* Input bitmap */ - *doc_path, /* Path to documentation dir */ - *target_path, /* Path to target binary */ *file_extension, /* File extension */ *orig_cmdline; /* Original command line */ + u8 *doc_path, /* Path to documentation dir */ + *target_path, /* Path to target binary */ + *out_file; /* File to fuzz, if any */ -EXP_ST u32 exec_tmout = EXEC_TIMEOUT; /* Configurable exec timeout (ms) */ + u32 exec_tmout = EXEC_TIMEOUT; /* Configurable exec timeout (ms) */ static u32 hang_tmout = EXEC_TIMEOUT; /* Timeout used for hang det (ms) */ -EXP_ST u64 mem_limit = MEM_LIMIT; /* Memory cap for child (MB) */ + u64 mem_limit = MEM_LIMIT; /* Memory cap for child (MB) */ EXP_ST u8 cal_cycles = CAL_CYCLES; /* Calibration cycles defaults */ EXP_ST u8 cal_cycles_long = CAL_CYCLES_LONG; @@ -204,7 +206,6 @@ EXP_ST u8 skip_deterministic, /* Skip deterministic stages? */ timeout_given, /* Specific timeout given? */ not_on_tty, /* stdout is not a tty */ term_too_small, /* terminal dimensions too small */ - uses_asan, /* Target uses ASAN? */ no_forkserver, /* Disable forkserver? */ crash_mode, /* Crash mode! Yeah! */ in_place_resume, /* Attempt in-place resume? */ @@ -221,6 +222,7 @@ EXP_ST u8 skip_deterministic, /* Skip deterministic stages? */ deferred_mode, /* Deferred forkserver mode? */ fixed_seed, /* do not reseed */ fast_cal; /* Try to calibrate faster? */ + u8 uses_asan; /* Target uses ASAN? */ static s32 out_fd, /* Persistent fd for out_file */ #ifndef HAVE_ARC4RANDOM @@ -230,7 +232,7 @@ static s32 out_fd, /* Persistent fd for out_file */ fsrv_ctl_fd, /* Fork server control pipe (write) */ fsrv_st_fd; /* Fork server status pipe (read) */ -static s32 forksrv_pid, /* PID of the fork server */ + s32 forksrv_pid, /* PID of the fork server */ child_pid = -1, /* PID of the fuzzed program */ out_dir_fd = -1; /* FD of the lock file */ @@ -321,7 +323,7 @@ static s32 cpu_aff = -1; /* Selected CPU core */ #endif /* HAVE_AFFINITY */ -static FILE* plot_file; /* Gnuplot output file */ +FILE* plot_file; /* Gnuplot output file */ struct queue_entry { @@ -453,7 +455,6 @@ static PyObject *py_functions[PY_FUNC_COUNT]; static int init_py() { Py_Initialize(); u8* module_name = getenv("AFL_PYTHON_MODULE"); - u8 py_notrim = 0; if (module_name) { PyObject* py_name = PyString_FromString(module_name); @@ -462,6 +463,7 @@ static int init_py() { Py_DECREF(py_name); if (py_module != NULL) { + u8 py_notrim = 0; py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init"); py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz"); py_functions[PY_FUNC_INIT_TRIM] = PyObject_GetAttrString(py_module, "init_trim"); @@ -537,9 +539,9 @@ static void finalize_py() { } static void fuzz_py(char* buf, size_t buflen, char* add_buf, size_t add_buflen, char** ret, size_t* retlen) { - PyObject *py_args, *py_value; if (py_module != NULL) { + PyObject *py_args, *py_value; py_args = PyTuple_New(2); py_value = PyByteArray_FromStringAndSize(buf, buflen); if (!py_value) { @@ -833,7 +835,7 @@ static void bind_to_free_cpu(void) { if (i == cpu_core_count) { SAYF("\n" cLRD "[-] " cRST - "Uh-oh, looks like all %u CPU cores on your system are allocated to\n" + "Uh-oh, looks like all %d CPU cores on your system are allocated to\n" " other instances of afl-fuzz (or similar CPU-locked tasks). Starting\n" " another fuzzer on this machine is probably a bad plan, but if you are\n" " absolutely sure, you can set AFL_NO_AFFINITY and try again.\n", @@ -1037,7 +1039,7 @@ static u8* DTD(u64 cur_ms, u64 event_ms) { t_m = (delta / 1000 / 60) % 60; t_s = (delta / 1000) % 60; - sprintf(tmp, "%s days, %u hrs, %u min, %u sec", DI(t_d), t_h, t_m, t_s); + sprintf(tmp, "%s days, %d hrs, %d min, %d sec", DI(t_d), t_h, t_m, t_s); return tmp; } @@ -1097,7 +1099,6 @@ static void mark_as_variable(struct queue_entry* q) { static void mark_as_redundant(struct queue_entry* q, u8 state) { u8* fn; - s32 fd; if (state == q->fs_redundant) return; @@ -1108,6 +1109,8 @@ static void mark_as_redundant(struct queue_entry* q, u8 state) { if (state) { + s32 fd; + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd < 0) PFATAL("Unable to create '%s'", fn); close(fd); @@ -1760,12 +1763,12 @@ static void read_testcases(void) { struct dirent **nl; s32 nl_cnt; u32 i; - u8* fn; + u8* fn1; /* Auto-detect non-in-place resumption attempts. */ - fn = alloc_printf("%s/queue", in_dir); - if (!access(fn, F_OK)) in_dir = fn; else ck_free(fn); + fn1 = alloc_printf("%s/queue", in_dir); + if (!access(fn1, F_OK)) in_dir = fn1; else ck_free(fn1); ACTF("Scanning '%s'...", in_dir); @@ -1800,28 +1803,28 @@ static void read_testcases(void) { struct stat st; - u8* fn = alloc_printf("%s/%s", in_dir, nl[i]->d_name); + u8* fn2 = alloc_printf("%s/%s", in_dir, nl[i]->d_name); u8* dfn = alloc_printf("%s/.state/deterministic_done/%s", in_dir, nl[i]->d_name); u8 passed_det = 0; free(nl[i]); /* not tracked */ - if (lstat(fn, &st) || access(fn, R_OK)) - PFATAL("Unable to access '%s'", fn); + if (lstat(fn2, &st) || access(fn2, R_OK)) + PFATAL("Unable to access '%s'", fn2); /* This also takes care of . and .. */ - if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn, "/README.txt")) { + if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { - ck_free(fn); + ck_free(fn2); ck_free(dfn); continue; } if (st.st_size > MAX_FILE) - FATAL("Test case '%s' is too big (%s, limit is %s)", fn, + FATAL("Test case '%s' is too big (%s, limit is %s)", fn2, DMS(st.st_size), DMS(MAX_FILE)); /* Check for metadata that indicates that deterministic fuzzing @@ -1832,7 +1835,7 @@ static void read_testcases(void) { if (!access(dfn, F_OK)) passed_det = 1; ck_free(dfn); - add_to_queue(fn, st.st_size, passed_det); + add_to_queue(fn2, st.st_size, passed_det); } @@ -2104,7 +2107,7 @@ check_and_sort: DMS(max_len)); if (extras_cnt > MAX_DET_EXTRAS) - WARNF("More than %u tokens - will use them probabilistically.", + WARNF("More than %d tokens - will use them probabilistically.", MAX_DET_EXTRAS); } @@ -2318,304 +2321,6 @@ static void destroy_extras(void) { } -/* Spin up fork server (instrumented mode only). The idea is explained here: - - http://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html - - In essence, the instrumentation allows us to skip execve(), and just keep - cloning a stopped child. So, we just execute once, and then send commands - through a pipe. The other part of this logic is in afl-as.h. */ - -EXP_ST void init_forkserver(char** argv) { - - static struct itimerval it; - int st_pipe[2], ctl_pipe[2]; - int status; - s32 rlen; - - ACTF("Spinning up the fork server..."); - - if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); - - forksrv_pid = fork(); - - if (forksrv_pid < 0) PFATAL("fork() failed"); - - if (!forksrv_pid) { - - /* CHILD PROCESS */ - - struct rlimit r; - - /* Umpf. On OpenBSD, the default fd limit for root users is set to - soft 128. Let's try to fix that... */ - - if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) { - - r.rlim_cur = FORKSRV_FD + 2; - setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */ - - } - - if (mem_limit) { - - r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; - -#ifdef RLIMIT_AS - - setrlimit(RLIMIT_AS, &r); /* Ignore errors */ - -#else - - /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but - according to reliable sources, RLIMIT_DATA covers anonymous - maps - so we should be getting good protection against OOM bugs. */ - - setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ - -#endif /* ^RLIMIT_AS */ - - - } - - /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered - before the dump is complete. */ - - r.rlim_max = r.rlim_cur = 0; - - setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ - - /* Isolate the process and configure standard descriptors. If out_file is - specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ - - setsid(); - - if (!getenv("AFL_DEBUG_CHILD_OUTPUT")) { - dup2(dev_null_fd, 1); - dup2(dev_null_fd, 2); - } - - if (out_file) { - - dup2(dev_null_fd, 0); - - } else { - - dup2(out_fd, 0); - close(out_fd); - - } - - /* Set up control and status pipes, close the unneeded original fds. */ - - if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed"); - if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed"); - - close(ctl_pipe[0]); - close(ctl_pipe[1]); - close(st_pipe[0]); - close(st_pipe[1]); - - close(out_dir_fd); - close(dev_null_fd); -#ifndef HAVE_ARC4RANDOM - close(dev_urandom_fd); -#endif - close(fileno(plot_file)); - - /* This should improve performance a bit, since it stops the linker from - doing extra work post-fork(). */ - - if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); - - /* Set sane defaults for ASAN if nothing else specified. */ - - setenv("ASAN_OPTIONS", "abort_on_error=1:" - "detect_leaks=0:" - "symbolize=0:" - "allocator_may_return_null=1", 0); - - /* MSAN is tricky, because it doesn't support abort_on_error=1 at this - point. So, we do this in a very hacky way. */ - - setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" - "symbolize=0:" - "abort_on_error=1:" - "allocator_may_return_null=1:" - "msan_track_origins=0", 0); - - execv(target_path, argv); - - /* Use a distinctive bitmap signature to tell the parent about execv() - falling through. */ - - *(u32*)trace_bits = EXEC_FAIL_SIG; - exit(0); - - } - - /* PARENT PROCESS */ - - /* Close the unneeded endpoints. */ - - close(ctl_pipe[0]); - close(st_pipe[1]); - - fsrv_ctl_fd = ctl_pipe[1]; - fsrv_st_fd = st_pipe[0]; - - /* Wait for the fork server to come up, but don't wait too long. */ - - it.it_value.tv_sec = ((exec_tmout * FORK_WAIT_MULT) / 1000); - it.it_value.tv_usec = ((exec_tmout * FORK_WAIT_MULT) % 1000) * 1000; - - setitimer(ITIMER_REAL, &it, NULL); - - rlen = read(fsrv_st_fd, &status, 4); - - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 0; - - setitimer(ITIMER_REAL, &it, NULL); - - /* If we have a four-byte "hello" message from the server, we're all set. - Otherwise, try to figure out what went wrong. */ - - if (rlen == 4) { - OKF("All right - fork server is up."); - return; - } - - if (child_timed_out) - FATAL("Timeout while initializing fork server (adjusting -t may help)"); - - if (waitpid(forksrv_pid, &status, 0) <= 0) - PFATAL("waitpid() failed"); - - if (WIFSIGNALED(status)) { - - if (mem_limit && mem_limit < 500 && uses_asan) { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, before receiving any input\n" - " from the fuzzer! Since it seems to be built with ASAN and you have a\n" - " restrictive memory limit configured, this is expected; please read\n" - " %s/notes_for_asan.txt for help.\n", doc_path); - - } else if (!mem_limit) { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, before receiving any input\n" - " from the fuzzer! There are several probable explanations:\n\n" - - " - The binary is just buggy and explodes entirely on its own. If so, you\n" - " need to fix the underlying problem or find a better replacement.\n\n" - -#ifdef __APPLE__ - - " - On MacOS X, the semantics of fork() syscalls are non-standard and may\n" - " break afl-fuzz performance optimizations when running platform-specific\n" - " targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n" - -#endif /* __APPLE__ */ - - " - Less likely, there is a horrible bug in the fuzzer. If other options\n" - " fail, poke <afl-users@googlegroups.com> for troubleshooting tips.\n"); - - } else { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, before receiving any input\n" - " from the fuzzer! There are several probable explanations:\n\n" - - " - The current memory limit (%s) is too restrictive, causing the\n" - " target to hit an OOM condition in the dynamic linker. Try bumping up\n" - " the limit with the -m setting in the command line. A simple way confirm\n" - " this diagnosis would be:\n\n" - -#ifdef RLIMIT_AS - " ( ulimit -Sv $[%llu << 10]; /path/to/fuzzed_app )\n\n" -#else - " ( ulimit -Sd $[%llu << 10]; /path/to/fuzzed_app )\n\n" -#endif /* ^RLIMIT_AS */ - - " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" - " estimate the required amount of virtual memory for the binary.\n\n" - - " - The binary is just buggy and explodes entirely on its own. If so, you\n" - " need to fix the underlying problem or find a better replacement.\n\n" - -#ifdef __APPLE__ - - " - On MacOS X, the semantics of fork() syscalls are non-standard and may\n" - " break afl-fuzz performance optimizations when running platform-specific\n" - " targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n" - -#endif /* __APPLE__ */ - - " - Less likely, there is a horrible bug in the fuzzer. If other options\n" - " fail, poke <afl-users@googlegroups.com> for troubleshooting tips.\n", - DMS(mem_limit << 20), mem_limit - 1); - - } - - FATAL("Fork server crashed with signal %d", WTERMSIG(status)); - - } - - if (*(u32*)trace_bits == EXEC_FAIL_SIG) - FATAL("Unable to execute target application ('%s')", argv[0]); - - if (mem_limit && mem_limit < 500 && uses_asan) { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated before we could complete a\n" - " handshake with the injected code. Since it seems to be built with ASAN and\n" - " you have a restrictive memory limit configured, this is expected; please\n" - " read %s/notes_for_asan.txt for help.\n", doc_path); - - } else if (!mem_limit) { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated before we could complete a\n" - " handshake with the injected code. Perhaps there is a horrible bug in the\n" - " fuzzer. Poke <afl-users@googlegroups.com> for troubleshooting tips.\n"); - - } else { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated before we could complete a\n" - " handshake with the injected code. There are %s probable explanations:\n\n" - - "%s" - " - The current memory limit (%s) is too restrictive, causing an OOM\n" - " fault in the dynamic linker. This can be fixed with the -m option. A\n" - " simple way to confirm the diagnosis may be:\n\n" - -#ifdef RLIMIT_AS - " ( ulimit -Sv $[%llu << 10]; /path/to/fuzzed_app )\n\n" -#else - " ( ulimit -Sd $[%llu << 10]; /path/to/fuzzed_app )\n\n" -#endif /* ^RLIMIT_AS */ - - " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" - " estimate the required amount of virtual memory for the binary.\n\n" - - " - Less likely, there is a horrible bug in the fuzzer. If other options\n" - " fail, poke <afl-users@googlegroups.com> for troubleshooting tips.\n", - getenv(DEFER_ENV_VAR) ? "three" : "two", - getenv(DEFER_ENV_VAR) ? - " - You are using deferred forkserver, but __AFL_INIT() is never\n" - " reached before the program terminates.\n\n" : "", - DMS(mem_limit << 20), mem_limit - 1); - - } - - FATAL("Fork server handshake failed"); - -} - - /* Execute target application, monitoring for timeouts. Return status information. The called program will update trace_bits[]. */ @@ -2879,7 +2584,8 @@ static void write_with_gap(void* mem, u32 len, u32 skip_at, u32 skip_len) { if (skip_at) ck_write(fd, mem, skip_at, out_file); - if (tail_len) ck_write(fd, mem + skip_at + skip_len, tail_len, out_file); + u8 *memu8 = mem; + if (tail_len) ck_write(fd, memu8 + skip_at + skip_len, tail_len, out_file); if (!out_file) { @@ -3173,23 +2879,13 @@ static void perform_dry_run(char** argv) { " bumping it up with the -m setting in the command line. If in doubt,\n" " try something along the lines of:\n\n" -#ifdef RLIMIT_AS - " ( ulimit -Sv $[%llu << 10]; /path/to/binary [...] <testcase )\n\n" -#else - " ( ulimit -Sd $[%llu << 10]; /path/to/binary [...] <testcase )\n\n" -#endif /* ^RLIMIT_AS */ + MSG_ULIMIT_USAGE " /path/to/binary [...] <testcase )\n\n" " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" " estimate the required amount of virtual memory for the binary. Also,\n" " if you are using ASAN, see %s/notes_for_asan.txt.\n\n" -#ifdef __APPLE__ - - " - On MacOS X, the semantics of fork() syscalls are non-standard and may\n" - " break afl-fuzz performance optimizations when running platform-specific\n" - " binaries. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n" - -#endif /* __APPLE__ */ + MSG_FORK_ON_APPLE " - Least likely, there is a horrible bug in the fuzzer. If other options\n" " fail, poke <afl-users@googlegroups.com> for troubleshooting tips.\n", @@ -3205,18 +2901,14 @@ static void perform_dry_run(char** argv) { " so, please remove it. The fuzzer should be seeded with interesting\n" " inputs - but not ones that cause an outright crash.\n\n" -#ifdef __APPLE__ - - " - On MacOS X, the semantics of fork() syscalls are non-standard and may\n" - " break afl-fuzz performance optimizations when running platform-specific\n" - " binaries. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n" - -#endif /* __APPLE__ */ + MSG_FORK_ON_APPLE " - Least likely, there is a horrible bug in the fuzzer. If other options\n" " fail, poke <afl-users@googlegroups.com> for troubleshooting tips.\n"); } +#undef MSG_ULIMIT_USAGE +#undef MSG_FORK_ON_APPLE FATAL("Test case '%s' results in a crash", fn); @@ -3408,20 +3100,20 @@ static u8* describe_op(u8 hnb) { sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - start_time); if (splicing_with >= 0) - sprintf(ret + strlen(ret), "+%06u", splicing_with); + sprintf(ret + strlen(ret), "+%06d", splicing_with); sprintf(ret + strlen(ret), ",op:%s", stage_short); if (stage_cur_byte >= 0) { - sprintf(ret + strlen(ret), ",pos:%u", stage_cur_byte); + sprintf(ret + strlen(ret), ",pos:%d", stage_cur_byte); if (stage_val_type != STAGE_VAL_NONE) sprintf(ret + strlen(ret), ",val:%s%+d", (stage_val_type == STAGE_VAL_BE) ? "be:" : "", stage_cur_val); - } else sprintf(ret + strlen(ret), ",rep:%u", stage_cur_val); + } else sprintf(ret + strlen(ret), ",rep:%d", stage_cur_val); } @@ -3787,7 +3479,7 @@ static void write_stats_file(double bitmap_cvg, double stability, double eps) { fprintf(f, "start_time : %llu\n" "last_update : %llu\n" - "fuzzer_pid : %u\n" + "fuzzer_pid : %d\n" "cycles_done : %llu\n" "execs_done : %llu\n" "execs_per_sec : %0.02f\n" @@ -4032,21 +3724,21 @@ static void maybe_delete_out_dir(void) { if (f) { - u64 start_time, last_update; + u64 start_time2, last_update; if (fscanf(f, "start_time : %llu\n" - "last_update : %llu\n", &start_time, &last_update) != 2) + "last_update : %llu\n", &start_time2, &last_update) != 2) FATAL("Malformed data in '%s'", fn); fclose(f); /* Let's see how much work is at stake. */ - if (!in_place_resume && last_update - start_time > OUTPUT_GRACE * 60) { + if (!in_place_resume && last_update - start_time2 > OUTPUT_GRACE * 60) { SAYF("\n" cLRD "[-] " cRST "The job output directory already exists and contains the results of more\n" - " than %u minutes worth of fuzzing. To avoid data loss, afl-fuzz will *NOT*\n" + " than %d minutes worth of fuzzing. To avoid data loss, afl-fuzz will *NOT*\n" " automatically delete this data for you.\n\n" " If you wish to start a new session, remove or rename the directory manually,\n" @@ -4150,13 +3842,13 @@ static void maybe_delete_out_dir(void) { #ifndef SIMPLE_FILES - u8* nfn = alloc_printf("%s.%04u-%02u-%02u-%02u:%02u:%02u", fn, + u8* nfn = alloc_printf("%s.%04d-%02d-%02d-%02d:%02d:%02d", fn, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); #else - u8* nfn = alloc_printf("%s_%04u%02u%02u%02u%02u%02u", fn, + u8* nfn = alloc_printf("%s_%04d%02d%02d%02d%02d%02d", fn, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); @@ -4181,13 +3873,13 @@ static void maybe_delete_out_dir(void) { #ifndef SIMPLE_FILES - u8* nfn = alloc_printf("%s.%04u-%02u-%02u-%02u:%02u:%02u", fn, + u8* nfn = alloc_printf("%s.%04d-%02d-%02d-%02d:%02d:%02d", fn, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); #else - u8* nfn = alloc_printf("%s_%04u%02u%02u%02u%02u%02u", fn, + u8* nfn = alloc_printf("%s_%04d%02d%02d%02d%02d%02d", fn, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); @@ -4490,7 +4182,7 @@ static void show_stats(void) { together, but then cram them into a fixed-width field - so we need to put them in a temporary buffer first. */ - sprintf(tmp, "%s%s%d (%0.02f%%)", DI(current_entry), + sprintf(tmp, "%s%s%u (%0.02f%%)", DI(current_entry), queue_cur->favored ? "." : "*", queue_cur->fuzz_level, ((double)current_entry * 100) / queued_paths); @@ -4865,7 +4557,7 @@ static u8 trim_case_python(char** argv, struct queue_entry* q, u8* in_buf) { stage_max = init_trim_py(in_buf, q->len); if (not_on_tty && debug) - SAYF("[Python Trimming] START: Max %d iterations, %d bytes", stage_max, q->len); + SAYF("[Python Trimming] START: Max %d iterations, %u bytes", stage_max, q->len); while(stage_cur < stage_max) { sprintf(tmp, "ptrim %s", DI(trim_exec)); @@ -4908,7 +4600,7 @@ static u8 trim_case_python(char** argv, struct queue_entry* q, u8* in_buf) { stage_cur = post_trim_py(1); if (not_on_tty && debug) - SAYF("[Python Trimming] SUCCESS: %d/%d iterations (now at %d bytes)", stage_cur, stage_max, q->len); + SAYF("[Python Trimming] SUCCESS: %d/%d iterations (now at %u bytes)", stage_cur, stage_max, q->len); } else { /* Tell the Python module that the trimming was unsuccessful */ stage_cur = post_trim_py(0); @@ -4922,7 +4614,7 @@ static u8 trim_case_python(char** argv, struct queue_entry* q, u8* in_buf) { } if (not_on_tty && debug) - SAYF("[Python Trimming] DONE: %d bytes -> %d bytes", orig_len, q->len); + SAYF("[Python Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len); /* If we have made changes to in_buf, we also need to update the on-disk version of the test case. */ @@ -5194,6 +4886,12 @@ static u32 calculate_score(struct queue_entry* q) { global average. Multiplier ranges from 0.1x to 3x. Fast inputs are less expensive to fuzz, so we're giving them more air time. */ + // TODO BUG FIXME: is this really a good idea? + // This sounds like looking for lost keys under a street light just because + // the light is better there. + // Longer execution time means longer work on the input, the deeper in + // coverage, the better the fuzzing, right? -mh + if (q->exec_us * 0.1 > avg_exec_us) perf_score = 10; else if (q->exec_us * 0.25 > avg_exec_us) perf_score = 25; else if (q->exec_us * 0.5 > avg_exec_us) perf_score = 50; @@ -5217,15 +4915,11 @@ static u32 calculate_score(struct queue_entry* q) { for a bit longer until they catch up with the rest. */ if (q->handicap >= 4) { - perf_score *= 4; q->handicap -= 4; - } else if (q->handicap) { - perf_score *= 2; --q->handicap; - } /* Final adjustment based on input depth, under the assumption that fuzzing @@ -5571,7 +5265,7 @@ static u8 fuzz_one_original(char** argv) { orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (orig_in == MAP_FAILED) PFATAL("Unable to mmap '%s' with len %u", queue_cur->fname, len); + if (orig_in == MAP_FAILED) PFATAL("Unable to mmap '%s' with len %d", queue_cur->fname, len); close(fd); @@ -5629,7 +5323,7 @@ static u8 fuzz_one_original(char** argv) { queue_cur->trim_done = 1; - if (len != queue_cur->len) len = queue_cur->len; + len = queue_cur->len; } @@ -7463,7 +7157,7 @@ static u8 pilot_fuzzing(char** argv) { queue_cur->trim_done = 1; - if (len != queue_cur->len) len = queue_cur->len; + len = queue_cur->len; } @@ -8579,7 +8273,9 @@ static u8 pilot_fuzzing(char** argv) { { +#ifndef IGNORE_FINDS havoc_stage_puppet: +#endif stage_cur_byte = -1; @@ -9266,7 +8962,7 @@ static u8 core_fuzzing(char** argv) { queue_cur->trim_done = 1; - if (len != queue_cur->len) len = queue_cur->len; + len = queue_cur->len; } @@ -10345,7 +10041,9 @@ static u8 core_fuzzing(char** argv) { } } { +#ifndef IGNORE_FINDS havoc_stage_puppet: +#endif stage_cur_byte = -1; @@ -11066,24 +10764,6 @@ static void handle_skipreq(int sig) { } -/* Handle timeout (SIGALRM). */ - -static void handle_timeout(int sig) { - - if (child_pid > 0) { - - child_timed_out = 1; - kill(child_pid, SIGKILL); - - } else if (child_pid == -1 && forksrv_pid > 0) { - - child_timed_out = 1; - kill(forksrv_pid, SIGKILL); - - } - -} - /* Do a PATH search and find target binary to see that it exists and isn't a shell script - a common and painful mistake. We also check for @@ -11332,6 +11012,13 @@ static void check_term_size(void) { static void usage(u8* argv0) { +#ifdef USE_PYTHON +#define PHYTON_SUPPORT \ + "Compiled with Python 2.7 module support, see docs/python_mutators.txt\n" +#else +#define PHYTON_SUPPORT "" +#endif + SAYF("\n%s [ options ] -- /path/to/fuzzed_app [ ... ]\n\n" "Required parameters:\n" @@ -11343,8 +11030,8 @@ static void usage(u8* argv0) { " <explore (default), fast, coe, lin, quad, or exploit>\n" " see docs/power_schedules.txt\n" " -f file - location read by the fuzzed program (stdin)\n" - " -t msec - timeout for each run (auto-scaled, 50-%u ms)\n" - " -m megs - memory limit for child process (%u MB)\n" + " -t msec - timeout for each run (auto-scaled, 50-%d ms)\n" + " -m megs - memory limit for child process (%d MB)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use Unicorn-based instrumentation (Unicorn mode)\n\n" " -L minutes - use MOpt(imize) mode and set the limit time for entering the\n" @@ -11368,14 +11055,14 @@ static void usage(u8* argv0) { " -C - crash exploration mode (the peruvian rabbit thing)\n" " -e ext - File extension for the temporarily generated test case\n\n" -#ifdef USE_PYTHON - "Compiled with Python 2.7 module support, see docs/python_mutators.txt\n" -#endif + PHYTON_SUPPORT + "For additional tips, please consult %s/README\n\n", argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path); exit(1); +#undef PHYTON_SUPPORT } @@ -11691,8 +11378,6 @@ static void check_cpu_governor(void) { static void get_core_count(void) { - u32 cur_runnable = 0; - #if defined(__APPLE__) || defined(__FreeBSD__) || defined (__OpenBSD__) size_t s = sizeof(cpu_core_count); @@ -11736,6 +11421,8 @@ static void get_core_count(void) { if (cpu_core_count > 0) { + u32 cur_runnable = 0; + cur_runnable = (u32)get_runnable_processes(); #if defined(__APPLE__) || defined(__FreeBSD__) || defined (__OpenBSD__) @@ -11746,7 +11433,7 @@ static void get_core_count(void) { #endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ - OKF("You have %u CPU core%s and %u runnable tasks (utilization: %0.0f%%).", + OKF("You have %d CPU core%s and %u runnable tasks (utilization: %0.0f%%).", cpu_core_count, cpu_core_count > 1 ? "s" : "", cur_runnable, cur_runnable * 100.0 / cpu_core_count); @@ -11995,8 +11682,8 @@ static void save_cmdline(u32 argc, char** argv) { } int stricmp(char const *a, char const *b) { - int d; for (;; ++a, ++b) { + int d; d = tolower(*a) - tolower(*b); if (d != 0 || !*a) return d; @@ -12461,15 +12148,13 @@ int main(int argc, char** argv) { setup_dirs_fds(); - u8 with_python_support = 0; #ifdef USE_PYTHON if (init_py()) FATAL("Failed to initialize Python module"); - with_python_support = 1; -#endif - - if (getenv("AFL_PYTHON_MODULE") && !with_python_support) +#else + if (getenv("AFL_PYTHON_MODULE")) FATAL("Your AFL binary was built without Python support"); +#endif setup_cmdline_file(argv + optind); diff --git a/afl-gcc.c b/src/afl-gcc.c index f6ededeb..f6ededeb 100644 --- a/afl-gcc.c +++ b/src/afl-gcc.c diff --git a/afl-gotcpu.c b/src/afl-gotcpu.c index 8c04b205..fa629eb7 100644 --- a/afl-gotcpu.c +++ b/src/afl-gotcpu.c @@ -26,7 +26,9 @@ */ #define AFL_MAIN -#define _GNU_SOURCE +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif #ifdef __ANDROID__ #include "android-ashmem.h" diff --git a/sharedmem.c b/src/afl-sharedmem.c index ce3b76e6..ce3b76e6 100644 --- a/sharedmem.c +++ b/src/afl-sharedmem.c diff --git a/afl-showmap.c b/src/afl-showmap.c index a490bca6..ee00bf22 100644 --- a/afl-showmap.c +++ b/src/afl-showmap.c @@ -32,7 +32,7 @@ #include "alloc-inl.h" #include "hash.h" #include "sharedmem.h" -#include "afl-common.h" +#include "common.h" #include <stdio.h> #include <unistd.h> @@ -412,7 +412,7 @@ static void usage(u8* argv0) { "Execution control settings:\n\n" " -t msec - timeout for each run (none)\n" - " -m megs - memory limit for child process (%u MB)\n" + " -m megs - memory limit for child process (%d MB)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use Unicorn-based instrumentation (Unicorn mode)\n" " (Not necessary, here for consistency with other afl-* tools)\n\n" diff --git a/afl-tmin.c b/src/afl-tmin.c index a36acd10..529720ca 100644 --- a/afl-tmin.c +++ b/src/afl-tmin.c @@ -24,13 +24,15 @@ #ifdef __ANDROID__ #include "android-ashmem.h" #endif + #include "config.h" #include "types.h" #include "debug.h" #include "alloc-inl.h" #include "hash.h" +#include "forkserver.h" #include "sharedmem.h" -#include "afl-common.h" +#include "common.h" #include <stdio.h> #include <unistd.h> @@ -49,22 +51,22 @@ #include <sys/types.h> #include <sys/resource.h> -static s32 forksrv_pid, /* PID of the fork server */ - child_pid; /* PID of the tested program */ +s32 forksrv_pid, /* PID of the fork server */ + child_pid; /* PID of the tested program */ -static s32 fsrv_ctl_fd, /* Fork server control pipe (write) */ - fsrv_st_fd; /* Fork server status pipe (read) */ +s32 fsrv_ctl_fd, /* Fork server control pipe (write) */ + fsrv_st_fd; /* Fork server status pipe (read) */ u8 *trace_bits; /* SHM with instrumentation bitmap */ static u8 *mask_bitmap; /* Mask for trace bits (-B) */ -static u8 *in_file, /* Minimizer input test case */ - *out_file, /* Minimizer output file */ - *prog_in, /* Targeted program input file */ + u8 *in_file, /* Minimizer input test case */ + *output_file, /* Minimizer output file */ + *out_file, /* Targeted program input file */ *target_path, /* Path to target binary */ *doc_path; /* Path to docs */ -static s32 prog_in_fd; /* Persistent fd for prog_in */ + s32 out_fd; /* Persistent fd for out_file */ static u8* in_data; /* Input data for trimming */ @@ -73,12 +75,12 @@ static u32 in_len, /* Input data length */ total_execs, /* Total number of execs */ missed_hangs, /* Misses due to hangs */ missed_crashes, /* Misses due to crashes */ - missed_paths, /* Misses due to exec path diffs */ - exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */ + missed_paths; /* Misses due to exec path diffs */ + u32 exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */ -static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ + u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ -static s32 dev_null_fd = -1; /* FD to /dev/null */ + s32 dev_null_fd = -1; /* FD to /dev/null */ static u8 crash_mode, /* Crash-centric mode? */ exit_crash, /* Treat non-zero exit as crash? */ @@ -87,8 +89,19 @@ static u8 crash_mode, /* Crash-centric mode? */ use_stdin = 1; /* Use stdin for program input? */ static volatile u8 - stop_soon, /* Ctrl-C pressed? */ - child_timed_out; /* Child timed out? */ + stop_soon; /* Ctrl-C pressed? */ + +/* + * forkserver section + */ + +/* we only need this to use afl-forkserver */ +FILE *plot_file; +u8 uses_asan; +s32 out_fd = -1, out_dir_fd = -1, dev_urandom_fd = -1; + +/* we import this as we need this information */ +extern u8 child_timed_out; /* Classify tuple counts. This is a slow & naive version, but good enough here. */ @@ -166,7 +179,7 @@ static inline u8 anything_set(void) { /* Get rid of temp files (atexit handler). */ static void at_exit_handler(void) { - if (prog_in) unlink(prog_in); /* Ignore errors */ + if (out_file) unlink(out_file); /* Ignore errors */ } /* Read initial file. */ @@ -217,24 +230,24 @@ static s32 write_to_file(u8* path, u8* mem, u32 len) { } /* Write modified data to file for testing. If use_stdin is clear, the old file - is unlinked and a new one is created. Otherwise, prog_in_fd is rewound and + is unlinked and a new one is created. Otherwise, out_fd is rewound and truncated. */ static void write_to_testcase(void* mem, u32 len) { - s32 fd = prog_in_fd; + s32 fd = out_fd; if (!use_stdin) { - unlink(prog_in); /* Ignore errors. */ + unlink(out_file); /* Ignore errors. */ - fd = open(prog_in, O_WRONLY | O_CREAT | O_EXCL, 0600); + fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) PFATAL("Unable to create '%s'", prog_in); + if (fd < 0) PFATAL("Unable to create '%s'", out_file); } else lseek(fd, 0, SEEK_SET); - ck_write(fd, mem, len, prog_in); + ck_write(fd, mem, len, out_file); if (use_stdin) { @@ -248,7 +261,7 @@ static void write_to_testcase(void* mem, u32 len) { /* Handle timeout signal. */ - +/* static void handle_timeout(int sig) { if (child_pid > 0) { @@ -264,8 +277,10 @@ static void handle_timeout(int sig) { } } +*/ /* start the app and it's forkserver */ +/* static void init_forkserver(char **argv) { static struct itimerval it; int st_pipe[2], ctl_pipe[2]; @@ -283,7 +298,7 @@ static void init_forkserver(char **argv) { struct rlimit r; - if (dup2(use_stdin ? prog_in_fd : dev_null_fd, 0) < 0 || + if (dup2(use_stdin ? out_fd : dev_null_fd, 0) < 0 || dup2(dev_null_fd, 1) < 0 || dup2(dev_null_fd, 2) < 0) { @@ -293,7 +308,7 @@ static void init_forkserver(char **argv) { } close(dev_null_fd); - close(prog_in_fd); + close(out_fd); setsid(); @@ -303,20 +318,20 @@ static void init_forkserver(char **argv) { #ifdef RLIMIT_AS - setrlimit(RLIMIT_AS, &r); /* Ignore errors */ + setrlimit(RLIMIT_AS, &r); // Ignore errors #else - setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ + setrlimit(RLIMIT_DATA, &r); // Ignore errors -#endif /* ^RLIMIT_AS */ +#endif // ^RLIMIT_AS } r.rlim_max = r.rlim_cur = 0; - setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + setrlimit(RLIMIT_CORE, &r); // Ignore errors - /* Set up control and status pipes, close the unneeded original fds. */ + // Set up control and status pipes, close the unneeded original fds. if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed"); if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed"); @@ -333,7 +348,7 @@ static void init_forkserver(char **argv) { } - /* Close the unneeded endpoints. */ + // Close the unneeded endpoints. close(ctl_pipe[0]); close(st_pipe[1]); @@ -341,7 +356,7 @@ static void init_forkserver(char **argv) { fsrv_ctl_fd = ctl_pipe[1]; fsrv_st_fd = st_pipe[0]; - /* Configure timeout, wait for child, cancel timeout. */ + // Configure timeout, wait for child, cancel timeout. if (exec_tmout) { @@ -359,8 +374,8 @@ static void init_forkserver(char **argv) { it.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &it, NULL); - /* If we have a four-byte "hello" message from the server, we're all set. - Otherwise, try to figure out what went wrong. */ + // If we have a four-byte "hello" message from the server, we're all set. + // Otherwise, try to figure out what went wrong. if (rlen == 4) { ACTF("All right - fork server is up."); @@ -383,7 +398,7 @@ static void init_forkserver(char **argv) { SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST, WTERMSIG(status)); } - +*/ /* Execute target application. Returns 0 if the changes are a dud, or 1 if they should be kept. */ @@ -425,11 +440,8 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) { /* Configure timeout, wait for child, cancel timeout. */ if (exec_tmout) { - - child_timed_out = 0; - it.it_value.tv_sec = (exec_tmout / 1000); - it.it_value.tv_usec = (exec_tmout % 1000) * 1000; - + it.it_value.tv_sec = (exec_tmout / 1000); + it.it_value.tv_usec = (exec_tmout % 1000) * 1000; } setitimer(ITIMER_REAL, &it, NULL); @@ -461,7 +473,7 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) { if (stop_soon) { SAYF(cRST cLRD "\n+++ Minimization aborted by user +++\n" cRST); - close(write_to_file(out_file, in_data, in_len)); + close(write_to_file(output_file, in_data, in_len)); exit(1); } @@ -554,7 +566,6 @@ static void minimize(char** argv) { while (set_pos < in_len) { - u8 res; u32 use_len = MIN(set_len, in_len - set_pos); for (i = 0; i < use_len; i++) @@ -565,12 +576,13 @@ static void minimize(char** argv) { memcpy(tmp_buf, in_data, in_len); memset(tmp_buf + set_pos, '0', use_len); + u8 res; res = run_target(argv, tmp_buf, in_len, 0); if (res) { memset(in_data + set_pos, '0', use_len); - changed_any = 1; +/* changed_any = 1; value is not used */ alpha_del0 += use_len; } @@ -790,7 +802,7 @@ static void set_up_environment(void) { dev_null_fd = open("/dev/null", O_RDWR); if (dev_null_fd < 0) PFATAL("Unable to open /dev/null"); - if (!prog_in) { + if (!out_file) { u8* use_dir = "."; @@ -801,15 +813,15 @@ static void set_up_environment(void) { } - prog_in = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, getpid()); + out_file = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, getpid()); } - unlink(prog_in); + unlink(out_file); - prog_in_fd = open(prog_in, O_RDWR | O_CREAT | O_EXCL, 0600); + out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600); - if (prog_in_fd < 0) PFATAL("Unable to create '%s'", prog_in); + if (out_fd < 0) PFATAL("Unable to create '%s'", out_file); /* Set sane defaults... */ @@ -899,8 +911,8 @@ static void usage(u8* argv0) { "Execution control settings:\n\n" " -f file - input file read by the tested program (stdin)\n" - " -t msec - timeout for each run (%u ms)\n" - " -m megs - memory limit for child process (%u MB)\n" + " -t msec - timeout for each run (%d ms)\n" + " -m megs - memory limit for child process (%d MB)\n" " -Q - use binary-only instrumentation (QEMU mode)\n" " -U - use Unicorn-based instrumentation (Unicorn mode)\n\n" " (Not necessary, here for consistency with other afl-* tools)\n\n" @@ -1070,15 +1082,15 @@ int main(int argc, char** argv) { case 'o': - if (out_file) FATAL("Multiple -o options not supported"); - out_file = optarg; + if (output_file) FATAL("Multiple -o options not supported"); + output_file = optarg; break; case 'f': - if (prog_in) FATAL("Multiple -f options not supported"); + if (out_file) FATAL("Multiple -f options not supported"); use_stdin = 0; - prog_in = optarg; + out_file = optarg; break; case 'e': @@ -1184,7 +1196,7 @@ int main(int argc, char** argv) { } - if (optind == argc || !in_file || !out_file) usage(argv[0]); + if (optind == argc || !in_file || !output_file) usage(argv[0]); setup_shm(0); atexit(at_exit_handler); @@ -1193,7 +1205,7 @@ int main(int argc, char** argv) { set_up_environment(); find_binary(argv[optind]); - detect_file_args(argv + optind, prog_in); + detect_file_args(argv + optind, out_file); if (qemu_mode) use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind); @@ -1232,12 +1244,12 @@ int main(int argc, char** argv) { minimize(use_argv); - ACTF("Writing output to '%s'...", out_file); + ACTF("Writing output to '%s'...", output_file); - unlink(prog_in); - prog_in = NULL; + unlink(out_file); + out_file = NULL; - close(write_to_file(out_file, in_data, in_len)); + close(write_to_file(output_file, in_data, in_len)); OKF("We're done here. Have a nice day!\n"); diff --git a/types.h b/types.h index 7606d4ed..67149a67 100644..120000 --- a/types.h +++ b/types.h @@ -1,91 +1 @@ -/* - american fuzzy lop - type definitions and minor macros - ------------------------------------------------------ - - Written and maintained by Michal Zalewski <lcamtuf@google.com> - - Copyright 2013, 2014, 2015 Google Inc. 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> - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; - -/* - - Ugh. There is an unintended compiler / glibc #include glitch caused by - combining the u64 type an %llu in format strings, necessitating a workaround. - - In essence, the compiler is always looking for 'unsigned long long' for %llu. - On 32-bit systems, the u64 type (aliased to uint64_t) is expanded to - 'unsigned long long' in <bits/types.h>, so everything checks out. - - But on 64-bit systems, it is #ifdef'ed in the same file as 'unsigned long'. - Now, it only happens in circumstances where the type happens to have the - expected bit width, *but* the compiler does not know that... and complains - about 'unsigned long' being unsafe to pass to %llu. - - */ - -#ifdef __x86_64__ -typedef unsigned long long u64; -#else -typedef uint64_t u64; -#endif /* ^__x86_64__ */ - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -#ifndef MIN -# define MIN(_a,_b) ((_a) > (_b) ? (_b) : (_a)) -# define MAX(_a,_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)); \ - }) - -#ifdef AFL_LLVM_PASS -# define AFL_R(x) (random() % (x)) -#else -# define R(x) (random() % (x)) -#endif /* ^AFL_LLVM_PASS */ - -#define STRINGIFY_INTERNAL(x) #x -#define STRINGIFY(x) STRINGIFY_INTERNAL(x) - -#define MEM_BARRIER() \ - __asm__ volatile("" ::: "memory") - -#if __GNUC__ < 6 - #define likely(_x) (_x) - #define unlikely(_x) (_x) -#else - #define likely(_x) __builtin_expect(!!(_x), 1) - #define unlikely(_x) __builtin_expect(!!(_x), 0) -#endif - -#endif /* ! _HAVE_TYPES_H */ +include/types.h \ No newline at end of file |