From 185f4436598aacb3f25736ce6eb53309d1d9472f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 31 Jul 2020 17:53:01 +0200 Subject: add LTO AFL_LLVM_DOCUMENT_IDS feature --- docs/env_variables.md | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index 87344331..4c0d2db7 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -121,18 +121,16 @@ Then there are a few specific features that are only available in llvm_mode: built if LLVM 11 or newer is used. - AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation. - (recommended) - - - AFL_LLVM_LTO_AUTODICTIONARY will generate a dictionary in the target - binary based on string compare and memory compare functions. - afl-fuzz will automatically get these transmitted when starting to - fuzz. + (not recommended!) None of the following options are necessary to be used and are rather for manual use (which only ever the author of this LTO implementation will use). These are used if several seperated instrumentation are performed which are then later combined. + - AFL_LLVM_DOCUMENT_IDS=file will document to a file which edge ID was given + to which function. This helps to identify functions with variable bytes + or which functions were touched by an input. - AFL_LLVM_MAP_ADDR sets the fixed map address to a different address than the default 0x10000. A value of 0 or empty sets the map address to be dynamic (the original afl way, which is slower) @@ -254,15 +252,6 @@ checks or alter some of the more exotic semantics of the tool: useful if you can't change the defaults (e.g., no root access to the system) and are OK with some performance loss. - - Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to - fork + execve() call for every tested input. This is useful mostly when - working with unruly libraries that create threads or do other crazy - things when initializing (before the instrumentation has a chance to run). - - Note that this setting inhibits some of the user-friendly diagnostics - normally done when starting up the forkserver and causes a pretty - significant performance drop. - - AFL_EXIT_WHEN_DONE causes afl-fuzz to terminate when all existing paths have been fuzzed and there were no new finds for a while. This would be normally indicated by the cycle counter in the UI turning green. May be @@ -338,6 +327,13 @@ checks or alter some of the more exotic semantics of the tool: - In QEMU mode (-Q), AFL_PATH will be searched for afl-qemu-trace. + - Setting AFL_CYCLE_SCHEDULES will switch to a different schedule everytime + a cycle is finished. + + - Setting AFL_EXPAND_HAVOC_NOW will start in the extended havoc mode that + includes costly mutations. afl-fuzz automatically enables this mode when + deemed useful otherwise. + - Setting AFL_PRELOAD causes AFL to set LD_PRELOAD for the target binary without disrupting the afl-fuzz process itself. This is useful, among other things, for bootstrapping libdislocator.so. @@ -365,6 +361,15 @@ checks or alter some of the more exotic semantics of the tool: for an existing out folder, even if a different `-i` was provided. Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir. + - Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to + fork + execve() call for every tested input. This is useful mostly when + working with unruly libraries that create threads or do other crazy + things when initializing (before the instrumentation has a chance to run). + + Note that this setting inhibits some of the user-friendly diagnostics + normally done when starting up the forkserver and causes a pretty + significant performance drop. + - Outdated environment variables that are that not supported anymore: AFL_DEFER_FORKSRV AFL_PERSISTENT -- cgit 1.4.1 From 9439ba1dac174741c7838c17de202b0dc68c6a88 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 1 Aug 2020 16:32:01 +0200 Subject: document env var --- docs/env_variables.md | 3 +++ 1 file changed, 3 insertions(+) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index 4c0d2db7..811c5658 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -262,6 +262,9 @@ checks or alter some of the more exotic semantics of the tool: the target. This must be equal or larger than the size the target was compiled with. + - Setting AFL_DISABLE_TRIM tells afl-fuzz to no trim test cases. This is + usually a bad idea! + - Setting AFL_NO_AFFINITY disables attempts to bind to a specific CPU core on Linux systems. This slows things down, but lets you run more instances of afl-fuzz than would be prudent (if you really want to). -- cgit 1.4.1 From 6d364dd2cb0ac31797b52e590b57bf9c10cc2302 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 5 Aug 2020 01:13:51 +0200 Subject: add sancov-like allow/denylist instrument feature --- README.md | 16 +- TODO.md | 1 - docs/Changelog.md | 4 + docs/FAQ.md | 2 +- docs/env_variables.md | 11 +- docs/perf_tips.md | 2 +- gcc_plugin/GNUmakefile | 2 +- gcc_plugin/Makefile | 2 +- include/envs.h | 3 + llvm_mode/README.instrument_file.md | 81 ----- llvm_mode/README.instrument_list.md | 86 +++++ llvm_mode/README.lto.md | 5 +- llvm_mode/README.md | 2 +- llvm_mode/afl-clang-fast.c | 32 +- llvm_mode/afl-llvm-common.cc | 485 +++++++++++++++++++++++----- llvm_mode/afl-llvm-lto-instrumentlist.so.cc | 156 +-------- 16 files changed, 567 insertions(+), 323 deletions(-) delete mode 100644 llvm_mode/README.instrument_file.md create mode 100644 llvm_mode/README.instrument_list.md (limited to 'docs/env_variables.md') diff --git a/README.md b/README.md index bd2784ae..2e24a534 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,7 @@ anything below 9 is not recommended. +--------------------------------+ | if you want to instrument only | -> use afl-gcc-fast and afl-gcc-fast++ | parts of the target | see [gcc_plugin/README.md](gcc_plugin/README.md) and - +--------------------------------+ [gcc_plugin/README.instrument_file.md](gcc_plugin/README.instrument_file.md) + +--------------------------------+ [gcc_plugin/README.instrument_list.md](gcc_plugin/README.instrument_list.md) | | if not, or if you do not have a gcc with plugin support | @@ -290,12 +290,18 @@ selectively only instrument parts of the target that you are interested in: create a file with all the filenames of the source code that should be instrumented. For afl-clang-lto and afl-gcc-fast - or afl-clang-fast if either the clang - version is < 7 or the CLASSIC instrumentation is used - just put one - filename per line, no directory information necessary, and set - `export AFL_LLVM_INSTRUMENT_FILE=yourfile.txt` - see [llvm_mode/README.instrument_file.md](llvm_mode/README.instrument_file.md) + version is below 7 or the CLASSIC instrumentation is used - just put one + filename or function per line (no directory information necessary for + filenames9, and either set `export AFL_LLVM_ALLOWLIST=allowlist.txt` **or** + `export AFL_LLVM_DENYLIST=denylist.txt` - depending on if you want per + default to instrument unless noted (DENYLIST) or not perform instrumentation + unless requested (ALLOWLIST). + **NOTE:** In optimization functions might be inlined and then not match! + see [llvm_mode/README.instrument_list.md](llvm_mode/README.instrument_list.md) For afl-clang-fast > 6.0 or if PCGUARD instrumentation is used then use the llvm sancov allow-list feature: [http://clang.llvm.org/docs/SanitizerCoverage.html](http://clang.llvm.org/docs/SanitizerCoverage.html) + The llvm sancov format works with the allowlist/denylist feature of afl++ + however afl++ is more flexible in the format. There are many more options and modes available however these are most of the time less effective. See: diff --git a/TODO.md b/TODO.md index 999cb9d3..e81b82a3 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,6 @@ ## Roadmap 2.67+ - - expand on AFL_LLVM_INSTRUMENT_FILE to also support sancov allowlist format - AFL_MAP_SIZE for qemu_mode and unicorn_mode - CPU affinity for many cores? There seems to be an issue > 96 cores diff --git a/docs/Changelog.md b/docs/Changelog.md index ae7377f2..f98f8b9b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -22,6 +22,10 @@ sending a mail to . - fixed a bug in redqueen for strings - llvm_mode: - now supports llvm 12! + - support for AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST (previous + AFL_LLVM_WHITELIST and AFL_LLVM_INSTRUMENT_FILE are deprecated and + are matched to AFL_LLVM_ALLOWLIST). The format is compatible to llvm + sancov, and also supports function matching! - fixes for laf-intel float splitting (thanks to mark-griffin for reporting) - LTO: autodictionary mode is a default diff --git a/docs/FAQ.md b/docs/FAQ.md index c15cd484..33ce49e6 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -117,7 +117,7 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation! Identify which source code files contain the functions that you need to remove from instrumentation. - Simply follow this document on how to do this: [llvm_mode/README.instrument_file.md](llvm_mode/README.instrument_file.md) + Simply follow this document on how to do this: [llvm_mode/README.instrument_list.md](llvm_mode/README.instrument_list.md) If PCGUARD is used, then you need to follow this guide (needs llvm 12+!): [http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation](http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation) diff --git a/docs/env_variables.md b/docs/env_variables.md index 811c5658..f0ae0b6c 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -202,14 +202,15 @@ Then there are a few specific features that are only available in llvm_mode: See llvm_mode/README.laf-intel.md for more information. -### INSTRUMENT_FILE +### INSTRUMENT LIST (selectively instrument files and functions) This feature allows selectively instrumentation of the source - - Setting AFL_LLVM_INSTRUMENT_FILE with a filename will only instrument those - files that match the names listed in this file. + - Setting AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST with a filenames and/or + function will only instrument (or skip) those files that match the names + listed in the specified file. - See llvm_mode/README.instrument_file.md for more information. + See llvm_mode/README.instrument_list.md for more information. ### NOT_ZERO @@ -241,7 +242,7 @@ Then there are a few specific features that are only available in the gcc_plugin - Setting AFL_GCC_INSTRUMENT_FILE with a filename will only instrument those files that match the names listed in this file (one filename per line). - See gcc_plugin/README.instrument_file.md for more information. + See gcc_plugin/README.instrument_list.md for more information. ## 3) Settings for afl-fuzz diff --git a/docs/perf_tips.md b/docs/perf_tips.md index 7a690b77..731dc238 100644 --- a/docs/perf_tips.md +++ b/docs/perf_tips.md @@ -67,7 +67,7 @@ to get to the important parts in the code. If you are only interested in specific parts of the code being fuzzed, you can instrument_files the files that are actually relevant. This improves the speed and -accuracy of afl. See llvm_mode/README.instrument_file.md +accuracy of afl. See llvm_mode/README.instrument_list.md Also use the InsTrim mode on larger binaries, this improves performance and coverage a lot. diff --git a/gcc_plugin/GNUmakefile b/gcc_plugin/GNUmakefile index 4a4f0dcd..f10a6c1d 100644 --- a/gcc_plugin/GNUmakefile +++ b/gcc_plugin/GNUmakefile @@ -163,7 +163,7 @@ install: all install -m 755 ../afl-gcc-fast $${DESTDIR}$(BIN_PATH) install -m 755 ../afl-gcc-pass.so ../afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH) install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md - install -m 644 -T README.instrument_file.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md + install -m 644 -T README.instrument_list.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md clean: rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2 diff --git a/gcc_plugin/Makefile b/gcc_plugin/Makefile index f720112f..c088b61c 100644 --- a/gcc_plugin/Makefile +++ b/gcc_plugin/Makefile @@ -152,7 +152,7 @@ install: all install -m 755 ../afl-gcc-fast $${DESTDIR}$(BIN_PATH) install -m 755 ../afl-gcc-pass.so ../afl-gcc-rt.o $${DESTDIR}$(HELPER_PATH) install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md - install -m 644 -T README.instrument_file.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md + install -m 644 -T README.instrument_list.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.instrument_file.md clean: rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1 .test2 diff --git a/include/envs.h b/include/envs.h index 7153ed47..96ae91ba 100644 --- a/include/envs.h +++ b/include/envs.h @@ -62,6 +62,9 @@ static char *afl_environment_variables[] = { "AFL_REAL_LD", "AFL_LD_PRELOAD", "AFL_LD_VERBOSE", + "AFL_LLVM_ALLOWLIST", + "AFL_LLVM_DENYLIST", + "AFL_LLVM_BLOCKLIST", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LLVM_CTX", diff --git a/llvm_mode/README.instrument_file.md b/llvm_mode/README.instrument_file.md deleted file mode 100644 index 46e45ba2..00000000 --- a/llvm_mode/README.instrument_file.md +++ /dev/null @@ -1,81 +0,0 @@ -# Using afl++ with partial instrumentation - - This file describes how you can selectively instrument only the source files - that are interesting to you using the LLVM instrumentation provided by - afl++ - - Originally developed by Christian Holler (:decoder) . - -## 1) Description and purpose - -When building and testing complex programs where only a part of the program is -the fuzzing target, it often helps to only instrument the necessary parts of -the program, leaving the rest uninstrumented. This helps to focus the fuzzer -on the important parts of the program, avoiding undesired noise and -disturbance by uninteresting code being exercised. - -For this purpose, I have added a "partial instrumentation" support to the LLVM -mode of AFLFuzz that allows you to specify on a source file level which files -should be compiled with or without instrumentation. - -Note: When using PCGUARD mode - and have llvm 12+ - you can use this instead: -https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation - -## 2) Building the LLVM module - -The new code is part of the existing afl++ LLVM module in the llvm_mode/ -subdirectory. There is nothing specifically to do :) - - -## 3) How to use the partial instrumentation mode - -In order to build with partial instrumentation, you need to build with -afl-clang-fast and afl-clang-fast++ respectively. The only required change is -that you need to set the environment variable AFL_LLVM_INSTRUMENT_FILE when calling -the compiler. - -The environment variable must point to a file containing all the filenames -that should be instrumented. For matching, the filename that is being compiled -must end in the filename entry contained in this the instrument file list (to avoid breaking -the matching when absolute paths are used during compilation). - -For example if your source tree looks like this: - -``` -project/ -project/feature_a/a1.cpp -project/feature_a/a2.cpp -project/feature_b/b1.cpp -project/feature_b/b2.cpp -``` - -and you only want to test feature_a, then create a the instrument file list file containing: - -``` -feature_a/a1.cpp -feature_a/a2.cpp -``` - -However if the instrument file list file contains only this, it works as well: - -``` -a1.cpp -a2.cpp -``` - -but it might lead to files being unwantedly instrumented if the same filename -exists somewhere else in the project directories. - -The created the instrument file list file is then set to AFL_LLVM_INSTRUMENT_FILE when you compile -your program. For each file that didn't match the the instrument file list, the compiler will -issue a warning at the end stating that no blocks were instrumented. If you -didn't intend to instrument that file, then you can safely ignore that warning. - -For old LLVM versions this feature might require to be compiled with debug -information (-g), however at least from llvm version 6.0 onwards this is not -required anymore (and might hurt performance and crash detection, so better not -use -g). - -## 4) UNIX-style filename pattern matching -You can add UNIX-style pattern matching in the the instrument file list entries. See `man -fnmatch` for the syntax. We do not set any of the `fnmatch` flags. diff --git a/llvm_mode/README.instrument_list.md b/llvm_mode/README.instrument_list.md new file mode 100644 index 00000000..b0e0cc1e --- /dev/null +++ b/llvm_mode/README.instrument_list.md @@ -0,0 +1,86 @@ +# Using afl++ with partial instrumentation + + This file describes how you can selectively instrument only the source files + or functions that are interesting to you using the LLVM instrumentation + provided by afl++ + +## 1) Description and purpose + +When building and testing complex programs where only a part of the program is +the fuzzing target, it often helps to only instrument the necessary parts of +the program, leaving the rest uninstrumented. This helps to focus the fuzzer +on the important parts of the program, avoiding undesired noise and +disturbance by uninteresting code being exercised. + +For this purpose, a "partial instrumentation" support en par with llvm sancov +is provided by afl++ that allows you to specify on a source file and function +level which should be compiled with or without instrumentation. + +Note: When using PCGUARD mode - and have llvm 12+ - you can use this instead: +https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation + +the llvm sancov list format is fully supported by afl++, however afl++ has +more flexbility. + +## 2) Building the LLVM module + +The new code is part of the existing afl++ LLVM module in the llvm_mode/ +subdirectory. There is nothing specifically to do :) + +## 3) How to use the partial instrumentation mode + +In order to build with partial instrumentation, you need to build with +afl-clang-fast/afl-clang-fast++ or afl-clang-lto/afl-clang-lto++. +The only required change is that you need to set either the environment variable +AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST set with a filename. + +That file then contains the filenames or functions that should be instrumented +(AFL_LLVM_ALLOWLIST) or should specifically NOT instrumentd (AFL_LLVM_DENYLIST). + +For matching, the function/filename that is being compiled must end in the +function/filename entry contained in this the instrument file list (to avoid +breaking the matching when absolute paths are used during compilation). + +**NOTE:** In optimization functions might be inlined and then not match! + +For example if your source tree looks like this: +``` +project/ +project/feature_a/a1.cpp +project/feature_a/a2.cpp +project/feature_b/b1.cpp +project/feature_b/b2.cpp +``` + +and you only want to test feature_a, then create a the instrument file list file containing: +``` +feature_a/a1.cpp +feature_a/a2.cpp +``` + +However if the instrument file list file contains only this, it works as well: +``` +a1.cpp +a2.cpp +``` +but it might lead to files being unwantedly instrumented if the same filename +exists somewhere else in the project directories. + +You can also specify function names. Note that for C++ the function names +must be mangled to match! + +afl++ is intelligent to identify if an entry is a filename or a function. +However if you want to be sure (and compliant to the sancov allow/blocklist +format), you can file entries like this: +``` +src: *malloc.c +``` +and function entries like this: +``` +fun: MallocFoo +``` +Note that whitespace is ignored and comments (`# foo`) supported. + +## 4) UNIX-style pattern matching +You can add UNIX-style pattern matching in the the instrument file list entries. +See `man fnmatch` for the syntax. We do not set any of the `fnmatch` flags. diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index e521ac82..4d643324 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -108,15 +108,12 @@ make install Just use afl-clang-lto like you did with afl-clang-fast or afl-gcc. -Also the instrument file listing (AFL_LLVM_INSTRUMENT_FILE -> [README.instrument_file.md](README.instrument_file.md)) and +Also the instrument file listing (AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST -> [README.instrument_list.md](README.instrument_list.md)) and laf-intel/compcov (AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work. -InsTrim (control flow graph instrumentation) is supported and recommended! - (set `AFL_LLVM_INSTRUMENT=CFG`) Example: ``` CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar ./configure -export AFL_LLVM_INSTRUMENT=CFG make ``` diff --git a/llvm_mode/README.md b/llvm_mode/README.md index 22088dfd..f23d7150 100644 --- a/llvm_mode/README.md +++ b/llvm_mode/README.md @@ -109,7 +109,7 @@ Several options are present to make llvm_mode faster or help it rearrange the code to make afl-fuzz path discovery easier. If you need just to instrument specific parts of the code, you can the instrument file list -which C/C++ files to actually instrument. See [README.instrument_file](README.instrument_file.md) +which C/C++ files to actually instrument. See [README.instrument_list](README.instrument_list.md) For splitting memcmp, strncmp, etc. please see [README.laf-intel](README.laf-intel.md) diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index ef99e3f3..f75adf1e 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -229,7 +229,8 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (lto_mode) { if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || - getenv("AFL_LLVM_WHITELIST")) { + getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || + getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) { cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; @@ -637,9 +638,13 @@ int main(int argc, char **argv, char **envp) { } - if ((getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")) && + if ((getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || + getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || + getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) && getenv("AFL_DONT_OPTIMIZE")) - FATAL("AFL_LLVM_INSTRUMENT_FILE and AFL_DONT_OPTIMIZE cannot be combined"); + WARNF( + "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined " + "for file matching, only function matching!"); if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") || getenv("INSTRIM_LIB")) { @@ -787,15 +792,17 @@ int main(int argc, char **argv, char **envp) { #if LLVM_VERSION_MAJOR <= 6 instrument_mode = INSTRUMENT_AFL; #else - if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")) { + if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || + getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || + getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) { instrument_mode = INSTRUMENT_AFL; WARNF( "switching to classic instrumentation because " - "AFL_LLVM_INSTRUMENT_FILE does not work with PCGUARD. Use " - "-fsanitize-coverage-allowlist=allowlist.txt if you want to use " - "PCGUARD. Requires llvm 12+. See " - "https://clang.llvm.org/docs/" + "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD. Use " + "-fsanitize-coverage-allowlist=allowlist.txt or " + "-fsanitize-coverage-blocklist=denylist.txt if you want to use " + "PCGUARD. Requires llvm 12+. See https://clang.llvm.org/docs/ " "SanitizerCoverage.html#partially-disabling-instrumentation"); } else @@ -846,11 +853,14 @@ int main(int argc, char **argv, char **envp) { "together"); if (instrument_mode == INSTRUMENT_PCGUARD && - (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST"))) + (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || + getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") || + getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST"))) FATAL( "Instrumentation type PCGUARD does not support " - "AFL_LLVM_INSTRUMENT_FILE! Use " - "-fsanitize-coverage-allowlist=allowlist.txt instead (requires llvm " + "AFL_LLVM_ALLOWLIST/DENYLIST! Use " + "-fsanitize-coverage-allowlist=allowlist.txt or " + "-fsanitize-coverage-blocklist=denylist.txt instead (requires llvm " "12+), see " "https://clang.llvm.org/docs/" "SanitizerCoverage.html#partially-disabling-instrumentation"); diff --git a/llvm_mode/afl-llvm-common.cc b/llvm_mode/afl-llvm-common.cc index 9a884ded..0b89c3b4 100644 --- a/llvm_mode/afl-llvm-common.cc +++ b/llvm_mode/afl-llvm-common.cc @@ -20,7 +20,10 @@ using namespace llvm; -static std::list myInstrumentList; +static std::list allowListFiles; +static std::list allowListFunctions; +static std::list denyListFiles; +static std::list denyListFunctions; char *getBBName(const llvm::BasicBlock *BB) { @@ -87,30 +90,166 @@ bool isIgnoreFunction(const llvm::Function *F) { void initInstrumentList() { - char *instrumentListFilename = getenv("AFL_LLVM_INSTRUMENT_FILE"); - if (!instrumentListFilename) - instrumentListFilename = getenv("AFL_LLVM_WHITELIST"); + char *allowlist = getenv("AFL_LLVM_ALLOWLIST"); + if (!allowlist) allowlist = getenv("AFL_LLVM_INSTRUMENT_FILE"); + if (!allowlist) allowlist = getenv("AFL_LLVM_WHITELIST"); + char *denylist = getenv("AFL_LLVM_DENYLIST"); + if (!denylist) denylist = getenv("AFL_LLVM_BLOCKLIST"); - if (instrumentListFilename) { + if (allowlist && denylist) + FATAL( + "You can only specify either AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST " + "but not both!"); + + if (allowlist) { std::string line; std::ifstream fileStream; - fileStream.open(instrumentListFilename); - if (!fileStream) - report_fatal_error("Unable to open AFL_LLVM_INSTRUMENT_FILE"); + fileStream.open(allowlist); + if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_ALLOWLIST"); getline(fileStream, line); + while (fileStream) { - myInstrumentList.push_back(line); - getline(fileStream, line); + int is_file = -1; + std::size_t npos; + std::string original_line = line; + + line.erase(std::remove_if(line.begin(), line.end(), ::isspace), + line.end()); + + // remove # and following + if ((npos = line.find("#")) != std::string::npos) + line = line.substr(0, npos); + + if (line.compare(0, 4, "fun:") == 0) { + + is_file = 0; + line = line.substr(4); + + } else if (line.compare(0, 9, "function:") == 0) { + + is_file = 0; + line = line.substr(9); + + } else if (line.compare(0, 4, "src:") == 0) { + + is_file = 1; + line = line.substr(4); + + } else if (line.compare(0, 7, "source:") == 0) { + + is_file = 1; + line = line.substr(7); + + } + + if (line.find(":") != std::string::npos) { + + FATAL("invalid line in AFL_LLVM_ALLOWLIST: %s", original_line.c_str()); + + } + + if (line.length() > 0) { + + // if the entry contains / or . it must be a file + if (is_file == -1) + if (line.find("/") != std::string::npos || + line.find(".") != std::string::npos) + is_file = 1; + // otherwise it is a function + + if (is_file == 1) + allowListFiles.push_back(line); + else + allowListFunctions.push_back(line); + getline(fileStream, line); + + } } + if (debug) + SAYF(cMGN "[D] " cRST + "loaded allowlist with %zu file and %zu function entries\n", + allowListFiles.size(), allowListFunctions.size()); + } - if (debug) - SAYF(cMGN "[D] " cRST "loaded instrument list with %zu entries\n", - myInstrumentList.size()); + if (denylist) { + + std::string line; + std::ifstream fileStream; + fileStream.open(denylist); + if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_DENYLIST"); + getline(fileStream, line); + + while (fileStream) { + + int is_file = -1; + std::size_t npos; + std::string original_line = line; + + line.erase(std::remove_if(line.begin(), line.end(), ::isspace), + line.end()); + + // remove # and following + if ((npos = line.find("#")) != std::string::npos) + line = line.substr(0, npos); + + if (line.compare(0, 4, "fun:") == 0) { + + is_file = 0; + line = line.substr(4); + + } else if (line.compare(0, 9, "function:") == 0) { + + is_file = 0; + line = line.substr(9); + + } else if (line.compare(0, 4, "src:") == 0) { + + is_file = 1; + line = line.substr(4); + + } else if (line.compare(0, 7, "source:") == 0) { + + is_file = 1; + line = line.substr(7); + + } + + if (line.find(":") != std::string::npos) { + + FATAL("invalid line in AFL_LLVM_DENYLIST: %s", original_line.c_str()); + + } + + if (line.length() > 0) { + + // if the entry contains / or . it must be a file + if (is_file == -1) + if (line.find("/") != std::string::npos || + line.find(".") != std::string::npos) + is_file = 1; + // otherwise it is a function + + if (is_file == 1) + denyListFiles.push_back(line); + else + denyListFunctions.push_back(line); + getline(fileStream, line); + + } + + } + + if (debug) + SAYF(cMGN "[D] " cRST + "loaded denylist with %zu file and %zu function entries\n", + denyListFiles.size(), denyListFunctions.size()); + + } } @@ -121,42 +260,173 @@ bool isInInstrumentList(llvm::Function *F) { if (!F->size() || isIgnoreFunction(F)) return false; // if we do not have a the instrument file list return true - if (myInstrumentList.empty()) return true; + if (!allowListFiles.empty() || !allowListFunctions.empty()) { + + if (!allowListFunctions.empty()) { + + std::string instFunction = F->getName().str(); + + for (std::list::iterator it = allowListFunctions.begin(); + it != allowListFunctions.end(); ++it) { + + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. We also allow UNIX-style pattern + * matching */ - // let's try to get the filename for the function - auto bb = &F->getEntryBlock(); - BasicBlock::iterator IP = bb->getFirstInsertionPt(); - IRBuilder<> IRB(&(*IP)); - DebugLoc Loc = IP->getDebugLoc(); + if (instFunction.length() >= it->length()) { + + if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) { + + if (debug) + SAYF(cMGN "[D] " cRST + "Function %s is in the allow function list, " + "instrumenting ... \n", + instFunction.c_str()); + return true; + + } + + } + + } + + } + + if (!allowListFiles.empty()) { + + // let's try to get the filename for the function + auto bb = &F->getEntryBlock(); + BasicBlock::iterator IP = bb->getFirstInsertionPt(); + IRBuilder<> IRB(&(*IP)); + DebugLoc Loc = IP->getDebugLoc(); #if LLVM_VERSION_MAJOR >= 4 || \ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) - if (Loc) { + if (Loc) { + + DILocation *cDILoc = dyn_cast(Loc.getAsMDNode()); + + unsigned int instLine = cDILoc->getLine(); + StringRef instFilename = cDILoc->getFilename(); - DILocation *cDILoc = dyn_cast(Loc.getAsMDNode()); + if (instFilename.str().empty()) { - unsigned int instLine = cDILoc->getLine(); - StringRef instFilename = cDILoc->getFilename(); + /* If the original location is empty, try using the inlined location + */ + DILocation *oDILoc = cDILoc->getInlinedAt(); + if (oDILoc) { + + instFilename = oDILoc->getFilename(); + instLine = oDILoc->getLine(); + + } + + } - if (instFilename.str().empty()) { + /* Continue only if we know where we actually are */ + if (!instFilename.str().empty()) { - /* If the original location is empty, try using the inlined location - */ - DILocation *oDILoc = cDILoc->getInlinedAt(); - if (oDILoc) { + for (std::list::iterator it = allowListFiles.begin(); + it != allowListFiles.end(); ++it) { - instFilename = oDILoc->getFilename(); - instLine = oDILoc->getLine(); + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. We also allow UNIX-style pattern + * matching */ + + if (instFilename.str().length() >= it->length()) { + + if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) == + 0) { + + if (debug) + SAYF(cMGN "[D] " cRST + "Function %s is in the allowlist (%s), " + "instrumenting ... \n", + F->getName().str().c_str(), instFilename.str().c_str()); + return true; + + } + + } + + } + + } + + } + + } + +#else + if (!Loc.isUnknown()) { + + DILocation cDILoc(Loc.getAsMDNode(F->getContext())); + + unsigned int instLine = cDILoc.getLineNumber(); + StringRef instFilename = cDILoc.getFilename(); + + (void)instLine; + /* Continue only if we know where we actually are */ + if (!instFilename.str().empty()) { + + for (std::list::iterator it = allowListFiles.begin(); + it != allowListFiles.end(); ++it) { + + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. We also allow UNIX-style pattern + * matching */ + + if (instFilename.str().length() >= it->length()) { + + if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) == + 0) { + + return true; + + } + + } + + } + + } } } - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { +#endif + else { + + // we could not find out the location. in this case we say it is not + // in the the instrument file list + if (!be_quiet) + WARNF( + "No debug information found for function %s, will not be " + "instrumented (recompile with -g -O[1-3]).", + F->getName().str().c_str()); + return false; + + } + + return false; + + } + + if (!denyListFiles.empty() || !denyListFunctions.empty()) { + + if (!denyListFunctions.empty()) { - for (std::list::iterator it = myInstrumentList.begin(); - it != myInstrumentList.end(); ++it) { + std::string instFunction = F->getName().str(); + + for (std::list::iterator it = denyListFunctions.begin(); + it != denyListFunctions.end(); ++it) { /* We don't check for filename equality here because * filenames might actually be full paths. Instead we @@ -164,16 +434,16 @@ bool isInInstrumentList(llvm::Function *F) { * specified in the list. We also allow UNIX-style pattern * matching */ - if (instFilename.str().length() >= it->length()) { + if (instFunction.length() >= it->length()) { - if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) == - 0) { + if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) { if (debug) SAYF(cMGN "[D] " cRST - "Function %s is in the list (%s), instrumenting ... \n", - F->getName().str().c_str(), instFilename.str().c_str()); - return true; + "Function %s is in the deny function list, " + "not instrumenting ... \n", + instFunction.c_str()); + return false; } @@ -183,35 +453,64 @@ bool isInInstrumentList(llvm::Function *F) { } - } + if (!denyListFiles.empty()) { -#else - if (!Loc.isUnknown()) { + // let's try to get the filename for the function + auto bb = &F->getEntryBlock(); + BasicBlock::iterator IP = bb->getFirstInsertionPt(); + IRBuilder<> IRB(&(*IP)); + DebugLoc Loc = IP->getDebugLoc(); - DILocation cDILoc(Loc.getAsMDNode(F->getContext())); +#if LLVM_VERSION_MAJOR >= 4 || \ + (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) + if (Loc) { - unsigned int instLine = cDILoc.getLineNumber(); - StringRef instFilename = cDILoc.getFilename(); + DILocation *cDILoc = dyn_cast(Loc.getAsMDNode()); - (void)instLine; - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { + unsigned int instLine = cDILoc->getLine(); + StringRef instFilename = cDILoc->getFilename(); - for (std::list::iterator it = myInstrumentList.begin(); - it != myInstrumentList.end(); ++it) { + if (instFilename.str().empty()) { - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. We also allow UNIX-style pattern - * matching */ + /* If the original location is empty, try using the inlined location + */ + DILocation *oDILoc = cDILoc->getInlinedAt(); + if (oDILoc) { - if (instFilename.str().length() >= it->length()) { + instFilename = oDILoc->getFilename(); + instLine = oDILoc->getLine(); - if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) == - 0) { + } - return true; + } + + /* Continue only if we know where we actually are */ + if (!instFilename.str().empty()) { + + for (std::list::iterator it = denyListFiles.begin(); + it != denyListFiles.end(); ++it) { + + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. We also allow UNIX-style pattern + * matching */ + + if (instFilename.str().length() >= it->length()) { + + if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) == + 0) { + + if (debug) + SAYF(cMGN "[D] " cRST + "Function %s is in the denylist (%s), not " + "instrumenting ... \n", + F->getName().str().c_str(), instFilename.str().c_str()); + return false; + + } + + } } @@ -221,23 +520,65 @@ bool isInInstrumentList(llvm::Function *F) { } - } +#else + if (!Loc.isUnknown()) { + + DILocation cDILoc(Loc.getAsMDNode(F->getContext())); + + unsigned int instLine = cDILoc.getLineNumber(); + StringRef instFilename = cDILoc.getFilename(); + + (void)instLine; + /* Continue only if we know where we actually are */ + if (!instFilename.str().empty()) { + + for (std::list::iterator it = denyListFiles.begin(); + it != denyListFiles.end(); ++it) { + + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. We also allow UNIX-style pattern + * matching */ + + if (instFilename.str().length() >= it->length()) { + + if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) == + 0) { + + return false; + + } + + } + + } + + } + + } + + } #endif - else { - - // we could not find out the location. in this case we say it is not - // in the the instrument file list - if (!be_quiet) - WARNF( - "No debug information found for function %s, will not be " - "instrumented (recompile with -g -O[1-3]).", - F->getName().str().c_str()); - return false; + else { + + // we could not find out the location. in this case we say it is not + // in the the instrument file list + if (!be_quiet) + WARNF( + "No debug information found for function %s, will be " + "instrumented (recompile with -g -O[1-3]).", + F->getName().str().c_str()); + return true; + + } + + return true; } - return false; + return true; // not reached } diff --git a/llvm_mode/afl-llvm-lto-instrumentlist.so.cc b/llvm_mode/afl-llvm-lto-instrumentlist.so.cc index ab7c0c58..a7331444 100644 --- a/llvm_mode/afl-llvm-lto-instrumentlist.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentlist.so.cc @@ -59,39 +59,9 @@ class AFLcheckIfInstrument : public ModulePass { static char ID; AFLcheckIfInstrument() : ModulePass(ID) { - int entries = 0; - if (getenv("AFL_DEBUG")) debug = 1; - char *instrumentListFilename = getenv("AFL_LLVM_INSTRUMENT_FILE"); - if (!instrumentListFilename) - instrumentListFilename = getenv("AFL_LLVM_WHITELIST"); - if (instrumentListFilename) { - - std::string line; - std::ifstream fileStream; - fileStream.open(instrumentListFilename); - if (!fileStream) - report_fatal_error("Unable to open AFL_LLVM_INSTRUMENT_FILE"); - getline(fileStream, line); - while (fileStream) { - - myInstrumentList.push_back(line); - getline(fileStream, line); - entries++; - - } - - } else - - PFATAL( - "afl-llvm-lto-instrumentlist.so loaded without " - "AFL_LLVM_INSTRUMENT_FILE?!"); - - if (debug) - SAYF(cMGN "[D] " cRST - "loaded the instrument file list %s with %d entries\n", - instrumentListFilename, entries); + initInstrumentList(); } @@ -129,120 +99,28 @@ bool AFLcheckIfInstrument::runOnModule(Module &M) { for (auto &F : M) { if (F.size() < 1) continue; - // fprintf(stderr, "F:%s\n", F.getName().str().c_str()); - if (isIgnoreFunction(&F)) continue; - - BasicBlock::iterator IP = F.getEntryBlock().getFirstInsertionPt(); - IRBuilder<> IRB(&(*IP)); - - if (!myInstrumentList.empty()) { - - bool instrumentFunction = false; - - /* Get the current location using debug information. - * For now, just instrument the block if we are not able - * to determine our location. */ - DebugLoc Loc = IP->getDebugLoc(); - if (Loc) { - - DILocation *cDILoc = dyn_cast(Loc.getAsMDNode()); - - unsigned int instLine = cDILoc->getLine(); - StringRef instFilename = cDILoc->getFilename(); - - if (instFilename.str().empty()) { - - /* If the original location is empty, try using the inlined location - */ - DILocation *oDILoc = cDILoc->getInlinedAt(); - if (oDILoc) { - - instFilename = oDILoc->getFilename(); - instLine = oDILoc->getLine(); - - } - - if (instFilename.str().empty()) { - if (!be_quiet) - WARNF( - "Function %s has no source file name information and will " - "not be instrumented.", - F.getName().str().c_str()); - continue; - - } - - } - - //(void)instLine; - - fprintf(stderr, "xxx %s %s\n", F.getName().str().c_str(), - instFilename.str().c_str()); - if (debug) - SAYF(cMGN "[D] " cRST "function %s is in file %s\n", - F.getName().str().c_str(), instFilename.str().c_str()); - - for (std::list::iterator it = myInstrumentList.begin(); - it != myInstrumentList.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) == - 0) { - - instrumentFunction = true; - break; - - } - - } - - } - - } else { - - if (!be_quiet) - WARNF( - "No debug information found for function %s, recompile with -g " - "-O[1-3]", - F.getName().str().c_str()); - continue; - - } - - /* Either we couldn't figure out our location or the location is - * not the instrument file listed, so we skip instrumentation. - * We do this by renaming the function. */ - if (instrumentFunction == true) { - - if (debug) - SAYF(cMGN "[D] " cRST "function %s is in the instrument file list\n", - F.getName().str().c_str()); - - } else { - - if (debug) - SAYF(cMGN "[D] " cRST - "function %s is NOT in the instrument file list\n", - F.getName().str().c_str()); + // fprintf(stderr, "F:%s\n", F.getName().str().c_str()); - auto & Ctx = F.getContext(); - AttributeList Attrs = F.getAttributes(); - AttrBuilder NewAttrs; - NewAttrs.addAttribute("skipinstrument"); - F.setAttributes( - Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs)); + if (isInInstrumentList(&F)) { - } + if (debug) + SAYF(cMGN "[D] " cRST "function %s is in the instrument file list\n", + F.getName().str().c_str()); } else { - PFATAL("InstrumentList is empty"); + if (debug) + SAYF(cMGN "[D] " cRST + "function %s is NOT in the instrument file list\n", + F.getName().str().c_str()); + + auto & Ctx = F.getContext(); + AttributeList Attrs = F.getAttributes(); + AttrBuilder NewAttrs; + NewAttrs.addAttribute("skipinstrument"); + F.setAttributes( + Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs)); } -- cgit 1.4.1 From 182b8b3e142814ac865396f8a66453f071d8a2d6 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 20 Aug 2020 19:00:15 +0200 Subject: remove doc reference for SKIPSINGLEBLOCK --- docs/env_variables.md | 10 +++------- llvm_mode/README.instrim.md | 9 --------- 2 files changed, 3 insertions(+), 16 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index f0ae0b6c..94c34400 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -83,17 +83,12 @@ tools make fairly broad use of environmental variables: The native instrumentation helpers (llvm_mode and gcc_plugin) accept a subset of the settings discussed in section #1, with the exception of: - - Setting AFL_LLVM_SKIPSINGLEBLOCK=1 will skip instrumenting - functions with a single basic block. This is useful for most C and - some C++ targets. This works for all instrumentation modes. - - AFL_AS, since this toolchain does not directly invoke GNU as. - TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are created. - - AFL_INST_RATIO, as we switched for instrim instrumentation which - is more effective but makes not much sense together with this option. + - AFL_INST_RATIO, as we by default collision free instrumentation is used. Then there are a few specific features that are only available in llvm_mode: @@ -121,7 +116,8 @@ Then there are a few specific features that are only available in llvm_mode: built if LLVM 11 or newer is used. - AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation. - (not recommended!) + (not recommended for afl-clang-fast, default for afl-clang-lto as there + it is a different and better kind of instrumentation.) None of the following options are necessary to be used and are rather for manual use (which only ever the author of this LTO implementation will use). diff --git a/llvm_mode/README.instrim.md b/llvm_mode/README.instrim.md index 53a518a9..7758091b 100644 --- a/llvm_mode/README.instrim.md +++ b/llvm_mode/README.instrim.md @@ -19,15 +19,6 @@ see how often the loop has been rerun. This again is a tradeoff for speed for less path information. To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`. -There is an additional optimization option that skips single block -functions. In 95% of the C targets and (guess) 50% of the C++ targets -it is good to enable this, as otherwise pointless instrumentation occurs. -The corner case where we want this instrumentation is when vtable/call table -is used and the index to that vtable/call table is not set in specific -basic blocks. -To enable skipping these (most of the time) unnecessary instrumentations set -`AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1` - ## Background The paper: [InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing] -- cgit 1.4.1 From 6184832ea98050c91cdefa5059e18e78c39b14de Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sun, 23 Aug 2020 10:59:56 +0200 Subject: added more env var docs, fsrv fixes for cmin, tmin --- docs/Changelog.md | 4 ++++ docs/env_variables.md | 15 +++++++++++++++ src/afl-showmap.c | 10 ++++++++++ src/afl-tmin.c | 10 ++++++++++ 4 files changed, 39 insertions(+) (limited to 'docs/env_variables.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 8bbb4e19..f7bc9600 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -14,6 +14,10 @@ sending a mail to . - Fix for auto dictionary entries found during fuzzing to not throw out a -x dictionary - added total execs done to plot file + - AFL_MAX_DET_EXTRAS env variable added to control the amount of deterministic + dict entries without recompiling. + - AFL_FORKSRV_INIT_TMOUT env variable added to control the time to wait for + the forkserver to come up without the need to increase the overall timeout. - llvm_mode: - Ported SanCov to LTO, and made it the default for LTO. better instrumentation locations diff --git a/docs/env_variables.md b/docs/env_variables.md index 94c34400..e8129a3f 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -278,6 +278,14 @@ checks or alter some of the more exotic semantics of the tool: don't want AFL to spend too much time classifying that stuff and just rapidly put all timeouts in that bin. + - Setting AFL_FORKSRV_INIT_TMOUT allows yout to specify a different timeout + to wait for the forkserver to spin up. The default is the `-t` value times + `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the + default would wait `1000` milis. Setting a different time here is useful + if the target has a very slow startup time, for example when doing + full-system fuzzing or emulation, but you don't want the actual runs + to wait too long for timeouts. + - AFL_NO_ARITH causes AFL to skip most of the deterministic arithmetics. This can be useful to speed up the fuzzing of text-based file formats. @@ -361,6 +369,13 @@ checks or alter some of the more exotic semantics of the tool: for an existing out folder, even if a different `-i` was provided. Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir. + - Setting AFL_MAX_DET_EXRAS will change the threshold at what number of elements + in the `-x` dictionary and LTO autodict (combined) the probabilistic mode will + kick off. In probabilistic mode, not all dictionary entires will be used all + of the times for fuzzing mutations to not make fuzzing slower by it. + The default count is `200` element. So for the 200 + 1st element, there is a + 1 in 201 chance, that one of the dictionary entry will not be used directly. + - Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to fork + execve() call for every tested input. This is useful mostly when working with unruly libraries that create threads or do other crazy diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 47c615d8..2c20e419 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1036,6 +1036,16 @@ int main(int argc, char **argv_orig, char **envp) { } + if (getenv("AFL_FORKSRV_INIT_TMOUT")) { + + s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT")); + if (forksrv_init_tmout < 1) { + FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT"); + } + fsrv->init_tmout = (u32) forksrv_init_tmout; + + } + afl_fsrv_start(fsrv, use_argv, &stop_soon, get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); map_size = fsrv->map_size; diff --git a/src/afl-tmin.c b/src/afl-tmin.c index b50d8597..a15a6079 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1103,6 +1103,16 @@ int main(int argc, char **argv_orig, char **envp) { } SAYF("\n"); + + if (getenv("AFL_FORKSRV_INIT_TMOUT")) { + + s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT")); + if (forksrv_init_tmout < 1) { + FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT"); + } + fsrv->init_tmout = (u32) forksrv_init_tmout; + + } shm_fuzz = ck_alloc(sizeof(sharedmem_t)); -- cgit 1.4.1 From 8253f9013418f2b8e94768c16a33e63a92e8e440 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Mon, 31 Aug 2020 15:16:55 +0200 Subject: typos/wording --- docs/env_variables.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index 7d4f6716..d377e83f 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -10,8 +10,8 @@ Because they can't directly accept command-line options, the compile-time tools make fairly broad use of environmental variables: - - Most afl tools do not print any ouput if stout/stderr are redirected. - If you want to have the output into a file then set the AFL_DEBUG + - Most afl tools do not print any output if stdout/stderr are redirected. + If you want to save the output in a file then set the AFL_DEBUG environment variable. This is sadly necessary for various build processes which fail otherwise. @@ -44,7 +44,7 @@ tools make fairly broad use of environmental variables: you instrument hand-written assembly when compiling clang code by plugging a normalizer into the chain. (There is no equivalent feature for GCC.) - - Setting AFL_INST_RATIO to a percentage between 0 and 100% controls the + - Setting AFL_INST_RATIO to a percentage between 0% and 100% controls the probability of instrumenting every branch. This is (very rarely) useful when dealing with exceptionally complex programs that saturate the output bitmap. Examples include v8, ffmpeg, and perl. @@ -88,7 +88,7 @@ of the settings discussed in section #1, with the exception of: - TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are created. - - AFL_INST_RATIO, as we by default collision free instrumentation is used. + - AFL_INST_RATIO, as we by default use collision free instrumentation. Then there are a few specific features that are only available in llvm_mode: @@ -121,7 +121,7 @@ Then there are a few specific features that are only available in llvm_mode: None of the following options are necessary to be used and are rather for manual use (which only ever the author of this LTO implementation will use). - These are used if several seperated instrumentation are performed which + These are used if several seperated instrumentations are performed which are then later combined. - AFL_LLVM_DOCUMENT_IDS=file will document to a file which edge ID was given @@ -200,7 +200,7 @@ Then there are a few specific features that are only available in llvm_mode: ### INSTRUMENT LIST (selectively instrument files and functions) - This feature allows selectively instrumentation of the source + This feature allows selective instrumentation of the source - Setting AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST with a filenames and/or function will only instrument (or skip) those files that match the names @@ -371,10 +371,10 @@ checks or alter some of the more exotic semantics of the tool: - Setting AFL_MAX_DET_EXRAS will change the threshold at what number of elements in the `-x` dictionary and LTO autodict (combined) the probabilistic mode will - kick off. In probabilistic mode, not all dictionary entires will be used all - of the times for fuzzing mutations to not make fuzzing slower by it. - The default count is `200` element. So for the 200 + 1st element, there is a - 1 in 201 chance, that one of the dictionary entry will not be used directly. + kick off. In probabilistic mode, not all dictionary entries will be used all + the times for fuzzing mutations in order not to slow down fuzzing. + The default count is `200` elements. So for the 200 + 1st element, there is a + 1 in 201 chance, that one of the dictionary entries will not be used directly. - Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to fork + execve() call for every tested input. This is useful mostly when @@ -385,14 +385,14 @@ checks or alter some of the more exotic semantics of the tool: normally done when starting up the forkserver and causes a pretty significant performance drop. - - Setting AFL_MAX_DET_EXTRAS changes the count of dictionary enties/extras + - Setting AFL_MAX_DET_EXTRAS changes the count of dictionary entries/extras (default 200), after which the entries will be used probabilistically. So, if the dict/extras file (`-x`) contains more tokens than this threshold, not all of the tokens will be used in each fuzzing step, every time. Instead, there is a chance that the entry will be skipped during fuzzing. This makes sure that the fuzzer doesn't spend all its time only inserting the extras, but will still do other mutations. However, it decreases the - likelyhood for each token to be inserted, before the next queue entrie is fuzzed. + likelihood for each token to be inserted, before the next queue entry is fuzzed. Either way, all tokens will be used eventually, in a longer fuzzing campaign. - Outdated environment variables that are that not supported anymore: -- cgit 1.4.1 From 192cadee3485eef1c69ca662323ac3e50669aee9 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 31 Aug 2020 18:10:18 +0200 Subject: fix docs --- docs/env_variables.md | 7 ------- 1 file changed, 7 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index d377e83f..c47d10e8 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -369,13 +369,6 @@ checks or alter some of the more exotic semantics of the tool: for an existing out folder, even if a different `-i` was provided. Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir. - - Setting AFL_MAX_DET_EXRAS will change the threshold at what number of elements - in the `-x` dictionary and LTO autodict (combined) the probabilistic mode will - kick off. In probabilistic mode, not all dictionary entries will be used all - the times for fuzzing mutations in order not to slow down fuzzing. - The default count is `200` elements. So for the 200 + 1st element, there is a - 1 in 201 chance, that one of the dictionary entries will not be used directly. - - Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to fork + execve() call for every tested input. This is useful mostly when working with unruly libraries that create threads or do other crazy -- cgit 1.4.1 From e30b2c6af6e369844c92c00a20ebdd53473a747c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 5 Sep 2020 13:18:28 +0200 Subject: final changes for pre-3.0 --- .gitignore | 6 ++ Android.bp | 6 +- GNUmakefile | 3 +- GNUmakefile.gcc_plugin | 1 + GNUmakefile.llvm | 8 ++- README.md | 2 +- docs/Changelog.md | 14 ++++ docs/FAQ.md | 104 +++++++++++++++--------------- docs/INSTALL.md | 19 +++--- docs/env_variables.md | 121 ++++++++++++++++++----------------- docs/ideas.md | 57 ----------------- docs/life_pro_tips.md | 4 +- docs/perf_tips.md | 8 +-- docs/sister_projects.md | 4 +- docs/status_screen.md | 2 +- examples/README.md | 2 +- examples/aflpp_driver/aflpp_driver.c | 2 +- include/afl-fuzz.h | 3 +- include/config.h | 4 +- include/envs.h | 1 + qemu_mode/patches/afl-qemu-cpu-inl.h | 2 +- src/afl-fuzz-init.c | 3 +- src/afl-fuzz-queue.c | 13 ++-- src/afl-fuzz-stats.c | 8 +-- src/afl-fuzz.c | 3 +- test/test-gcc-plugin.sh | 2 +- test/test-unittests.sh | 2 + 27 files changed, 188 insertions(+), 216 deletions(-) (limited to 'docs/env_variables.md') diff --git a/.gitignore b/.gitignore index 0527a0b2..e3adb6ef 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,12 @@ afl-showmap.8 afl-system-config.8 afl-tmin.8 afl-whatsup.8 +afl-c++ +afl-cc +afl-lto +afl-lto++ +afl-lto++.8 +afl-lto.8 qemu_mode/libcompcov/compcovtest qemu_mode/qemu-* unicorn_mode/samples/*/\.test-* diff --git a/Android.bp b/Android.bp index e59129db..2c2114b2 100644 --- a/Android.bp +++ b/Android.bp @@ -101,7 +101,7 @@ cc_binary_host { ], srcs: [ - "llvm_mode/afl-clang-fast.c", + "src/afl-cc.c", ], } @@ -119,7 +119,7 @@ cc_binary_host { ], srcs: [ - "llvm_mode/afl-clang-fast.c", + "src/afl-cc.c", ], } @@ -136,6 +136,6 @@ cc_library_static { ], srcs: [ - "llvm_mode/afl-llvm-rt.o.c", + "instrumentation/afl-llvm-rt.o.c", ], } diff --git a/GNUmakefile b/GNUmakefile index 0046a481..7455483c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -533,7 +533,7 @@ endif deepclean: clean rm -rf qemu_mode/qemu-3.1.1.tar.xz rm -rf unicorn_mode/unicornafl - git reset --hard >/dev/null 2>&1 || true + # NEVER EVER ACTIVATE THAT!!!!! git reset --hard >/dev/null 2>&1 || true .PHONY: distrib distrib: all @@ -591,6 +591,7 @@ install: all $(MANPAGES) @install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) @rm -f $${DESTDIR}$(BIN_PATH)/afl-plot.sh @rm -f $${DESTDIR}$(BIN_PATH)/afl-as + @rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o install -m 755 $(PROGS) $(SH_PROGS) $${DESTDIR}$(BIN_PATH) @if [ -f afl-qemu-trace ]; then install -m 755 afl-qemu-trace $${DESTDIR}$(BIN_PATH); fi @if [ -f libdislocator.so ]; then set -e; install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH); fi diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin index aeb1ef16..b73fcfda 100644 --- a/GNUmakefile.gcc_plugin +++ b/GNUmakefile.gcc_plugin @@ -158,6 +158,7 @@ vpath % .. install: all ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc-fast ln -sf afl-c++ $${DESTDIR}$(BIN_PATH)/afl-g++-fast + ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt.o install -m 755 ./afl-gcc-pass.so $${DESTDIR}$(HELPER_PATH) install -m 644 -T instrumentation/README.gcc_plugin.md $${DESTDIR}$(DOC_PATH)/README.gcc_plugin.md diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index d76e0b28..1bb3d265 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -423,10 +423,12 @@ document: ./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c | test_deps @printf "[*] Building 32-bit variant of the runtime (-m32)... " @$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi + @test -e afl-compiler-rt-32.o && ln -sf afl-compiler-rt-32.o afl-llvm-rt-64.o ./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c | test_deps @printf "[*] Building 64-bit variant of the runtime (-m64)... " @$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi + @test -e afl-compiler-rt-64.o && ln -sf afl-compiler-rt-64.o afl-llvm-rt-64.o .PHONY: test_build test_build: $(PROGS) @@ -448,11 +450,11 @@ all_done: test_build install: all @install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) @if [ -f ./afl-cc ]; then set -e; install -m 755 ./afl-cc $${DESTDIR}$(BIN_PATH); ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-c++; fi - @if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); fi + @if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)afl-llvm-rt.o ;fi @if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-lto-instrumentation.so ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi - @if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); fi - @if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); fi + @if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH)afl-llvm-rt-32.o ;fi + @if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH)afl-llvm-rt-64.o ; fi @if [ -f ./compare-transform-pass.so ]; then set -e; install -m 755 ./*.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f ./compare-transform-pass.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-fast ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-fast++ ; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang++ ; fi @if [ -f ./SanitizerCoverageLTO.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-lto++ ; fi diff --git a/README.md b/README.md index 96b34260..c886489d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Release Version: [2.67c](https://github.com/AFLplusplus/AFLplusplus/releases) - Github Version: 2.67d + Github Version: 3.00a Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) diff --git a/docs/Changelog.md b/docs/Changelog.md index 6321aee4..9de03e78 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,20 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . +### Version ++3.00a (develop) + - llvm_mode/ and gcc_plugin/ moved to instrumentation/ + - all compilers combined to afl-cc which emulates the previous ones + - afl-llvm/gcc-rt.o merged into afl-compiler-rt.o + - afl-fuzz + - reading testcases from -i now descends into subdirectories + - allow up to 4 -x command line options + - loaded extras now have a duplicate protection + - instrumentation + - new llvm pass: dict2file via AFL_LLVM_DICT2FILE, create afl-fuzz + -x dictionary of string comparisons found during compilation + - not overriding -Ox or -fno-unroll-loops anymore + + ### Version ++2.68c (release) - added the GSoC excellent afl++ grammar mutator by Shengtuo to our custom_mutators/ (see custom_mutators/README.md) - or get it here: diff --git a/docs/FAQ.md b/docs/FAQ.md index 064638f4..24942492 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -4,11 +4,11 @@ * [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl) * [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed) - * [How do I fuzz a network service?](#how-do-i-fuzz-a-network-service) - * [How do I fuzz a GUI program?](#how-do-i-fuzz-a-gui-program) + * [How do I fuzz a network service?](#how-to-fuzz-a-network-service) + * [How do I fuzz a GUI program?](#how-to-fuzz-a-gui-program) * [What is an edge?](#what-is-an-edge) * [Why is my stability below 100%?](#why-is-my-stability-below-100) - * [How can I improve the stability value?](#how-can-i-improve-the-stability-value) + * [How can I improve the stability value](#how-can-i-improve-the-stability-value) If you find an interesting or important question missing, submit it via [https://github.com/AFLplusplus/AFLplusplus/issues](https://github.com/AFLplusplus/AFLplusplus/issues) @@ -18,52 +18,51 @@ If you find an interesting or important question missing, submit it via American Fuzzy Lop (AFL) was developed by Michał "lcamtuf" Zalewski starting in 2013/2014, and when he left Google end of 2017 he stopped developing it. -At the end of 2019 the Google fuzzing team took over maintenance of AFL, however -it is only accepting PRs from the community and is not developing enhancements +At the end of 2019 the Google fuzzing team took over maintance of AFL, however +it is only accepting PR from the community and is not developing enhancements anymore. -In the second quarter of 2019, 1 1/2 year later when no further development of -AFL had happened and it became clear there would none be coming, afl++ -was born, where initially community patches were collected and applied -for bug fixes and enhancements. Then from various AFL spin-offs - mostly academic +In the second quarter of 2019, 1 1/2 years after no further development of +AFL had happened and it became clear there would be none coming, afl++ +was born, where initially first community patches were collected and applied +for bugs and enhancements. Then from various AFL spin-offs - mostly academic research - features were integrated. This already resulted in a much advanced AFL. Until the end of 2019 the afl++ team had grown to four active developers which -then implemented their own research and features, making it now by far the most +then implemented their own research and feature, making it now by far the most flexible and feature rich guided fuzzer available as open source. And in independent fuzzing benchmarks it is one of the best fuzzers available, e.g. [Fuzzbench Report](https://www.fuzzbench.com/reports/2020-08-03/index.html) -## How to improve the fuzzing speed? +## How to improve the fuzzing speed - 1. Use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended) - 2. Use [persistent mode](llvm_mode/README.persistent_mode.md) (x2-x20 speed increase) + 1. use [instrumentation](docs/README.llvm.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended) + 2. Use [persistent mode](instrumentation/README.persistent_mode.md) (x2-x20 speed increase) 3. Use the [afl++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM) (x2 speed increase) - 4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to put the input file directory on a tempfs location, see [docs/env_variables.md](docs/env_variables.md) - 5. Improve Linux kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system less secure) + 4. If you do not use shmem persistent mode, use `AFL_TMPDIR` to point the input file on a tempfs location, see [docs/env_variables.md](docs/env_variables.md) + 5. Improve kernel performance: modify `/etc/default/grub`, set `GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"`; then `update-grub` and `reboot` (warning: makes the system more insecure) 6. Running on an `ext2` filesystem with `noatime` mount option will be a bit faster than on any other journaling filesystem 7. Use your cores! [README.md:3.b) Using multiple cores/threads](../README.md#b-using-multiple-coresthreads) ## How do I fuzz a network service? -The short answer is - you cannot, at least not "out of the box". +The short answer is - you cannot, at least "out of the box". -Using a network channel is inadequate for several reasons: -- it has a slow-down of x10-20 on the fuzzing speed -- it does not scale to fuzzing multiple instances easily, -- instead of one initial data packet often a back-and-forth interplay of packets is needed for stateful protocols (which is totally unsupported by most coverage aware fuzzers). +Using network has a slow-down of x10-20 on the fuzzing speed, does not scale, +and finally usually it is more than one initial data packet but a back-and-forth +which is totally unsupported by most coverage aware fuzzers. The established method to fuzz network services is to modify the source code to read from a file or stdin (fd 0) (or even faster via shared memory, combine -this with persistent mode [llvm_mode/README.persistent_mode.md](llvm_mode/README.persistent_mode.md) +this with persistent mode [instrumentation/README.persistent_mode.md](instrumentation/README.persistent_mode.md) and you have a performance gain of x10 instead of a performance loss of over -x10 - that is a x100 difference!). +x10 - that is a x100 difference! If modifying the source is not an option (e.g. because you only have a binary and perform binary fuzzing) you can also use a shared library with AFL_PRELOAD -to emulate the network. This is also much faster than the real network would be. -See [examples/socket_fuzzing/](../examples/socket_fuzzing/). +to emulate the network. This is also much faster than network would be. +See [examples/socket_fuzzing/](../examples/socket_fuzzing/) There is an outdated afl++ branch that implements networking if you are desperate though: [https://github.com/AFLplusplus/AFLplusplus/tree/networking](https://github.com/AFLplusplus/AFLplusplus/tree/networking) - @@ -74,7 +73,7 @@ which allows you to define network state with different type of data packets. If the GUI program can read the fuzz data from a file (via the command line, a fixed location or via an environment variable) without needing any user -interaction then it would be suitable for fuzzing. +interaction then then yes. Otherwise it is not possible without modifying the source code - which is a very good idea anyway as the GUI functionality is a huge CPU/time overhead @@ -83,13 +82,13 @@ for the fuzzing. So create a new `main()` that just reads the test case and calls the functionality for processing the input that the GUI program is using. -## What is an "edge"? +## What is an "edge" A program contains `functions`, `functions` contain the compiled machine code. The compiled machine code in a `function` can be in a single or many `basic blocks`. A `basic block` is the largest possible number of subsequent machine code -instructions that has exactly one entrypoint (which can be be entered by multiple other basic blocks) -and runs linearly without branching or jumping to other addresses (except at the end). +instructions that runs independent, meaning it does not split up to different +locations nor is it jumped into it from a different location: ``` function() { A: @@ -99,7 +98,7 @@ function() { if (x) goto C; else goto D; C: some code - goto E + goto D D: some code goto B @@ -109,7 +108,7 @@ function() { ``` Every code block between two jump locations is a `basic block`. -An `edge` is then the unique relationship between two directly connected `basic blocks` (from the +An `edge` is then the unique relationship between two `basic blocks` (from the code example above): ``` Block A @@ -124,9 +123,8 @@ code example above): Block E ``` Every line between two blocks is an `edge`. -Note that a few basic block loop to itself, this too would be an edge. -## Why is my stability below 100%? +## Why is my stability below 100% Stability is measured by how many percent of the edges in the target are "stable". Sending the same input again and again should take the exact same @@ -134,37 +132,37 @@ path through the target every time. If that is the case, the stability is 100%. If however randomness happens, e.g. a thread reading other external data, reaction to timing, etc. then in some of the re-executions with the same data -the edge coverage result will be different accross runs. +the result in the edge information will be different accross runs. Those edges that change are then flagged "unstable". The more "unstable" edges, the more difficult for afl++ to identify valid new paths. A value above 90% is usually fine and a value above 80% is also still ok, and -even a value above 20% can still result in successful finds of bugs. -However, it is recommended that for values below 90% or 80% you should take -countermeasures to improve stability. +even above 20% can still result in successful finds of bugs. +However, it is recommended that below 90% or 80% you should take measures to +improve the stability. -## How can I improve the stability value? +## How can I improve the stability value -For fuzzing a 100% stable target that covers all edges is the best case. +For fuzzing a 100% stable target that covers all edges is the best. A 90% stable target that covers all edges is however better than a 100% stable target that ignores 10% of the edges. With instability you basically have a partial coverage loss on an edge, with -ignored functions you have a full loss on that edges. +ignore you have a full loss on that edge. There are functions that are unstable, but also provide value to coverage, eg init functions that use fuzz data as input for example. -If however a function that has nothing to do with the input data is the -source of instability, e.g. checking jitter, or is a hash map function etc. -then it should not be instrumented. +If however it is a function that has nothing to do with the input data is the +source, e.g. checking jitter, or is a hash map function etc. then it should +not be instrumented. -To be able to exclude these functions (based on AFL++'s measured stability) -the following process will allow to identify functions with variable edges. +To be able to make this decision the following process will allow you to +identify the functions with variable edges so you can make this decision. -Four steps are required to do this and it also requires quite some knowledge -of coding and/or disassembly and is effectively possible only with +Four steps are required to do this and requires quite some knowledge of +coding and/or disassembly and it is only effectively possible with afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. 1. First step: Identify which edge ID numbers are unstable @@ -173,7 +171,7 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. The out/fuzzer_stats file will then show the edge IDs that were identified as unstable. - 2. Second step: Find the responsible function(s). + 2. Second step: Find the responsible function. a) For LTO instrumented binaries this can be documented during compile time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/a/file`. @@ -182,10 +180,10 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. b) For PCGUARD instrumented binaries it is much more difficult. Here you can either modify the __sanitizer_cov_trace_pc_guard function in - llvm_mode/afl-llvm-rt.o.c to write a backtrace to a file if the ID in + instrumentation/afl-llvm-rt.o.c to write a backtrace to a file if the ID in __afl_area_ptr[*guard] is one of the unstable edge IDs. (Example code is already there). - Then recompile and reinstall llvm_mode and rebuild your target. + Then recompile and reinstall instrumentation and rebuild your target. Run the recompiled target with afl-fuzz for a while and then check the file that you wrote with the backtrace information. Alternatively you can use `gdb` to hook __sanitizer_cov_trace_pc_guard_init @@ -193,20 +191,20 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. and set a write breakpoint to that address (`watch 0x.....`). c) in all other instrumentation types this is not possible. So just - recompile with the two mentioned above. This is just for + recompile with the the two mentioned above. This is just for identifying the functions that have unstable edges. 3. Third step: create a text file with the filenames/functions Identify which source code files contain the functions that you need to remove from instrumentation, or just specify the functions you want to - skip for instrumentation. Note that optimization might inline functions! + skip instrumenting. Note that optimization might inline functions! - Simply follow this document on how to do this: [llvm_mode/README.instrument_list.md](llvm_mode/README.instrument_list.md) + Simply follow this document on how to do this: [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md) If PCGUARD is used, then you need to follow this guide (needs llvm 12+!): [http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation](http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation) - Only exclude those functions from instrumentation that provide no value + Only deny those functions from instrumentation that provide no value for coverage - that is if it does not process any fuzz data directly or indirectly (e.g. hash maps, thread management etc.). If however a function directly or indirectly handles fuzz data then you diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 766f24d7..fb7b5642 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -24,7 +24,7 @@ There are no special dependencies to speak of; you will need GNU make and a working compiler (gcc or clang). Some of the optional scripts bundled with the program may depend on bash, gdb, and similar basic tools. -If you are using clang, please review llvm_mode/README.md; the LLVM +If you are using clang, please review README.llvm.md; the LLVM integration mode can offer substantial performance gains compared to the traditional approach. @@ -52,10 +52,10 @@ sudo gmake install Keep in mind that if you are using csh as your shell, the syntax of some of the shell commands given in the README.md and other docs will be different. -The `llvm_mode` requires a dynamically linked, fully-operational installation of +The `llvm` requires a dynamically linked, fully-operational installation of clang. At least on FreeBSD, the clang binaries are static and do not include some of the essential tools, so if you want to make it work, you may need to -follow the instructions in llvm_mode/README.md. +follow the instructions in README.llvm.md. Beyond that, everything should work as advertised. @@ -97,27 +97,24 @@ and definitely don't look POSIX-compliant. This means two things: User emulation mode of QEMU does not appear to be supported on MacOS X, so black-box instrumentation mode (`-Q`) will not work. -The llvm_mode requires a fully-operational installation of clang. The one that +The llvm instrumentation requires a fully-operational installation of clang. The one that comes with Xcode is missing some of the essential headers and helper tools. -See llvm_mode/README.md for advice on how to build the compiler from scratch. +See README.llvm.md for advice on how to build the compiler from scratch. ## 4. Linux or *BSD on non-x86 systems Standard build will fail on non-x86 systems, but you should be able to leverage two other options: - - The LLVM mode (see llvm_mode/README.md), which does not rely on + - The LLVM mode (see README.llvm.md), which does not rely on x86-specific assembly shims. It's fast and robust, but requires a complete installation of clang. - The QEMU mode (see qemu_mode/README.md), which can be also used for fuzzing cross-platform binaries. It's slower and more fragile, but can be used even when you don't have the source for the tested app. -If you're not sure what you need, you need the LLVM mode. To get it, try: - -```bash -AFL_NO_X86=1 gmake && gmake -C llvm_mode -``` +If you're not sure what you need, you need the LLVM mode, which is built by +default. ...and compile your target program with afl-clang-fast or afl-clang-fast++ instead of the traditional afl-gcc or afl-clang wrappers. diff --git a/docs/env_variables.md b/docs/env_variables.md index c47d10e8..9d289f6d 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -5,13 +5,25 @@ users or for some types of custom fuzzing setups. See README.md for the general instruction manual. -## 1) Settings for afl-gcc, afl-clang, and afl-as - and gcc_plugin afl-gcc-fast +## 1) Settings for all compilers -Because they can't directly accept command-line options, the compile-time -tools make fairly broad use of environmental variables: +Starting with afl++ 3.0 there is only one compiler: afl-cc +To select the different instrumentation modes this can be done by + 1. passing --afl-MODE command line options to the compiler + 2. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++, + afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++, + afl-gcc-fast, afl-g++-fast + 3. using the environment variable AFL_CC_COMPILER with MODE - - Most afl tools do not print any output if stdout/stderr are redirected. - If you want to save the output in a file then set the AFL_DEBUG +MODE can one of LTO (afl-clang-lto*), LLVM (afl-clang-fast*), GCC_PLUGIN +(afl-g*-fast) or GCC (afl-gcc/afl-g++). + +Because beside the --afl-MODE command no afl specific command-line options +are accepted, the compile-time tools make fairly broad use of environmental +variables: + + - Most afl tools do not print any ouput if stout/stderr are redirected. + If you want to have the output into a file then set the AFL_DEBUG environment variable. This is sadly necessary for various build processes which fail otherwise. @@ -24,6 +36,8 @@ tools make fairly broad use of environmental variables: will cause problems in programs built with -Werror, simply because -O3 enables more thorough code analysis and can spew out additional warnings. To disable optimizations, set AFL_DONT_OPTIMIZE. + However if -O... and/or -fno-unroll-loops are set, these are not + overriden. - Setting AFL_USE_ASAN automatically enables ASAN, provided that your compiler supports that. Note that fuzzing with ASAN is mildly challenging @@ -44,7 +58,7 @@ tools make fairly broad use of environmental variables: you instrument hand-written assembly when compiling clang code by plugging a normalizer into the chain. (There is no equivalent feature for GCC.) - - Setting AFL_INST_RATIO to a percentage between 0% and 100% controls the + - Setting AFL_INST_RATIO to a percentage between 0 and 100% controls the probability of instrumenting every branch. This is (very rarely) useful when dealing with exceptionally complex programs that saturate the output bitmap. Examples include v8, ffmpeg, and perl. @@ -55,19 +69,16 @@ tools make fairly broad use of environmental variables: Setting AFL_INST_RATIO to 0 is a valid choice. This will instrument only the transitions between function entry points, but not individual branches. + Note that this is an outdated variable. A few instances (e.g. afl-gcc) + still support these, but state-of-the-art (e.g. LLVM LTO and LLVM PCGUARD) + do not need this. + - AFL_NO_BUILTIN causes the compiler to generate code suitable for use with libtokencap.so (but perhaps running a bit slower than without the flag). - TMPDIR is used by afl-as for temporary files; if this variable is not set, the tool defaults to /tmp. - - Setting AFL_KEEP_ASSEMBLY prevents afl-as from deleting instrumented - assembly files. Useful for troubleshooting problems or understanding how - the tool works. To get them in a predictable place, try something like: - - mkdir assembly_here - TMPDIR=$PWD/assembly_here AFL_KEEP_ASSEMBLY=1 make clean all - - If you are a weird person that wants to compile and instrument asm text files then use the AFL_AS_FORCE_INSTRUMENT variable: AFL_AS_FORCE_INSTRUMENT=1 afl-gcc foo.s -o foo @@ -78,19 +89,24 @@ tools make fairly broad use of environmental variables: - Setting AFL_CAL_FAST will speed up the initial calibration, if the application is very slow -## 2) Settings for afl-clang-fast / afl-clang-fast++ / afl-gcc-fast / afl-g++-fast +## 2) Settings for LLVM and LTO: afl-clang-fast / afl-clang-fast++ / afl-clang-lto / afl-clang-lto++ -The native instrumentation helpers (llvm_mode and gcc_plugin) accept a subset +The native instrumentation helpers (instrumentation and gcc_plugin) accept a subset of the settings discussed in section #1, with the exception of: + - LLVM modes support `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` which will + write all constant string comparisons to this file to be used with + afl-fuzz' `-x` option. + - AFL_AS, since this toolchain does not directly invoke GNU as. - TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are created. - - AFL_INST_RATIO, as we by default use collision free instrumentation. + - AFL_INST_RATIO, as we by default collision free instrumentation is used. + Not all passes support this option though as it is an outdated feature. -Then there are a few specific features that are only available in llvm_mode: +Then there are a few specific features that are only available in instrumentation: ### Select the instrumentation mode @@ -121,7 +137,7 @@ Then there are a few specific features that are only available in llvm_mode: None of the following options are necessary to be used and are rather for manual use (which only ever the author of this LTO implementation will use). - These are used if several seperated instrumentations are performed which + These are used if several seperated instrumentation are performed which are then later combined. - AFL_LLVM_DOCUMENT_IDS=file will document to a file which edge ID was given @@ -136,7 +152,7 @@ Then there are a few specific features that are only available in llvm_mode: - AFL_LLVM_LTO_DONTWRITEID prevents that the highest location ID written into the instrumentation is set in a global variable - See llvm_mode/README.LTO.md for more information. + See instrumentation/README.LTO.md for more information. ### INSTRIM @@ -154,7 +170,7 @@ Then there are a few specific features that are only available in llvm_mode: afl-fuzz will only be able to see the path the loop took, but not how many times it was called (unless it is a complex loop). - See llvm_mode/README.instrim.md + See instrumentation/README.instrim.md ### NGRAM @@ -165,7 +181,7 @@ Then there are a few specific features that are only available in llvm_mode: config.h to at least 18 and maybe up to 20 for this as otherwise too many map collisions occur. - See llvm_mode/README.ctx.md + See instrumentation/README.ctx.md ### CTX @@ -176,7 +192,7 @@ Then there are a few specific features that are only available in llvm_mode: config.h to at least 18 and maybe up to 20 for this as otherwise too many map collisions occur. - See llvm_mode/README.ngram.md + See instrumentation/README.ngram.md ### LAF-INTEL @@ -196,17 +212,17 @@ Then there are a few specific features that are only available in llvm_mode: - Setting AFL_LLVM_LAF_ALL sets all of the above - See llvm_mode/README.laf-intel.md for more information. + See instrumentation/README.laf-intel.md for more information. ### INSTRUMENT LIST (selectively instrument files and functions) - This feature allows selective instrumentation of the source + This feature allows selectively instrumentation of the source - Setting AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST with a filenames and/or function will only instrument (or skip) those files that match the names listed in the specified file. - See llvm_mode/README.instrument_list.md for more information. + See instrumentation/README.instrument_list.md for more information. ### NOT_ZERO @@ -220,27 +236,34 @@ Then there are a few specific features that are only available in llvm_mode: test. If the target performs only few loops then this will give a small performance boost. - See llvm_mode/README.neverzero.md + See instrumentation/README.neverzero.md ### CMPLOG - Setting AFL_LLVM_CMPLOG=1 during compilation will tell afl-clang-fast to - produce a CmpLog binary. See llvm_mode/README.cmplog.md + produce a CmpLog binary. See instrumentation/README.cmplog.md - See llvm_mode/README.neverzero.md + See instrumentation/README.neverzero.md -Then there are a few specific features that are only available in the gcc_plugin: +## 3) Settings for GCC / GCC_PLUGIN modes -### INSTRUMENT_FILE +Then there are a few specific features that are only available in GCC and +GCC_PLUGIN mode. - This feature allows selective instrumentation of the source + - Setting AFL_KEEP_ASSEMBLY prevents afl-as from deleting instrumented + assembly files. Useful for troubleshooting problems or understanding how + the tool works. (GCC mode only) + To get them in a predictable place, try something like: - - Setting AFL_GCC_INSTRUMENT_FILE with a filename will only instrument those - files that match the names listed in this file (one filename per line). + mkdir assembly_here + TMPDIR=$PWD/assembly_here AFL_KEEP_ASSEMBLY=1 make clean all + - Setting AFL_GCC_INSTRUMENT_FILE with a filename will only instrument those + files that match the names listed in this file (one filename per line). See gcc_plugin/README.instrument_list.md for more information. + (GCC_PLUGIN mode only) -## 3) Settings for afl-fuzz +## 4) Settings for afl-fuzz The main fuzzer binary accepts several options that disable a couple of sanity checks or alter some of the more exotic semantics of the tool: @@ -278,14 +301,6 @@ checks or alter some of the more exotic semantics of the tool: don't want AFL to spend too much time classifying that stuff and just rapidly put all timeouts in that bin. - - Setting AFL_FORKSRV_INIT_TMOUT allows yout to specify a different timeout - to wait for the forkserver to spin up. The default is the `-t` value times - `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the - default would wait `1000` milis. Setting a different time here is useful - if the target has a very slow startup time, for example when doing - full-system fuzzing or emulation, but you don't want the actual runs - to wait too long for timeouts. - - AFL_NO_ARITH causes AFL to skip most of the deterministic arithmetics. This can be useful to speed up the fuzzing of text-based file formats. @@ -377,22 +392,12 @@ checks or alter some of the more exotic semantics of the tool: Note that this setting inhibits some of the user-friendly diagnostics normally done when starting up the forkserver and causes a pretty significant performance drop. - - - Setting AFL_MAX_DET_EXTRAS changes the count of dictionary entries/extras - (default 200), after which the entries will be used probabilistically. - So, if the dict/extras file (`-x`) contains more tokens than this threshold, - not all of the tokens will be used in each fuzzing step, every time. - Instead, there is a chance that the entry will be skipped during fuzzing. - This makes sure that the fuzzer doesn't spend all its time only inserting - the extras, but will still do other mutations. However, it decreases the - likelihood for each token to be inserted, before the next queue entry is fuzzed. - Either way, all tokens will be used eventually, in a longer fuzzing campaign. - Outdated environment variables that are that not supported anymore: AFL_DEFER_FORKSRV AFL_PERSISTENT -## 4) Settings for afl-qemu-trace +## 5) Settings for afl-qemu-trace The QEMU wrapper used to instrument binary-only code supports several settings: @@ -446,7 +451,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings: stack pointer in which QEMU can find the return address when `start addr` is hitted. -## 5) Settings for afl-cmin +## 6) Settings for afl-cmin The corpus minimization script offers very little customization: @@ -472,12 +477,12 @@ to match when minimizing crashes. This will make minimization less useful, but may prevent the tool from "jumping" from one crashing condition to another in very buggy software. You probably want to combine it with the -e flag. -## 7) Settings for afl-analyze +## 8) Settings for afl-analyze You can set AFL_ANALYZE_HEX to get file offsets printed as hexadecimal instead of decimal. -## 8) Settings for libdislocator +## 9) Settings for libdislocator The library honors these environmental variables: @@ -499,12 +504,12 @@ The library honors these environmental variables: - AFL_ALIGNED_ALLOC=1 will force the alignment of the allocation size to max_align_t to be compliant with the C standard. -## 9) Settings for libtokencap +## 10) Settings for libtokencap This library accepts AFL_TOKEN_FILE to indicate the location to which the discovered tokens should be written. -## 10) Third-party variables set by afl-fuzz & other tools +## 11) Third-party variables set by afl-fuzz & other tools Several variables are not directly interpreted by afl-fuzz, but are set to optimal values if not already present in the environment: diff --git a/docs/ideas.md b/docs/ideas.md index 65e2e8e6..a5d40963 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -3,49 +3,6 @@ In the following, we describe a variety of ideas that could be implemented for future AFL++ versions. -For GSOC2020 interested students please see -[https://github.com/AFLplusplus/AFLplusplus/issues/208](https://github.com/AFLplusplus/AFLplusplus/issues/208) - -## Flexible Grammar Mutator (currently in development) - -Currently, AFL++'s mutation does not have deeper knowledge about the fuzzed -binary, apart from feedback, even though the developer may have insights -about the target. - -A developer may choose to provide dictionaries and implement own mutations -in python or C, but an easy mutator that behaves according to a given grammar, -does not exist. - -State-of-the-art research on grammar fuzzing has some problems in their -implementations like code quality, scalability, or ease of use and other -common issues of the academic code. - -We aim to develop a pluggable grammar mutator for afl++ that combines -various results. - -Mentor: andreafioraldi - -## perf-fuzz Linux Kernel Module - -Expand on [snapshot LKM](https://github.com/AFLplusplus/AFL-Snapshot-LKM) -To make it thread safe, can snapshot several processes at once and increase -overall performance. - -Mentor: any - -## QEMU 5-based Instrumentation - -First tests to use QEMU 4 for binary-only AFL++ showed that caching behavior -changed, which vastly decreases fuzzing speeds. - -In this task test if QEMU 5 performs better and port the afl++ QEMU 3.1 -patches to QEMU 5. - -Understanding the current instrumentation and fixing the current caching -issues will be needed. - -Mentor: andreafioraldi - ## WASM Instrumentation Currently, AFL++ can be used for source code fuzzing and traditional binaries. @@ -66,20 +23,6 @@ Either improve a single mutator thorugh learning of many different bugs Mentor: domenukk -## Reengineer `afl-fuzz` as Thread Safe, Embeddable Library (currently in development) - -Right now, afl-fuzz is single threaded, cannot safely be embedded in tools, -and not multi-threaded. It makes use of a large number of globals, must always -be the parent process and exec child processes. -Instead, afl-fuzz could be refactored to contain no global state and globals. -This allows for different use cases that could be implemented during this -project. -Note that in the mean time a lot has happened here already, but e.g. making -it all work and implement multithreading in afl-fuzz ... there is still quite -some work to do. - -Mentor: hexcoder- or vanhauser-thc - ## Collision-free Binary-Only Maps AFL++ supports collison-free maps using an LTO (link-time-optimization) pass. diff --git a/docs/life_pro_tips.md b/docs/life_pro_tips.md index a5bd7286..0004c297 100644 --- a/docs/life_pro_tips.md +++ b/docs/life_pro_tips.md @@ -30,10 +30,10 @@ Check out the `fuzzer_stats` file in the AFL output dir or try `afl-whatsup`. It could be important - consult docs/status_screen.md right away! ## Know your target? Convert it to persistent mode for a huge performance gain! -Consult section #5 in llvm_mode/README.md for tips. +Consult section #5 in README.llvm.md for tips. ## Using clang? -Check out llvm_mode/ for a faster alternative to afl-gcc! +Check out instrumentation/ for a faster alternative to afl-gcc! ## Did you know that AFL can fuzz closed-source or cross-platform binaries? Check out qemu_mode/README.md and unicorn_mode/README.md for more. diff --git a/docs/perf_tips.md b/docs/perf_tips.md index 731dc238..fbcb4d8d 100644 --- a/docs/perf_tips.md +++ b/docs/perf_tips.md @@ -51,7 +51,7 @@ a file. ## 3. Use LLVM instrumentation When fuzzing slow targets, you can gain 20-100% performance improvement by -using the LLVM-based instrumentation mode described in [the llvm_mode README](../llvm_mode/README.md). +using the LLVM-based instrumentation mode described in [the instrumentation README](../instrumentation/README.llvm.md). Note that this mode requires the use of clang and will not work with GCC. The LLVM mode also offers a "persistent", in-process fuzzing mode that can @@ -62,12 +62,12 @@ modes require you to edit the source code of the fuzzed program, but the changes often amount to just strategically placing a single line or two. If there are important data comparisons performed (e.g. `strcmp(ptr, MAGIC_HDR)`) -then using laf-intel (see llvm_mode/README.laf-intel.md) will help `afl-fuzz` a lot +then using laf-intel (see instrumentation/README.laf-intel.md) will help `afl-fuzz` a lot to get to the important parts in the code. If you are only interested in specific parts of the code being fuzzed, you can instrument_files the files that are actually relevant. This improves the speed and -accuracy of afl. See llvm_mode/README.instrument_list.md +accuracy of afl. See instrumentation/README.instrument_list.md Also use the InsTrim mode on larger binaries, this improves performance and coverage a lot. @@ -110,7 +110,7 @@ e.g.: https://launchpad.net/libeatmydata In programs that are slow due to unavoidable initialization overhead, you may -want to try the LLVM deferred forkserver mode (see llvm_mode/README.md), +want to try the LLVM deferred forkserver mode (see README.llvm.md), which can give you speed gains up to 10x, as mentioned above. Last but not least, if you are using ASAN and the performance is unacceptable, diff --git a/docs/sister_projects.md b/docs/sister_projects.md index a501ecbd..640e59f7 100644 --- a/docs/sister_projects.md +++ b/docs/sister_projects.md @@ -52,7 +52,7 @@ options. Provides an evolutionary instrumentation-guided fuzzing harness that allows some programs to be fuzzed without the fork / execve overhead. (Similar functionality is now available as the "persistent" feature described in -[the llvm_mode readme](../llvm_mode/README.md)) +[the llvm_mode readme](../instrumentation/README.llvm.md)) http://llvm.org/docs/LibFuzzer.html @@ -245,7 +245,7 @@ https://code.google.com/p/address-sanitizer/wiki/AsanCoverage#Coverage_counters ### AFL JS (Han Choongwoo) One-off optimizations to speed up the fuzzing of JavaScriptCore (now likely -superseded by LLVM deferred forkserver init - see llvm_mode/README.md). +superseded by LLVM deferred forkserver init - see README.llvm.md). https://github.com/tunz/afl-fuzz-js diff --git a/docs/status_screen.md b/docs/status_screen.md index b89468ce..2eeb8f3f 100644 --- a/docs/status_screen.md +++ b/docs/status_screen.md @@ -324,7 +324,7 @@ there are several things to look at: - Multiple threads executing at once in semi-random order. This is harmless when the 'stability' metric stays over 90% or so, but can become an issue if not. Here's what to try: - * Use afl-clang-fast from [llvm_mode](../llvm_mode/) - it uses a thread-local tracking + * Use afl-clang-fast from [instrumentation](../instrumentation/) - it uses a thread-local tracking model that is less prone to concurrency issues, * See if the target can be compiled or run without threads. Common `./configure` options include `--without-threads`, `--disable-pthreads`, or diff --git a/examples/README.md b/examples/README.md index d28aadbe..46a92c6e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -47,7 +47,7 @@ Here's a quick overview of the stuff you can find in this directory: Note that the minimize_corpus.sh tool has graduated from the examples/ directory and is now available as ../afl-cmin. The LLVM mode has likewise -graduated to ../llvm_mode/*. +graduated to ../instrumentation/*. Most of the tools in this directory are meant chiefly as examples that need to be tweaked for your specific needs. They come with some basic documentation, diff --git a/examples/aflpp_driver/aflpp_driver.c b/examples/aflpp_driver/aflpp_driver.c index ff5446e9..82e55fc4 100644 --- a/examples/aflpp_driver/aflpp_driver.c +++ b/examples/aflpp_driver/aflpp_driver.c @@ -27,7 +27,7 @@ EOF # Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang. clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c # Build afl-llvm-rt.o.c from the AFL distribution. -clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c +clang -c -w $AFL_HOME/instrumentation/afl-llvm-rt.o.c # Build this file, link it with afl-llvm-rt.o.o and the target code. clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o # Run AFL: diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 4281c554..9e469864 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -935,6 +935,7 @@ u8 has_new_bits(afl_state_t *, u8 *); void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32); void load_extras(afl_state_t *, u8 *); +void dedup_extras(afl_state_t *); void add_extra(afl_state_t *afl, u8 *mem, u32 len); void maybe_add_auto(afl_state_t *, u8 *, u32); void save_auto(afl_state_t *); @@ -972,7 +973,7 @@ u8 fuzz_one(afl_state_t *); void bind_to_free_cpu(afl_state_t *); #endif void setup_post(afl_state_t *); -void read_testcases(afl_state_t *); +void read_testcases(afl_state_t *, u8 *); void perform_dry_run(afl_state_t *); void pivot_inputs(afl_state_t *); u32 find_start_position(afl_state_t *); diff --git a/include/config.h b/include/config.h index 77407d50..8cc70075 100644 --- a/include/config.h +++ b/include/config.h @@ -28,7 +28,7 @@ /* Version string: */ // c = release, d = volatile github dev, e = experimental branch -#define VERSION "++2.68c" +#define VERSION "++3.00a" /****************************************************** * * @@ -195,7 +195,7 @@ steps; past this point, the "extras/user" step will be still carried out, but with proportionally lower odds: */ -#define MAX_DET_EXTRAS 200 +#define MAX_DET_EXTRAS 256 /* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing (first value), and to keep in memory as candidates. The latter should be much diff --git a/include/envs.h b/include/envs.h index 2dc1dbbf..d9968fcd 100644 --- a/include/envs.h +++ b/include/envs.h @@ -69,6 +69,7 @@ static char *afl_environment_variables[] = { "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LLVM_CTX", + "AFL_LLVM_DICT2FILE", "AFL_LLVM_DOCUMENT_IDS", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD", diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 63b7581d..0e38f38b 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -466,7 +466,7 @@ void afl_forkserver(CPUState *cpu) { } /* A simplified persistent mode handler, used as explained in - * llvm_mode/README.md. */ + * instrumentation/README.llvm.md */ void afl_persistent_loop(void) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 713849a1..1351d274 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -626,6 +626,7 @@ if (dir == NULL) { if (!access(fn1, F_OK)) { afl->in_dir = fn1; + subdirs = 0; } else { @@ -1063,7 +1064,7 @@ restart_outer_cull_loop: } - afl->q_prev100 = afl->queue = afl->queue_top = afl->queue; + afl->queue = afl->queue_top = afl->queue; } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index db91813b..af52aa45 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -138,8 +138,7 @@ static u8 check_if_text(struct queue_entry *q) { } // non-overlong 2-byte - if (len - offset > 1 && - ((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) && + if (len - offset > 1 && ((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) && (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) { offset += 2; @@ -230,7 +229,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { } else { - afl->q_prev100 = afl->queue = afl->queue_top = q; + afl->queue = afl->queue_top = q; } @@ -274,15 +273,15 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { void destroy_queue(afl_state_t *afl) { - struct queue_entry *q = afl->queue, *n; + struct queue_entry *q; + u32 i; - while (q) { + for (i = 0; i < afl->queued_paths; i++) { - n = q->next; + q = afl->queue_buf[i]; ck_free(q->fname); ck_free(q->trace_mini); ck_free(q); - q = n; } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 51eed14b..c60c65aa 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -982,10 +982,9 @@ void show_stats(afl_state_t *afl) { void show_init_stats(afl_state_t *afl) { struct queue_entry *q = afl->queue; - u32 min_bits = 0, max_bits = 0; + u32 min_bits = 0, max_bits = 0, max_len = 0, count = 0; u64 min_us = 0, max_us = 0; u64 avg_us = 0; - u32 max_len = 0; u8 val_bufs[4][STRINGIFY_VAL_SIZE_MAX]; #define IB(i) val_bufs[(i)], sizeof(val_bufs[(i)]) @@ -1006,6 +1005,7 @@ void show_init_stats(afl_state_t *afl) { if (q->len > max_len) { max_len = q->len; } + ++count; q = q->next; } @@ -1072,10 +1072,10 @@ void show_init_stats(afl_state_t *afl) { OKF("Here are some useful stats:\n\n" cGRA " Test case count : " cRST - "%u favored, %u variable, %u total\n" cGRA " Bitmap range : " cRST + "%u favored, %u variable, %u ignored, %u total\n" cGRA " Bitmap range : " cRST "%u to %u bits (average: %0.02f bits)\n" cGRA " Exec timing : " cRST "%s to %s us (average: %s us)\n", - afl->queued_favored, afl->queued_variable, afl->queued_paths, min_bits, + afl->queued_favored, afl->queued_variable, afl->queued_paths - count, afl->queued_paths, min_bits, max_bits, ((double)afl->total_bitmap_size) / (afl->total_bitmap_entries ? afl->total_bitmap_entries : 1), diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index bfaa22e8..73ca6aaa 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1133,8 +1133,9 @@ int main(int argc, char **argv_orig, char **envp) { setup_cmdline_file(afl, argv + optind); - read_testcases(afl); + read_testcases(afl, NULL); // read_foreign_testcases(afl, 1); for the moment dont do this + OKF("Loaded a total of %u seeds.", afl->queued_paths); load_auto(afl); diff --git a/test/test-gcc-plugin.sh b/test/test-gcc-plugin.sh index 2ed10a72..8b8cbd8e 100755 --- a/test/test-gcc-plugin.sh +++ b/test/test-gcc-plugin.sh @@ -3,7 +3,7 @@ . ./test-pre.sh $ECHO "$BLUE[*] Testing: gcc_plugin" -test -e ../afl-gcc-fast -a -e ../afl-gcc-rt.o && { +test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && { SAVE_AFL_CC=${AFL_CC} export AFL_CC=`command -v gcc` ../afl-gcc-fast -o test-instr.plain.gccpi ../test-instr.c > /dev/null 2>&1 diff --git a/test/test-unittests.sh b/test/test-unittests.sh index f540b5f8..58c2eea9 100755 --- a/test/test-unittests.sh +++ b/test/test-unittests.sh @@ -7,3 +7,5 @@ unset AFL_CC make -C .. unit || CODE=1 INCOMPLETE=1 : . ./test-post.sh + +rm -rf unittests/unit_hash unittests/unit_rand -- cgit 1.4.1 From 59815cd4473bdf6568e0eee673d49d6236132b41 Mon Sep 17 00:00:00 2001 From: Edznux Date: Sun, 11 Oct 2020 23:06:37 +0200 Subject: Add documentation for StatsD --- docs/env_variables.md | 8 ++++++++ docs/status_screen.md | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index 9d289f6d..ebb7521e 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -393,6 +393,14 @@ checks or alter some of the more exotic semantics of the tool: normally done when starting up the forkserver and causes a pretty significant performance drop. + - Setting AFL_STATSD enable StatsD metrics collection. + By default AFL will send these metrics over UDP to 127.0.0.1:8125. + The host and port are configurable with AFL_STATSD_HOST and AFL_STATSD_PORT + respectively. + To get the most out of this, you should provide AFL_STATSD_TAGS_FLAVOR that + matches your StatsD server. + Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`. + - Outdated environment variables that are that not supported anymore: AFL_DEFER_FORKSRV AFL_PERSISTENT diff --git a/docs/status_screen.md b/docs/status_screen.md index f7655bf4..0cede6ff 100644 --- a/docs/status_screen.md +++ b/docs/status_screen.md @@ -406,3 +406,27 @@ Most of these map directly to the UI elements discussed earlier on. On top of that, you can also find an entry called `plot_data`, containing a plottable history for most of these fields. If you have gnuplot installed, you can turn this into a nice progress report with the included `afl-plot` tool. + + +### Addendum: Automatically send metrics with StatsD + +In a CI environment or when running multiple fuzzers, it can be tedious to +log into each of them or deploy scripts to read the fuzzer statistics. +Using `AFL_STATSD` (and the other related environment variables `AFL_STATSD_HOST`, +`AFL_STATSD_PORT`, `AFL_STATSD_TAGS_FLAVOR`) you can automatically send metrics +to your favorite StatsD server. Depending on your StatsD server you will be able +to monitor, trigger alerts or perform actions based on these metrics (e.g: alert on +slow exec/s for a new build, threshold of crashes, time since last crash > X, etc). + +The selected metrics are a subset of all the metrics found in the status and in +the plot file. The list is the following: `cycle_done`, `cycles_wo_finds`, +`execs_done`,`execs_per_sec`, `paths_total`, `paths_favored`, `paths_found`, +`paths_imported`, `max_depth`, `cur_path`, `pending_favs`, `pending_total`, +`variable_paths`, `unique_crashes`, `unique_hangs`, `total_crashes`, +`slowest_exec_ms`, `edges_found`, `var_byte_count`, `havoc_expansion`. +Their definitions can be found in the addendum above. + +When using multiple fuzzer instances with StatsD it is *strongly* recommended to setup +the flavor (AFL_STATSD_TAGS_FLAVOR) to match your StatsD server. This will allow you +to see individual fuzzer performance, detect bad ones, see the progress of each +strategy... -- cgit 1.4.1 From 23872d6f2c0ae77beb832f44d392f86cc8530e1a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 14 Oct 2020 16:38:29 +0200 Subject: add documentation --- README.md | 12 ++++++++++-- docs/env_variables.md | 4 ++++ include/afl-fuzz.h | 4 ++++ 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'docs/env_variables.md') diff --git a/README.md b/README.md index 384ae830..c7793dff 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,9 @@ behaviours and defaults: * -m none is now default, set memory limits (in MB) with e.g. -m 250 * deterministic fuzzing is now disabled by default (unless using -M) and can be enabled with -D + * a caching of testcases can now be performed and can be enabled by + editing config.h for TESTCASE_CACHE or by specifying the env variable + `AFL_TESTCACHE_SIZE` (in MB). Good values are between 50-500. ## Contents @@ -555,7 +558,7 @@ is: All labels are explained in [docs/status_screen.md](docs/status_screen.md). -#### b) Using multiple cores/threads +#### b) Using multiple cores If you want to seriously fuzz then use as many cores/threads as possible to fuzz your target. @@ -563,7 +566,12 @@ fuzz your target. On the same machine - due to the design of how afl++ works - there is a maximum number of CPU cores/threads that are useful, use more and the overall performance degrades instead. This value depends on the target, and the limit is between 32 -and 64 cores/threads per machine. +and 64 cores per machine. + +If you have the RAM, it is highly recommended run the instances with a caching +of the testcases. Depending on the average testcase size (and those found +during fuzzing) and their number, a value between 50-500MB is recommended. +You can set the cache size (in MB) by setting the environment variable `AFL_TESTCACHE_SIZE`. There should be one main fuzzer (`-M main` option) and as many secondary fuzzers (eg `-S variant1`) as you have cores that you use. diff --git a/docs/env_variables.md b/docs/env_variables.md index ebb7521e..49eadcaa 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -282,6 +282,10 @@ checks or alter some of the more exotic semantics of the tool: the target. This must be equal or larger than the size the target was compiled with. + - AFL_TESTCACHE_SIZE allows you to overrider the define in config.h for + TESTCASE_CACHE. Recommended values are 50-250MB - or more if your + fuzzing finds a huge amount of paths for large inputs. + - Setting AFL_DISABLE_TRIM tells afl-fuzz to no trim test cases. This is usually a bad idea! diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 940c5602..514d558b 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1164,5 +1164,9 @@ u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q); void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, u32 old_len); +#if TESTCASE_CACHE == 1 +#error define of TESTCASE_CACHE must be zero or larger than 1 +#endif + #endif -- cgit 1.4.1 From dfb847a51bb3dbcbe6237e92fa385b8c6c6c417c Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 30 Oct 2020 14:37:06 +0100 Subject: review, mark env variables, linkify --- docs/env_variables.md | 359 +++++++++++++++++++++++++------------------------- 1 file changed, 180 insertions(+), 179 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index 49eadcaa..a36f2b4e 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -2,63 +2,64 @@ This document discusses the environment variables used by American Fuzzy Lop++ to expose various exotic functions that may be (rarely) useful for power - users or for some types of custom fuzzing setups. See README.md for the general + users or for some types of custom fuzzing setups. See [README.md](README.md) for the general instruction manual. ## 1) Settings for all compilers Starting with afl++ 3.0 there is only one compiler: afl-cc To select the different instrumentation modes this can be done by - 1. passing --afl-MODE command line options to the compiler - 2. use a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++, + 1. passing the --afl-MODE command line option to the compiler + 2. or using a symlink to afl-cc: afl-gcc, afl-g++, afl-clang, afl-clang++, afl-clang-fast, afl-clang-fast++, afl-clang-lto, afl-clang-lto++, afl-gcc-fast, afl-g++-fast - 3. using the environment variable AFL_CC_COMPILER with MODE + 3. or using the environment variable `AFL_CC_COMPILER` with `MODE` -MODE can one of LTO (afl-clang-lto*), LLVM (afl-clang-fast*), GCC_PLUGIN -(afl-g*-fast) or GCC (afl-gcc/afl-g++). +`MODE` can be one of `LTO` (afl-clang-lto*), `LLVM` (afl-clang-fast*), `GCC_PLUGIN` +(afl-g*-fast) or `GCC` (afl-gcc/afl-g++). -Because beside the --afl-MODE command no afl specific command-line options -are accepted, the compile-time tools make fairly broad use of environmental -variables: - - Most afl tools do not print any ouput if stout/stderr are redirected. - If you want to have the output into a file then set the AFL_DEBUG +Because (with the exception of the --afl-MODE command line option) the +compile-time tools do not accept afl specific command-line options, they +make fairly broad use of environmental variables instead: + + - Most afl tools do not print any output if stdout/stderr are redirected. + If you want to get the output into a file then set the `AFL_DEBUG` environment variable. This is sadly necessary for various build processes which fail otherwise. - - Setting AFL_HARDEN automatically adds code hardening options when invoking - the downstream compiler. This currently includes -D_FORTIFY_SOURCE=2 and - -fstack-protector-all. The setting is useful for catching non-crashing + - Setting `AFL_HARDEN` automatically adds code hardening options when invoking + the downstream compiler. This currently includes `-D_FORTIFY_SOURCE=2` and + `-fstack-protector-all`. The setting is useful for catching non-crashing memory bugs at the expense of a very slight (sub-5%) performance loss. - - By default, the wrapper appends -O3 to optimize builds. Very rarely, this - will cause problems in programs built with -Werror, simply because -O3 + - By default, the wrapper appends `-O3` to optimize builds. Very rarely, this + will cause problems in programs built with -Werror, simply because `-O3` enables more thorough code analysis and can spew out additional warnings. - To disable optimizations, set AFL_DONT_OPTIMIZE. - However if -O... and/or -fno-unroll-loops are set, these are not - overriden. + To disable optimizations, set `AFL_DONT_OPTIMIZE`. + However if `-O...` and/or `-fno-unroll-loops` are set, these are not + overridden. - - Setting AFL_USE_ASAN automatically enables ASAN, provided that your + - Setting `AFL_USE_ASAN` automatically enables ASAN, provided that your compiler supports that. Note that fuzzing with ASAN is mildly challenging - see [notes_for_asan.md](notes_for_asan.md). - (You can also enable MSAN via AFL_USE_MSAN; ASAN and MSAN come with the + (You can also enable MSAN via `AFL_USE_MSAN`; ASAN and MSAN come with the same gotchas; the modes are mutually exclusive. UBSAN can be enabled - similarly by setting the environment variable AFL_USE_UBSAN=1. Finally + similarly by setting the environment variable `AFL_USE_UBSAN=1`. Finally there is the Control Flow Integrity sanitizer that can be activated by - AFL_USE_CFISAN=1) + `AFL_USE_CFISAN=1`) - - Setting AFL_CC, AFL_CXX, and AFL_AS lets you use alternate downstream + - Setting `AFL_CC`, `AFL_CXX`, and `AFL_AS` lets you use alternate downstream compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries - in your $PATH. + in your `$PATH`. - - AFL_PATH can be used to point afl-gcc to an alternate location of afl-as. + - `AFL_PATH` can be used to point afl-gcc to an alternate location of afl-as. One possible use of this is examples/clang_asm_normalize/, which lets you instrument hand-written assembly when compiling clang code by plugging a normalizer into the chain. (There is no equivalent feature for GCC.) - - Setting AFL_INST_RATIO to a percentage between 0 and 100% controls the + - Setting `AFL_INST_RATIO` to a percentage between 0 and 100 controls the probability of instrumenting every branch. This is (very rarely) useful when dealing with exceptionally complex programs that saturate the output bitmap. Examples include v8, ffmpeg, and perl. @@ -66,51 +67,51 @@ variables: (If this ever happens, afl-fuzz will warn you ahead of the time by displaying the "bitmap density" field in fiery red.) - Setting AFL_INST_RATIO to 0 is a valid choice. This will instrument only + Setting `AFL_INST_RATIO` to 0 is a valid choice. This will instrument only the transitions between function entry points, but not individual branches. Note that this is an outdated variable. A few instances (e.g. afl-gcc) still support these, but state-of-the-art (e.g. LLVM LTO and LLVM PCGUARD) do not need this. - - AFL_NO_BUILTIN causes the compiler to generate code suitable for use with + - `AFL_NO_BUILTIN` causes the compiler to generate code suitable for use with libtokencap.so (but perhaps running a bit slower than without the flag). - - TMPDIR is used by afl-as for temporary files; if this variable is not set, + - `TMPDIR` is used by afl-as for temporary files; if this variable is not set, the tool defaults to /tmp. - If you are a weird person that wants to compile and instrument asm - text files then use the AFL_AS_FORCE_INSTRUMENT variable: - AFL_AS_FORCE_INSTRUMENT=1 afl-gcc foo.s -o foo + text files then use the `AFL_AS_FORCE_INSTRUMENT` variable: + `AFL_AS_FORCE_INSTRUMENT=1 afl-gcc foo.s -o foo` - - Setting AFL_QUIET will prevent afl-cc and afl-as banners from being + - Setting `AFL_QUIET` will prevent afl-cc and afl-as banners from being displayed during compilation, in case you find them distracting. - - Setting AFL_CAL_FAST will speed up the initial calibration, if the - application is very slow + - Setting `AFL_CAL_FAST` will speed up the initial calibration, if the + application is very slow. ## 2) Settings for LLVM and LTO: afl-clang-fast / afl-clang-fast++ / afl-clang-lto / afl-clang-lto++ The native instrumentation helpers (instrumentation and gcc_plugin) accept a subset -of the settings discussed in section #1, with the exception of: +of the settings discussed in section 1, with the exception of: - LLVM modes support `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` which will - write all constant string comparisons to this file to be used with + write all constant string comparisons to this file to be used later with afl-fuzz' `-x` option. - - AFL_AS, since this toolchain does not directly invoke GNU as. + - `AFL_AS`, since this toolchain does not directly invoke GNU as. - - TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are + - `TMPDIR` and `AFL_KEEP_ASSEMBLY`, since no temporary assembly files are created. - - AFL_INST_RATIO, as we by default collision free instrumentation is used. + - `AFL_INST_RATIO`, as we by default use collision free instrumentation. Not all passes support this option though as it is an outdated feature. -Then there are a few specific features that are only available in instrumentation: +Then there are a few specific features that are only available in instrumentation mode: ### Select the instrumentation mode - - AFL_LLVM_INSTRUMENT - this configures the instrumentation mode. + - `AFL_LLVM_INSTRUMENT` - this configures the instrumentation mode. Available options: CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default) CFG - InsTrim instrumentation (see below) @@ -119,148 +120,148 @@ Then there are a few specific features that are only available in instrumentatio NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16) In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or NGRAM, seperate the options with a comma "," then, e.g.: - AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4 + `AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4` Not that this is a good idea to use both CTX and NGRAM :) ### LTO - This is a different kind way of instrumentation: first it compiles all + This is a different kind way of instrumentation: first it compiles all code in LTO (link time optimization) and then performs an edge inserting instrumentation which is 100% collision free (collisions are a big issue in afl and afl-like instrumentations). This is performed by using afl-clang-lto/afl-clang-lto++ instead of afl-clang-fast, but is only built if LLVM 11 or newer is used. - - AFL_LLVM_INSTRUMENT=CFG will use Control Flow Graph instrumentation. + - `AFL_LLVM_INSTRUMENT=CFG` will use Control Flow Graph instrumentation. (not recommended for afl-clang-fast, default for afl-clang-lto as there it is a different and better kind of instrumentation.) - None of the following options are necessary to be used and are rather for + None of the following options are necessary to be used and are rather for manual use (which only ever the author of this LTO implementation will use). - These are used if several seperated instrumentation are performed which + These are used if several separated instrumentations are performed which are then later combined. - - AFL_LLVM_DOCUMENT_IDS=file will document to a file which edge ID was given + - `AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge ID was given to which function. This helps to identify functions with variable bytes or which functions were touched by an input. - - AFL_LLVM_MAP_ADDR sets the fixed map address to a different address than - the default 0x10000. A value of 0 or empty sets the map address to be + - `AFL_LLVM_MAP_ADDR` sets the fixed map address to a different address than + the default `0x10000`. A value of 0 or empty sets the map address to be dynamic (the original afl way, which is slower) - - AFL_LLVM_MAP_DYNAMIC sets the shared memory address to be dynamic - - AFL_LLVM_LTO_STARTID sets the starting location ID for the instrumentation. + - `AFL_LLVM_MAP_DYNAMIC` sets the shared memory address to be dynamic + - `AFL_LLVM_LTO_STARTID` sets the starting location ID for the instrumentation. This defaults to 1 - - AFL_LLVM_LTO_DONTWRITEID prevents that the highest location ID written + - `AFL_LLVM_LTO_DONTWRITEID` prevents that the highest location ID written into the instrumentation is set in a global variable - See instrumentation/README.LTO.md for more information. + See [instrumentation/README.lto.md](../instrumentation/README.lto.md) for more information. ### INSTRIM - This feature increases the speed by ~15% without any disadvantages to the + This feature increases the speed by ~15% without any disadvantages to the classic instrumentation. - Note that there is also an LTO version (if you have llvm 11 or higher) - + Note that there is also an LTO version (if you have llvm 11 or higher) - that is the best instrumentation we have. Use `afl-clang-lto` to activate. The InsTrim LTO version additionally has all the options and features of LTO (see above). - - Setting AFL_LLVM_INSTRIM or AFL_LLVM_INSTRUMENT=CFG to activates this mode + - Setting `AFL_LLVM_INSTRIM` or `AFL_LLVM_INSTRUMENT=CFG` activates this mode - - Setting AFL_LLVM_INSTRIM_LOOPHEAD=1 expands on INSTRIM to optimize loops. + - Setting `AFL_LLVM_INSTRIM_LOOPHEAD=1` expands on INSTRIM to optimize loops. afl-fuzz will only be able to see the path the loop took, but not how many times it was called (unless it is a complex loop). - See instrumentation/README.instrim.md + See [instrumentation/README.instrim.md](../instrumentation/README.instrim.md) ### NGRAM - - Setting AFL_LLVM_NGRAM_SIZE or AFL_LLVM_INSTRUMENT=NGRAM-{value} + - Setting `AFL_LLVM_NGRAM_SIZE` or `AFL_LLVM_INSTRUMENT=NGRAM-{value}` activates ngram prev_loc coverage, good values are 2, 4 or 8 (any value between 2 and 16 is valid). - It is highly recommended to increase the MAP_SIZE_POW2 definition in + It is highly recommended to increase the `MAP_SIZE_POW2` definition in config.h to at least 18 and maybe up to 20 for this as otherwise too many map collisions occur. - See instrumentation/README.ctx.md + See [instrumentation/README.ngram.md](../instrumentation/README.ngram.md) ### CTX - - Setting AFL_LLVM_CTX or AFL_LLVM_INSTRUMENT=CTX + - Setting `AFL_LLVM_CTX` or `AFL_LLVM_INSTRUMENT=CTX` activates context sensitive branch coverage - meaning that each edge is additionally combined with its caller. - It is highly recommended to increase the MAP_SIZE_POW2 definition in + It is highly recommended to increase the `MAP_SIZE_POW2` definition in config.h to at least 18 and maybe up to 20 for this as otherwise too many map collisions occur. - See instrumentation/README.ngram.md + See [instrumentation/README.ctx.md](../instrumentation/README.ctx.md) ### LAF-INTEL - This great feature will split compares to series of single byte comparisons + This great feature will split compares into series of single byte comparisons to allow afl-fuzz to find otherwise rather impossible paths. It is not restricted to Intel CPUs ;-) - - Setting AFL_LLVM_LAF_TRANSFORM_COMPARES will split string compare functions + - Setting `AFL_LLVM_LAF_TRANSFORM_COMPARES` will split string compare functions - - Setting AFL_LLVM_LAF_SPLIT_SWITCHES will split switch()es + - Setting `AFL_LLVM_LAF_SPLIT_SWITCHES` will split all `switch` constructs - - Setting AFL_LLVM_LAF_SPLIT_COMPARES will split all floating point and + - Setting `AFL_LLVM_LAF_SPLIT_COMPARES` will split all floating point and 64, 32 and 16 bit integer CMP instructions - - Setting AFL_LLVM_LAF_SPLIT_FLOATS will split floating points, needs + - Setting `AFL_LLVM_LAF_SPLIT_FLOATS` will split floating points, needs AFL_LLVM_LAF_SPLIT_COMPARES to be set - - Setting AFL_LLVM_LAF_ALL sets all of the above + - Setting `AFL_LLVM_LAF_ALL` sets all of the above - See instrumentation/README.laf-intel.md for more information. + See [instrumentation/README.laf-intel.md](../instrumentation/README.laf-intel.md) for more information. ### INSTRUMENT LIST (selectively instrument files and functions) - This feature allows selectively instrumentation of the source + This feature allows selective instrumentation of the source - - Setting AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST with a filenames and/or + - Setting `AFL_LLVM_ALLOWLIST` or `AFL_LLVM_DENYLIST` with a filenames and/or function will only instrument (or skip) those files that match the names listed in the specified file. - See instrumentation/README.instrument_list.md for more information. + See [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) for more information. ### NOT_ZERO - - Setting AFL_LLVM_NOT_ZERO=1 during compilation will use counters + - Setting `AFL_LLVM_NOT_ZERO=1` during compilation will use counters that skip zero on overflow. This is the default for llvm >= 9, however for llvm versions below that this will increase an unnecessary slowdown due a performance issue that is only fixed in llvm 9+. This feature increases path discovery by a little bit. - - Setting AFL_LLVM_SKIP_NEVERZERO=1 will not implement the skip zero + - Setting `AFL_LLVM_SKIP_NEVERZERO=1` will not implement the skip zero test. If the target performs only few loops then this will give a small performance boost. - See instrumentation/README.neverzero.md + See [instrumentation/README.neverzero.md](../instrumentation/README.neverzero.md) ### CMPLOG - - Setting AFL_LLVM_CMPLOG=1 during compilation will tell afl-clang-fast to - produce a CmpLog binary. See instrumentation/README.cmplog.md + - Setting `AFL_LLVM_CMPLOG=1` during compilation will tell afl-clang-fast to + produce a CmpLog binary. - See instrumentation/README.neverzero.md + See [instrumentation/README.cmplog.md](../instrumentation/README.cmplog.md) ## 3) Settings for GCC / GCC_PLUGIN modes Then there are a few specific features that are only available in GCC and GCC_PLUGIN mode. - - Setting AFL_KEEP_ASSEMBLY prevents afl-as from deleting instrumented + - Setting `AFL_KEEP_ASSEMBLY` prevents afl-as from deleting instrumented assembly files. Useful for troubleshooting problems or understanding how the tool works. (GCC mode only) To get them in a predictable place, try something like: - +``` mkdir assembly_here TMPDIR=$PWD/assembly_here AFL_KEEP_ASSEMBLY=1 make clean all - - - Setting AFL_GCC_INSTRUMENT_FILE with a filename will only instrument those +``` + - Setting `AFL_GCC_INSTRUMENT_FILE` with a filename will only instrument those files that match the names listed in this file (one filename per line). - See gcc_plugin/README.instrument_list.md for more information. + See [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) for more information. (GCC_PLUGIN mode only) ## 4) Settings for afl-fuzz @@ -268,127 +269,127 @@ GCC_PLUGIN mode. The main fuzzer binary accepts several options that disable a couple of sanity checks or alter some of the more exotic semantics of the tool: - - Setting AFL_SKIP_CPUFREQ skips the check for CPU scaling policy. This is + - Setting `AFL_SKIP_CPUFREQ` skips the check for CPU scaling policy. This is useful if you can't change the defaults (e.g., no root access to the system) and are OK with some performance loss. - - AFL_EXIT_WHEN_DONE causes afl-fuzz to terminate when all existing paths + - `AFL_EXIT_WHEN_DONE` causes afl-fuzz to terminate when all existing paths have been fuzzed and there were no new finds for a while. This would be normally indicated by the cycle counter in the UI turning green. May be convenient for some types of automated jobs. - - AFL_MAP_SIZE sets the size of the shared map that afl-fuzz, afl-showmap, + - `AFL_MAP_SIZE` sets the size of the shared map that afl-fuzz, afl-showmap, afl-tmin and afl-analyze create to gather instrumentation data from the target. This must be equal or larger than the size the target was compiled with. - - AFL_TESTCACHE_SIZE allows you to overrider the define in config.h for - TESTCASE_CACHE. Recommended values are 50-250MB - or more if your - fuzzing finds a huge amount of paths for large inputs. + - `AFL_TESTCACHE_SIZE` allows you to override the size of `#define TESTCASE_CACHE` + in config.h. Recommended values are 50-250MB - or more if your fuzzing + finds a huge amount of paths for large inputs. - - Setting AFL_DISABLE_TRIM tells afl-fuzz to no trim test cases. This is + - Setting `AFL_DISABLE_TRIM` tells afl-fuzz not to trim test cases. This is usually a bad idea! - - Setting AFL_NO_AFFINITY disables attempts to bind to a specific CPU core + - Setting `AFL_NO_AFFINITY` disables attempts to bind to a specific CPU core on Linux systems. This slows things down, but lets you run more instances of afl-fuzz than would be prudent (if you really want to). - - AFL_SKIP_CRASHES causes AFL to tolerate crashing files in the input + - `AFL_SKIP_CRASHES` causes AFL++ to tolerate crashing files in the input queue. This can help with rare situations where a program crashes only intermittently, but it's not really recommended under normal operating conditions. - - Setting AFL_HANG_TMOUT allows you to specify a different timeout for + - Setting `AFL_HANG_TMOUT` allows you to specify a different timeout for deciding if a particular test case is a "hang". The default is 1 second - or the value of the -t parameter, whichever is larger. Dialing the value + or the value of the `-t` parameter, whichever is larger. Dialing the value down can be useful if you are very concerned about slow inputs, or if you - don't want AFL to spend too much time classifying that stuff and just + don't want AFL++ to spend too much time classifying that stuff and just rapidly put all timeouts in that bin. - - AFL_NO_ARITH causes AFL to skip most of the deterministic arithmetics. + - `AFL_NO_ARITH` causes AFL++ to skip most of the deterministic arithmetics. This can be useful to speed up the fuzzing of text-based file formats. - - AFL_NO_SNAPSHOT will advice afl-fuzz not to use the snapshot feature + - `AFL_NO_SNAPSHOT` will advice afl-fuzz not to use the snapshot feature if the snapshot lkm is loaded - - AFL_SHUFFLE_QUEUE randomly reorders the input queue on startup. Requested + - `AFL_SHUFFLE_QUEUE` randomly reorders the input queue on startup. Requested by some users for unorthodox parallelized fuzzing setups, but not advisable otherwise. - - AFL_TMPDIR is used to write the .cur_input file to if exists, and in + - `AFL_TMPDIR` is used to write the `.cur_input` file to if exists, and in the normal output directory otherwise. You would use this to point to a ramdisk/tmpfs. This increases the speed by a small value but also reduces the stress on SSDs. - When developing custom instrumentation on top of afl-fuzz, you can use - AFL_SKIP_BIN_CHECK to inhibit the checks for non-instrumented binaries - and shell scripts; and AFL_DUMB_FORKSRV in conjunction with the -n + `AFL_SKIP_BIN_CHECK` to inhibit the checks for non-instrumented binaries + and shell scripts; and `AFL_DUMB_FORKSRV` in conjunction with the `-n` setting to instruct afl-fuzz to still follow the fork server protocol without expecting any instrumentation data in return. - - When running in the -M or -S mode, setting AFL_IMPORT_FIRST causes the + - When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the fuzzer to import test cases from other instances before doing anything else. This makes the "own finds" counter in the UI more accurate. Beyond counter aesthetics, not much else should change. - - Note that AFL_POST_LIBRARY is deprecated, use AFL_CUSTOM_MUTATOR_LIBRARY + - Note that `AFL_POST_LIBRARY` is deprecated, use `AFL_CUSTOM_MUTATOR_LIBRARY` instead (see below). - - Setting AFL_CUSTOM_MUTATOR_LIBRARY to a shared library with + - Setting `AFL_CUSTOM_MUTATOR_LIBRARY` to a shared library with afl_custom_fuzz() creates additional mutations through this library. If afl-fuzz is compiled with Python (which is autodetected during builing - afl-fuzz), setting AFL_PYTHON_MODULE to a Python module can also provide + afl-fuzz), setting `AFL_PYTHON_MODULE` to a Python module can also provide additional mutations. - If AFL_CUSTOM_MUTATOR_ONLY is also set, all mutations will solely be + If `AFL_CUSTOM_MUTATOR_ONLY` is also set, all mutations will solely be performed with the custom mutator. This feature allows to configure custom mutators which can be very helpful, e.g. fuzzing XML or other highly flexible structured input. Please see [custom_mutators.md](custom_mutators.md). - - AFL_FAST_CAL keeps the calibration stage about 2.5x faster (albeit less + - `AFL_FAST_CAL` keeps the calibration stage about 2.5x faster (albeit less precise), which can help when starting a session against a slow target. - The CPU widget shown at the bottom of the screen is fairly simplistic and may complain of high load prematurely, especially on systems with low core - counts. To avoid the alarming red color, you can set AFL_NO_CPU_RED. + counts. To avoid the alarming red color, you can set `AFL_NO_CPU_RED`. - - In QEMU mode (-Q), AFL_PATH will be searched for afl-qemu-trace. + - In QEMU mode (-Q), `AFL_PATH` will be searched for afl-qemu-trace. - - Setting AFL_CYCLE_SCHEDULES will switch to a different schedule everytime + - Setting `AFL_CYCLE_SCHEDULES` will switch to a different schedule everytime a cycle is finished. - - Setting AFL_EXPAND_HAVOC_NOW will start in the extended havoc mode that + - Setting `AFL_EXPAND_HAVOC_NOW` will start in the extended havoc mode that includes costly mutations. afl-fuzz automatically enables this mode when deemed useful otherwise. - - Setting AFL_PRELOAD causes AFL to set LD_PRELOAD for the target binary + - Setting `AFL_PRELOAD` causes AFL++ to set `LD_PRELOAD` for the target binary without disrupting the afl-fuzz process itself. This is useful, among other things, for bootstrapping libdislocator.so. - - Setting AFL_NO_UI inhibits the UI altogether, and just periodically prints + - Setting `AFL_NO_UI` inhibits the UI altogether, and just periodically prints some basic stats. This behavior is also automatically triggered when the output from afl-fuzz is redirected to a file or to a pipe. - - Setting AFL_FORCE_UI will force painting the UI on the screen even if + - Setting `AFL_FORCE_UI` will force painting the UI on the screen even if no valid terminal was detected (for virtual consoles) - - If you are Jakub, you may need AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES. + - If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`. Others need not apply. - - Benchmarking only: AFL_BENCH_JUST_ONE causes the fuzzer to exit after - processing the first queue entry; and AFL_BENCH_UNTIL_CRASH causes it to + - Benchmarking only: `AFL_BENCH_JUST_ONE` causes the fuzzer to exit after + processing the first queue entry; and `AFL_BENCH_UNTIL_CRASH` causes it to exit soon after the first crash is found. - - Setting AFL_DEBUG_CHILD_OUTPUT will not suppress the child output. + - Setting `AFL_DEBUG_CHILD_OUTPUT` will not suppress the child output. Not pretty but good for debugging purposes. - - Setting AFL_NO_CPU_RED will not display very high cpu usages in red color. + - Setting `AFL_NO_CPU_RED` will not display very high cpu usages in red color. - - Setting AFL_AUTORESUME will resume a fuzz run (same as providing `-i -`) + - Setting `AFL_AUTORESUME` will resume a fuzz run (same as providing `-i -`) for an existing out folder, even if a different `-i` was provided. Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir. - - Setting AFL_NO_FORKSRV disables the forkserver optimization, reverting to + - Setting `AFL_NO_FORKSRV` disables the forkserver optimization, reverting to fork + execve() call for every tested input. This is useful mostly when working with unruly libraries that create threads or do other crazy things when initializing (before the instrumentation has a chance to run). @@ -397,128 +398,128 @@ checks or alter some of the more exotic semantics of the tool: normally done when starting up the forkserver and causes a pretty significant performance drop. - - Setting AFL_STATSD enable StatsD metrics collection. - By default AFL will send these metrics over UDP to 127.0.0.1:8125. - The host and port are configurable with AFL_STATSD_HOST and AFL_STATSD_PORT + - Setting `AFL_STATSD` enable StatsD metrics collection. + By default AFL++ will send these metrics over UDP to 127.0.0.1:8125. + The host and port are configurable with `AFL_STATSD_HOST` and `AFL_STATSD_PORT` respectively. - To get the most out of this, you should provide AFL_STATSD_TAGS_FLAVOR that + To get the most out of this, you should provide `AFL_STATSD_TAGS_FLAVOR` that matches your StatsD server. Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`. - - Outdated environment variables that are that not supported anymore: - AFL_DEFER_FORKSRV - AFL_PERSISTENT + - Outdated environment variables that are not supported anymore: + `AFL_DEFER_FORKSRV` + `AFL_PERSISTENT` ## 5) Settings for afl-qemu-trace The QEMU wrapper used to instrument binary-only code supports several settings: - - It is possible to set AFL_INST_RATIO to skip the instrumentation on some + - It is possible to set `AFL_INST_RATIO` to skip the instrumentation on some of the basic blocks, which can be useful when dealing with very complex binaries. - - Setting AFL_INST_LIBS causes the translator to also instrument the code + - Setting `AFL_INST_LIBS` causes the translator to also instrument the code inside any dynamically linked libraries (notably including glibc). - - Setting AFL_COMPCOV_LEVEL enables the CompareCoverage tracing of all cmp + - Setting `AFL_COMPCOV_LEVEL` enables the CompareCoverage tracing of all cmp and sub in x86 and x86_64 and memory comparions functions (e.g. strcmp, - memcmp, ...) when libcompcov is preloaded using AFL_PRELOAD. + memcmp, ...) when libcompcov is preloaded using `AFL_PRELOAD`. More info at qemu_mode/libcompcov/README.md. - There are two levels at the moment, AFL_COMPCOV_LEVEL=1 that instruments + There are two levels at the moment, `AFL_COMPCOV_LEVEL=1` that instruments only comparisons with immediate values / read-only memory and - AFL_COMPCOV_LEVEL=2 that instruments all the comparions. Level 2 is more + `AFL_COMPCOV_LEVEL=2` that instruments all the comparions. Level 2 is more accurate but may need a larger shared memory. - - Setting AFL_QEMU_COMPCOV enables the CompareCoverage tracing of all + - Setting `AFL_QEMU_COMPCOV` enables the CompareCoverage tracing of all cmp and sub in x86 and x86_64. - This is an alias of AFL_COMPCOV_LEVEL=1 when AFL_COMPCOV_LEVEL is + This is an alias of `AFL_COMPCOV_LEVEL=1` when `AFL_COMPCOV_LEVEL` is not specified. - The underlying QEMU binary will recognize any standard "user space - emulation" variables (e.g., QEMU_STACK_SIZE), but there should be no + emulation" variables (e.g., `QEMU_STACK_SIZE`), but there should be no reason to touch them. - - AFL_DEBUG will print the found entrypoint for the binary to stderr. + - `AFL_DEBUG` will print the found entrypoint for the binary to stderr. Use this if you are unsure if the entrypoint might be wrong - but - use it directly, e.g. afl-qemu-trace ./program + use it directly, e.g. `afl-qemu-trace ./program` - - AFL_ENTRYPOINT allows you to specify a specific entrypoint into the + - `AFL_ENTRYPOINT` allows you to specify a specific entrypoint into the binary (this can be very good for the performance!). - The entrypoint is specified as hex address, e.g. 0x4004110 + The entrypoint is specified as hex address, e.g. `0x4004110` Note that the address must be the address of a basic block. - When the target is i386/x86_64 you can specify the address of the function that has to be the body of the persistent loop using - AFL_QEMU_PERSISTENT_ADDR=`start addr`. + `AFL_QEMU_PERSISTENT_ADDR=start addr`. - Another modality to execute the persistent loop is to specify also the - AFL_QEMU_PERSISTENT_RET=`end addr` env variable. + `AFL_QEMU_PERSISTENT_RET=end addr` env variable. With this variable assigned, instead of patching the return address, the specified instruction is transformed to a jump towards `start addr`. - - AFL_QEMU_PERSISTENT_GPR=1 QEMU will save the original value of general + - `AFL_QEMU_PERSISTENT_GPR=1` QEMU will save the original value of general purpose registers and restore them in each persistent cycle. - - With AFL_QEMU_PERSISTENT_RETADDR_OFFSET you can specify the offset from the + - With `AFL_QEMU_PERSISTENT_RETADDR_OFFSET` you can specify the offset from the stack pointer in which QEMU can find the return address when `start addr` is - hitted. + hit. ## 6) Settings for afl-cmin The corpus minimization script offers very little customization: - - Setting AFL_PATH offers a way to specify the location of afl-showmap - and afl-qemu-trace (the latter only in -Q mode). + - Setting `AFL_PATH` offers a way to specify the location of afl-showmap + and afl-qemu-trace (the latter only in `-Q` mode). - - AFL_KEEP_TRACES makes the tool keep traces and other metadata used for + - `AFL_KEEP_TRACES` makes the tool keep traces and other metadata used for minimization and normally deleted at exit. The files can be found in the - /.traces/*. + `/.traces/` directory. - - AFL_ALLOW_TMP permits this and some other scripts to run in /tmp. This is + - `AFL_ALLOW_TMP` permits this and some other scripts to run in /tmp. This is a modest security risk on multi-user systems with rogue users, but should be safe on dedicated fuzzing boxes. # #6) Settings for afl-tmin -Virtually nothing to play with. Well, in QEMU mode (-Q), AFL_PATH will be -searched for afl-qemu-trace. In addition to this, TMPDIR may be used if a +Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be +searched for afl-qemu-trace. In addition to this, `TMPDIR` may be used if a temporary file can't be created in the current working directory. -You can specify AFL_TMIN_EXACT if you want afl-tmin to require execution paths +You can specify `AFL_TMIN_EXACT` if you want afl-tmin to require execution paths to match when minimizing crashes. This will make minimization less useful, but may prevent the tool from "jumping" from one crashing condition to another in -very buggy software. You probably want to combine it with the -e flag. +very buggy software. You probably want to combine it with the `-e` flag. ## 8) Settings for afl-analyze -You can set AFL_ANALYZE_HEX to get file offsets printed as hexadecimal instead +You can set `AFL_ANALYZE_HEX` to get file offsets printed as hexadecimal instead of decimal. ## 9) Settings for libdislocator The library honors these environmental variables: - - AFL_LD_LIMIT_MB caps the size of the maximum heap usage permitted by the + - `AFL_LD_LIMIT_MB` caps the size of the maximum heap usage permitted by the library, in megabytes. The default value is 1 GB. Once this is exceeded, allocations will return NULL. - - AFL_LD_HARD_FAIL alters the behavior by calling abort() on excessive - allocations, thus causing what AFL would perceive as a crash. Useful for + - `AFL_LD_HARD_FAIL` alters the behavior by calling `abort()` on excessive + allocations, thus causing what AFL++ would perceive as a crash. Useful for programs that are supposed to maintain a specific memory footprint. - - AFL_LD_VERBOSE causes the library to output some diagnostic messages + - `AFL_LD_VERBOSE` causes the library to output some diagnostic messages that may be useful for pinpointing the cause of any observed issues. - - AFL_LD_NO_CALLOC_OVER inhibits abort() on calloc() overflows. Most + - `AFL_LD_NO_CALLOC_OVER` inhibits `abort()` on `calloc()` overflows. Most of the common allocators check for that internally and return NULL, so it's a security risk only in more exotic setups. - - AFL_ALIGNED_ALLOC=1 will force the alignment of the allocation size to - max_align_t to be compliant with the C standard. + - `AFL_ALIGNED_ALLOC=1` will force the alignment of the allocation size to + `max_align_t` to be compliant with the C standard. ## 10) Settings for libtokencap -This library accepts AFL_TOKEN_FILE to indicate the location to which the +This library accepts `AFL_TOKEN_FILE` to indicate the location to which the discovered tokens should be written. ## 11) Third-party variables set by afl-fuzz & other tools @@ -526,33 +527,33 @@ discovered tokens should be written. Several variables are not directly interpreted by afl-fuzz, but are set to optimal values if not already present in the environment: - - By default, LD_BIND_NOW is set to speed up fuzzing by forcing the + - By default, `LD_BIND_NOW` is set to speed up fuzzing by forcing the linker to do all the work before the fork server kicks in. You can - override this by setting LD_BIND_LAZY beforehand, but it is almost + override this by setting `LD_BIND_LAZY` beforehand, but it is almost certainly pointless. - - By default, ASAN_OPTIONS are set to: - + - By default, `ASAN_OPTIONS` are set to: +``` abort_on_error=1 detect_leaks=0 malloc_context_size=0 symbolize=0 allocator_may_return_null=1 - - If you want to set your own options, be sure to include abort_on_error=1 - +``` + If you want to set your own options, be sure to include `abort_on_error=1` - otherwise, the fuzzer will not be able to detect crashes in the tested - app. Similarly, include symbolize=0, since without it, AFL may have + app. Similarly, include `symbolize=0`, since without it, AFL++ may have difficulty telling crashes and hangs apart. - - In the same vein, by default, MSAN_OPTIONS are set to: - + - In the same vein, by default, `MSAN_OPTIONS` are set to: +``` exit_code=86 (required for legacy reasons) abort_on_error=1 symbolize=0 msan_track_origins=0 allocator_may_return_null=1 - - Be sure to include the first one when customizing anything, since some - MSAN versions don't call abort() on error, and we need a way to detect +``` + Be sure to include the first one when customizing anything, since some + MSAN versions don't call `abort()` on error, and we need a way to detect faults. -- cgit 1.4.1 From 57f8aec3814e1959d36210815a0369d7bc149ac7 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 18 Nov 2020 02:41:35 +0100 Subject: brought back missing env vars --- docs/env_variables.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index a36f2b4e..469fc957 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -306,6 +306,14 @@ checks or alter some of the more exotic semantics of the tool: don't want AFL++ to spend too much time classifying that stuff and just rapidly put all timeouts in that bin. + - Setting `AFL_FORKSRV_INIT_TMOUT` allows yout to specify a different timeout + to wait for the forkserver to spin up. The default is the `-t` value times + `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the + default would wait `1000` milis. Setting a different time here is useful + if the target has a very slow startup time, for example when doing + full-system fuzzing or emulation, but you don't want the actual runs + to wait too long for timeouts. + - `AFL_NO_ARITH` causes AFL++ to skip most of the deterministic arithmetics. This can be useful to speed up the fuzzing of text-based file formats. @@ -389,6 +397,13 @@ checks or alter some of the more exotic semantics of the tool: for an existing out folder, even if a different `-i` was provided. Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir. + - Setting `AFL_MAX_DET_EXRAS` will change the threshold at what number of elements + in the `-x` dictionary and LTO autodict (combined) the probabilistic mode will + kick off. In probabilistic mode, not all dictionary entires will be used all + of the times for fuzzing mutations to not make fuzzing slower by it. + The default count is `200` element. So for the 200 + 1st element, there is a + 1 in 201 chance, that one of the dictionary entry will not be used directly. + - Setting `AFL_NO_FORKSRV` disables the forkserver optimization, reverting to fork + execve() call for every tested input. This is useful mostly when working with unruly libraries that create threads or do other crazy -- cgit 1.4.1 From f80f62f14bb5222344925a7ec51c81aa2f95d86e Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 18 Nov 2020 03:02:13 +0100 Subject: renamed env var to AFL_DEBUG_CHILD --- docs/Changelog.md | 1 + docs/env_variables.md | 2 +- examples/afl_network_proxy/afl-network-server.c | 7 +++++-- include/afl-fuzz.h | 4 ++-- include/envs.h | 3 ++- instrumentation/afl-compiler-rt.o.c | 2 +- src/afl-fuzz-run.c | 2 +- src/afl-fuzz-state.c | 6 ++++-- src/afl-fuzz.c | 4 ++-- src/afl-showmap.c | 6 +++++- src/afl-tmin.c | 7 +++++-- test/test-unicorn-mode.sh | 6 +++--- 12 files changed, 32 insertions(+), 18 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index baa2667b..9426ed54 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -58,6 +58,7 @@ sending a mail to . - added INTROSPECTION support for custom modules - python fuzz function was not optional, fixed - unicornafl synced with upstream (arm64 fix, better rust bindings) + - renamed AFL_DEBUG_CHILD_OUTPUT to AFL_DEBUG_CHILD ### Version ++2.68c (release) diff --git a/docs/env_variables.md b/docs/env_variables.md index 469fc957..1ce6f206 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -388,7 +388,7 @@ checks or alter some of the more exotic semantics of the tool: processing the first queue entry; and `AFL_BENCH_UNTIL_CRASH` causes it to exit soon after the first crash is found. - - Setting `AFL_DEBUG_CHILD_OUTPUT` will not suppress the child output. + - Setting `AFL_DEBUG_CHILD` will not suppress the child output. Not pretty but good for debugging purposes. - Setting `AFL_NO_CPU_RED` will not display very high cpu usages in red color. diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c index 3831f985..513dc8f2 100644 --- a/examples/afl_network_proxy/afl-network-server.c +++ b/examples/afl_network_proxy/afl-network-server.c @@ -636,8 +636,11 @@ int main(int argc, char **argv_orig, char **envp) { if (listen(sock, 1) < 0) { PFATAL("listen() failed"); } - afl_fsrv_start(fsrv, use_argv, &stop_soon, - get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); + afl_fsrv_start( + fsrv, use_argv, &stop_soon, + (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) + ? 1 + : 0); #ifdef USE_DEFLATE compressor = libdeflate_alloc_compressor(1); diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c355263b..b484b93e 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -362,8 +362,8 @@ typedef struct afl_env_vars { u8 afl_skip_cpufreq, afl_exit_when_done, afl_no_affinity, afl_skip_bin_check, afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, - afl_bench_until_crash, afl_debug_child_output, afl_autoresume, - afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd; + afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, + afl_cycle_schedules, afl_expand_havoc, afl_statsd; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, diff --git a/include/envs.h b/include/envs.h index b753d5f8..8255cf4f 100644 --- a/include/envs.h +++ b/include/envs.h @@ -6,6 +6,7 @@ static char *afl_environment_deprecated[] = { "AFL_LLVM_WHITELIST", "AFL_GCC_WHITELIST", + "AFL_DEBUG_CHILD_OUTPUT", "AFL_DEFER_FORKSRV", "AFL_POST_LIBRARY", "AFL_PERSISTENT", @@ -36,7 +37,7 @@ static char *afl_environment_variables[] = { "AFL_CXX", "AFL_CYCLE_SCHEDULES", "AFL_DEBUG", - "AFL_DEBUG_CHILD_OUTPUT", + "AFL_DEBUG_CHILD", "AFL_DEBUG_GDB", "AFL_DISABLE_TRIM", "AFL_DONT_OPTIMIZE", diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 18501b65..485f500c 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -992,7 +992,7 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) { // For stability analysis, if you want to know to which function unstable // edge IDs belong - uncomment, recompile+install llvm_mode, recompile // the target. libunwind and libbacktrace are better solutions. - // Set AFL_DEBUG_CHILD_OUTPUT=1 and run afl-fuzz with 2>file to capture + // Set AFL_DEBUG_CHILD=1 and run afl-fuzz with 2>file to capture // the backtrace output /* uint32_t unstable[] = { ... unstable edge IDs }; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index b96fe71a..95b3ee8a 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -332,7 +332,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, - afl->afl_env.afl_debug_child_output); + afl->afl_env.afl_debug_child); if (afl->fsrv.support_shmem_fuzz && !afl->fsrv.use_shmem_fuzz) { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 61bd06b7..489d4e53 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -268,11 +268,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_bench_until_crash = get_afl_env(afl_environment_variables[i]) ? 1 : 0; - } else if (!strncmp(env, "AFL_DEBUG_CHILD_OUTPUT", + } else if (!strncmp(env, "AFL_DEBUG_CHILD", + afl_environment_variable_len) || + !strncmp(env, "AFL_DEBUG_CHILD_OUTPUT", afl_environment_variable_len)) { - afl->afl_env.afl_debug_child_output = + afl->afl_env.afl_debug_child = get_afl_env(afl_environment_variables[i]) ? 1 : 0; } else if (!strncmp(env, "AFL_AUTORESUME", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index ac77bb1f..e04ae649 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -166,7 +166,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n" "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n" "AFL_DEBUG: extra debugging output for Python mode trimming\n" - "AFL_DEBUG_CHILD_OUTPUT: do not suppress stdout/stderr from target\n" + "AFL_DEBUG_CHILD: do not suppress stdout/stderr from target\n" "AFL_DISABLE_TRIM: disable the trimming of test cases\n" "AFL_DUMB_FORKSRV: use fork server without feedback from target\n" "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n" @@ -1426,7 +1426,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; afl->cmplog_fsrv.init_child_func = cmplog_exec_child; afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, - afl->afl_env.afl_debug_child_output); + afl->afl_env.afl_debug_child); OKF("Cmplog forkserver successfully started"); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 4b357254..69527007 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1091,7 +1091,11 @@ int main(int argc, char **argv_orig, char **envp) { } afl_fsrv_start(fsrv, use_argv, &stop_soon, - get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); + (get_afl_env("AFL_DEBUG_CHILD") || + get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) + ? 1 + : 0); + map_size = fsrv->map_size; if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 06037d61..e4fb068d 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1141,8 +1141,11 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); - afl_fsrv_start(fsrv, use_argv, &stop_soon, - get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); + afl_fsrv_start( + fsrv, use_argv, &stop_soon, + (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) + ? 1 + : 0); if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); diff --git a/test/test-unicorn-mode.sh b/test/test-unicorn-mode.sh index 7ac4cdd2..b4c6eb3e 100755 --- a/test/test-unicorn-mode.sh +++ b/test/test-unicorn-mode.sh @@ -7,7 +7,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel test -e ../unicorn_mode/samples/simple/simple_target.bin -a -e ../unicorn_mode/samples/compcov_x64/compcov_target.bin && { { # We want to see python errors etc. in logs, in case something doesn't work - export AFL_DEBUG_CHILD_OUTPUT=1 + export AFL_DEBUG_CHILD=1 # some python version should be available now PYTHONS="`command -v python3` `command -v python` `command -v python2`" @@ -34,7 +34,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel cd ../unicorn_mode/samples/persistent make >>errors 2>&1 $ECHO "$GREY[*] running afl-fuzz for unicorn_mode (persistent), this will take approx 25 seconds" - AFL_DEBUG_CHILD_OUTPUT=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1 + AFL_DEBUG_CHILD=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1 test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && { $ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode (persistent)" } || { @@ -96,7 +96,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel } fi - unset AFL_DEBUG_CHILD_OUTPUT + unset AFL_DEBUG_CHILD } } || { -- cgit 1.4.1 From 68e18dbb7a261b0343bc3580f26cf59531c18152 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 18 Nov 2020 03:09:50 +0100 Subject: more info about child_debug --- docs/env_variables.md | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index 1ce6f206..e6f9c275 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -389,7 +389,11 @@ checks or alter some of the more exotic semantics of the tool: exit soon after the first crash is found. - Setting `AFL_DEBUG_CHILD` will not suppress the child output. + This lets you see all output of the child, making setup issues obvious. + For example, in an unicornafl harness, you might see python stacktraces. + You may also see other logs that way, indicating why the forkserver won't start. Not pretty but good for debugging purposes. + Note that `AFL_DEBUG_CHILD_OUTPUT` is deprecated. - Setting `AFL_NO_CPU_RED` will not display very high cpu usages in red color. -- cgit 1.4.1 From 211a6eb411a6e57cd22a24bb50ae095676d8b0c5 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Wed, 18 Nov 2020 08:40:12 +0100 Subject: typos and wording --- docs/env_variables.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index e6f9c275..04ba032a 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -306,10 +306,10 @@ checks or alter some of the more exotic semantics of the tool: don't want AFL++ to spend too much time classifying that stuff and just rapidly put all timeouts in that bin. - - Setting `AFL_FORKSRV_INIT_TMOUT` allows yout to specify a different timeout + - Setting `AFL_FORKSRV_INIT_TMOUT` allows you to specify a different timeout to wait for the forkserver to spin up. The default is the `-t` value times `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the - default would wait `1000` milis. Setting a different time here is useful + default would wait for `1000` milliseconds. Setting a different time here is useful if the target has a very slow startup time, for example when doing full-system fuzzing or emulation, but you don't want the actual runs to wait too long for timeouts. @@ -403,10 +403,10 @@ checks or alter some of the more exotic semantics of the tool: - Setting `AFL_MAX_DET_EXRAS` will change the threshold at what number of elements in the `-x` dictionary and LTO autodict (combined) the probabilistic mode will - kick off. In probabilistic mode, not all dictionary entires will be used all - of the times for fuzzing mutations to not make fuzzing slower by it. - The default count is `200` element. So for the 200 + 1st element, there is a - 1 in 201 chance, that one of the dictionary entry will not be used directly. + kick off. In probabilistic mode not all dictionary entires will be used all + of the times for fuzzing mutations to not slow down fuzzing. + The default count is `200` elements. So for the 200 + 1st element, there is a + 1 in 201 chance, that one of the dictionary entries will not be used directly. - Setting `AFL_NO_FORKSRV` disables the forkserver optimization, reverting to fork + execve() call for every tested input. This is useful mostly when -- cgit 1.4.1 From 8584f9d2b5de9687c518c672e471f4f8cd9166fa Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 1 Dec 2020 13:13:11 +0100 Subject: added AFL_NO_AUTODICT --- docs/Changelog.md | 1 + docs/env_variables.md | 3 + include/envs.h | 1 + instrumentation/README.lto.md | 33 +++++++---- src/afl-forkserver.c | 125 ++++++++++++++++++++++-------------------- src/afl-fuzz.c | 1 + 6 files changed, 95 insertions(+), 69 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 3c20f8bd..7fa7ff53 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -34,6 +34,7 @@ sending a mail to . - crashing seeds are now not prohibiting a run anymore but are skipped. They are used for splicing though. - update MOpt for expanded havoc modes + - setting the env var AFL_NO_AUTODICT will not load an LTO autodictionary - added NO_SPLICING compile option and makefile define - added INTROSPECTION make target that writes all mutations to out/NAME/introspection.txt diff --git a/docs/env_variables.md b/docs/env_variables.md index 04ba032a..f7b4c994 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -294,6 +294,9 @@ checks or alter some of the more exotic semantics of the tool: on Linux systems. This slows things down, but lets you run more instances of afl-fuzz than would be prudent (if you really want to). + - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary + that is compiled into the target. + - `AFL_SKIP_CRASHES` causes AFL++ to tolerate crashing files in the input queue. This can help with rare situations where a program crashes only intermittently, but it's not really recommended under normal operating diff --git a/include/envs.h b/include/envs.h index 8255cf4f..3aa05cb5 100644 --- a/include/envs.h +++ b/include/envs.h @@ -100,6 +100,7 @@ static char *afl_environment_variables[] = { "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", + "AFL_NO_AUTODICT", "AFL_NO_BUILTIN", "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", diff --git a/instrumentation/README.lto.md b/instrumentation/README.lto.md index abdbd2ac..62e98902 100644 --- a/instrumentation/README.lto.md +++ b/instrumentation/README.lto.md @@ -60,7 +60,12 @@ AUTODICTIONARY: 11 strings found ## Getting llvm 11+ -### Installing llvm from the llvm repository (version 11) +### Installing llvm version 11 + +llvm 11 should be available in all current Linux repository. +If you use an outdated Linux distribution read the next section. + +### Installing llvm from the llvm repository (version 12) Installing the llvm snapshot builds is easy and mostly painless: @@ -73,11 +78,11 @@ then add the pgp key of llvm and install the packages: ``` wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - apt-get update && apt-get upgrade -y -apt-get install -y clang-11 clang-tools-11 libc++1-11 libc++-11-dev \ - libc++abi1-11 libc++abi-11-dev libclang1-11 libclang-11-dev \ - libclang-common-11-dev libclang-cpp11 libclang-cpp11-dev liblld-11 \ - liblld-11-dev liblldb-11 liblldb-11-dev libllvm11 libomp-11-dev \ - libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools +apt-get install -y clang-12 clang-tools-12 libc++1-12 libc++-12-dev \ + libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \ + libclang-common-12-dev libclang-cpp11 libclang-cpp11-dev liblld-12 \ + liblld-12-dev liblldb-12 liblldb-12-dev libllvm11 libomp-12-dev \ + libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools ``` ### Building llvm yourself (version 12) @@ -120,16 +125,22 @@ While compiling, a dictionary based on string comparisons is automatically generated and put into the target binary. This dictionary is transfered to afl-fuzz on start. This improves coverage statistically by 5-10% :) +Note that if for any reason you do not want to use the autodictionary feature +then just set the environment variable `AFL_NO_AUTODICT` when starting afl-fuzz. + ## Fixed memory map -To speed up fuzzing, it is possible to set a fixed shared memory map. +To speed up fuzzing a little bit more, it is possible to set a fixed shared +memory map. Recommended 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 -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 -to be dynamic - the original afl way, which is slower). + +Also on unusual operating systems/processors/kernels or weird libraries the +recommended 0x10000 address might not work, so then change the fixed address. + +To enable this feature set AFL_LLVM_MAP_ADDR with the address. ## Document edge IDs diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 3814a77e..01ef1d9e 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -348,9 +348,10 @@ static void report_error_and_exit(int error) { void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, u8 debug_child_output) { - int st_pipe[2], ctl_pipe[2]; - s32 status; - s32 rlen; + int st_pipe[2], ctl_pipe[2]; + s32 status; + s32 rlen; + char *ignore_autodict = getenv("AFL_NO_AUTODICT"); if (!be_quiet) { ACTF("Spinning up the fork server..."); } @@ -607,7 +608,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, fsrv->use_shmem_fuzz = 1; if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); } - if ((status & FS_OPT_AUTODICT) == 0) { + if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) { u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) { @@ -660,101 +661,109 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { - if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) { + if (ignore_autodict) { - // this is not afl-fuzz - or it is cmplog - we deny and return - if (fsrv->use_shmem_fuzz) { + if (!be_quiet) { WARNF("Ignoring offered AUTODICT feature."); } - status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); + } else { - } else { + if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) { - status = (FS_OPT_ENABLED); + // this is not afl-fuzz - or it is cmplog - we deny and return + if (fsrv->use_shmem_fuzz) { - } + status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); - if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { + } else { - FATAL("Writing to forkserver failed."); + status = (FS_OPT_ENABLED); - } + } - return; + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { - } + FATAL("Writing to forkserver failed."); - if (!be_quiet) { ACTF("Using AUTODICT feature."); } + } - if (fsrv->use_shmem_fuzz) { + return; - status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ); + } - } else { + if (!be_quiet) { ACTF("Using AUTODICT feature."); } - status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); + if (fsrv->use_shmem_fuzz) { - } + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ); - if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { + } else { - FATAL("Writing to forkserver failed."); + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); - } + } - if (read(fsrv->fsrv_st_fd, &status, 4) != 4) { + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { - FATAL("Reading from forkserver failed."); + FATAL("Writing to forkserver failed."); - } + } - if (status < 2 || (u32)status > 0xffffff) { + if (read(fsrv->fsrv_st_fd, &status, 4) != 4) { - FATAL("Dictionary has an illegal size: %d", status); + FATAL("Reading from forkserver failed."); - } + } - u32 offset = 0, count = 0; - u32 len = status; - u8 *dict = ck_alloc(len); - if (dict == NULL) { + if (status < 2 || (u32)status > 0xffffff) { - FATAL("Could not allocate %u bytes of autodictionary memory", len); + FATAL("Dictionary has an illegal size: %d", status); - } + } - while (len != 0) { + u32 offset = 0, count = 0; + u32 len = status; + u8 *dict = ck_alloc(len); + if (dict == NULL) { - rlen = read(fsrv->fsrv_st_fd, dict + offset, len); - if (rlen > 0) { + FATAL("Could not allocate %u bytes of autodictionary memory", len); - len -= rlen; - offset += rlen; + } - } else { + while (len != 0) { - FATAL( - "Reading autodictionary fail at position %u with %u bytes " - "left.", - offset, len); + rlen = read(fsrv->fsrv_st_fd, dict + offset, len); + if (rlen > 0) { + + len -= rlen; + offset += rlen; + + } else { + + FATAL( + "Reading autodictionary fail at position %u with %u bytes " + "left.", + offset, len); + + } } - } + offset = 0; + while (offset < (u32)status && + (u8)dict[offset] + offset < (u32)status) { + + fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, + (u8)dict[offset]); + offset += (1 + dict[offset]); + count++; - offset = 0; - while (offset < (u32)status && - (u8)dict[offset] + offset < (u32)status) { + } - fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, - (u8)dict[offset]); - offset += (1 + dict[offset]); - count++; + if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); } + ck_free(dict); } - if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); } - ck_free(dict); - } } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index b60908da..b91d862d 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -187,6 +187,7 @@ static void usage(u8 *argv0, int more_help) { " used. Defaults to 200.\n" "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n" "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" + "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n" "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n" -- cgit 1.4.1 From c05e4efbe9b4e7d1ff078b7a392621f2ca7572e6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Dec 2020 14:40:30 +0100 Subject: renamed examples/ to utils/ --- GNUmakefile | 36 +- README.md | 7 +- docs/Changelog.md | 1 + docs/FAQ.md | 2 +- docs/binaryonly_fuzzing.md | 6 +- docs/custom_mutators.md | 4 +- docs/env_variables.md | 2 +- docs/life_pro_tips.md | 4 +- docs/notes_for_asan.md | 4 +- docs/parallel_fuzzing.md | 2 +- examples/README.md | 54 -- examples/afl_frida/GNUmakefile | 23 - examples/afl_frida/Makefile | 2 - examples/afl_frida/README.md | 34 - examples/afl_frida/afl-frida.c | 542 --------------- examples/afl_frida/afl-frida.h | 53 -- examples/afl_frida/libtestinstr.c | 35 - examples/afl_network_proxy/GNUmakefile | 43 -- examples/afl_network_proxy/Makefile | 2 - examples/afl_network_proxy/README.md | 61 -- examples/afl_network_proxy/afl-network-client.c | 415 ------------ examples/afl_network_proxy/afl-network-server.c | 720 -------------------- examples/afl_proxy/Makefile | 7 - examples/afl_proxy/README.md | 9 - examples/afl_proxy/afl-proxy.c | 238 ------- examples/afl_untracer/Makefile | 16 - examples/afl_untracer/README.md | 60 -- examples/afl_untracer/TODO | 2 - examples/afl_untracer/afl-untracer.c | 768 ---------------------- examples/afl_untracer/ghidra_get_patchpoints.java | 84 --- examples/afl_untracer/ida_get_patchpoints.py | 62 -- examples/afl_untracer/libtestinstr.c | 35 - examples/afl_untracer/libtestinstr.so | Bin 17152 -> 0 bytes examples/afl_untracer/patches.txt | 34 - examples/aflpp_driver/GNUmakefile | 46 -- examples/aflpp_driver/Makefile | 2 - examples/aflpp_driver/aflpp_driver.c | 326 --------- examples/aflpp_driver/aflpp_driver_test.c | 32 - examples/aflpp_driver/aflpp_qemu_driver.c | 38 -- examples/aflpp_driver/aflpp_qemu_driver_hook.c | 22 - examples/analysis_scripts/queue2csv.sh | 122 ---- examples/argv_fuzzing/Makefile | 58 -- examples/argv_fuzzing/README.md | 16 - examples/argv_fuzzing/argv-fuzz-inl.h | 90 --- examples/argv_fuzzing/argvfuzz.c | 49 -- examples/asan_cgroups/limit_memory.sh | 157 ----- examples/bash_shellshock/shellshock-fuzz.diff | 59 -- examples/canvas_harness/canvas_harness.html | 170 ----- examples/clang_asm_normalize/as | 75 --- examples/crash_triage/triage_crashes.sh | 115 ---- examples/custom_mutators/Makefile | 7 - examples/custom_mutators/README.md | 35 - examples/custom_mutators/XmlMutatorMin.py | 332 ---------- examples/custom_mutators/common.py | 40 -- examples/custom_mutators/custom_mutator_helpers.h | 342 ---------- examples/custom_mutators/example.c | 376 ----------- examples/custom_mutators/example.py | 186 ------ examples/custom_mutators/post_library_gif.so.c | 165 ----- examples/custom_mutators/post_library_png.so.c | 163 ----- examples/custom_mutators/simple-chunk-replace.py | 64 -- examples/custom_mutators/simple_example.c | 74 --- examples/custom_mutators/wrapper_afl_min.py | 118 ---- examples/defork/Makefile | 64 -- examples/defork/README.md | 11 - examples/defork/defork.c | 50 -- examples/defork/forking_target.c | 49 -- examples/distributed_fuzzing/sync_script.sh | 97 --- examples/libpng_no_checksum/libpng-nocrc.patch | 15 - examples/persistent_mode/Makefile | 10 - examples/persistent_mode/persistent_demo.c | 112 ---- examples/persistent_mode/persistent_demo_new.c | 117 ---- examples/persistent_mode/test-instr.c | 69 -- examples/qemu_persistent_hook/Makefile | 6 - examples/qemu_persistent_hook/README.md | 19 - examples/qemu_persistent_hook/read_into_rdi.c | 34 - examples/qemu_persistent_hook/test.c | 35 - examples/socket_fuzzing/Makefile | 61 -- examples/socket_fuzzing/README.md | 11 - examples/socket_fuzzing/socketfuzz.c | 110 ---- instrumentation/README.gcc_plugin.md | 2 +- instrumentation/README.persistent_mode.md | 4 +- qemu_mode/README.md | 2 +- qemu_mode/README.persistent.md | 2 +- src/afl-as.c | 2 +- test/test-custom-mutators.sh | 8 +- test/test-gcc-plugin.sh | 2 +- test/test-llvm-lto.sh | 2 +- test/test-llvm.sh | 2 +- utils/README.md | 54 ++ utils/afl_frida/GNUmakefile | 23 + utils/afl_frida/Makefile | 2 + utils/afl_frida/README.md | 34 + utils/afl_frida/afl-frida.c | 542 +++++++++++++++ utils/afl_frida/afl-frida.h | 53 ++ utils/afl_frida/libtestinstr.c | 35 + utils/afl_network_proxy/GNUmakefile | 43 ++ utils/afl_network_proxy/Makefile | 2 + utils/afl_network_proxy/README.md | 61 ++ utils/afl_network_proxy/afl-network-client.c | 415 ++++++++++++ utils/afl_network_proxy/afl-network-server.c | 720 ++++++++++++++++++++ utils/afl_proxy/Makefile | 7 + utils/afl_proxy/README.md | 9 + utils/afl_proxy/afl-proxy.c | 238 +++++++ utils/afl_untracer/Makefile | 16 + utils/afl_untracer/README.md | 60 ++ utils/afl_untracer/TODO | 2 + utils/afl_untracer/afl-untracer.c | 768 ++++++++++++++++++++++ utils/afl_untracer/ghidra_get_patchpoints.java | 84 +++ utils/afl_untracer/ida_get_patchpoints.py | 62 ++ utils/afl_untracer/libtestinstr.c | 35 + utils/afl_untracer/patches.txt | 34 + utils/aflpp_driver/GNUmakefile | 46 ++ utils/aflpp_driver/Makefile | 2 + utils/aflpp_driver/aflpp_driver.c | 326 +++++++++ utils/aflpp_driver/aflpp_driver_test.c | 32 + utils/aflpp_driver/aflpp_qemu_driver.c | 38 ++ utils/aflpp_driver/aflpp_qemu_driver_hook.c | 22 + utils/analysis_scripts/queue2csv.sh | 122 ++++ utils/argv_fuzzing/Makefile | 58 ++ utils/argv_fuzzing/README.md | 16 + utils/argv_fuzzing/argv-fuzz-inl.h | 90 +++ utils/argv_fuzzing/argvfuzz.c | 49 ++ utils/asan_cgroups/limit_memory.sh | 157 +++++ utils/bash_shellshock/shellshock-fuzz.diff | 59 ++ utils/canvas_harness/canvas_harness.html | 170 +++++ utils/clang_asm_normalize/as | 75 +++ utils/crash_triage/triage_crashes.sh | 115 ++++ utils/custom_mutators/Makefile | 7 + utils/custom_mutators/README.md | 35 + utils/custom_mutators/XmlMutatorMin.py | 332 ++++++++++ utils/custom_mutators/common.py | 40 ++ utils/custom_mutators/custom_mutator_helpers.h | 342 ++++++++++ utils/custom_mutators/example.c | 376 +++++++++++ utils/custom_mutators/example.py | 186 ++++++ utils/custom_mutators/post_library_gif.so.c | 165 +++++ utils/custom_mutators/post_library_png.so.c | 163 +++++ utils/custom_mutators/simple-chunk-replace.py | 64 ++ utils/custom_mutators/simple_example.c | 74 +++ utils/custom_mutators/wrapper_afl_min.py | 118 ++++ utils/defork/Makefile | 64 ++ utils/defork/README.md | 11 + utils/defork/defork.c | 50 ++ utils/defork/forking_target.c | 49 ++ utils/distributed_fuzzing/sync_script.sh | 97 +++ utils/libpng_no_checksum/libpng-nocrc.patch | 15 + utils/persistent_mode/Makefile | 10 + utils/persistent_mode/persistent_demo.c | 112 ++++ utils/persistent_mode/persistent_demo_new.c | 117 ++++ utils/persistent_mode/test-instr.c | 69 ++ utils/qemu_persistent_hook/Makefile | 6 + utils/qemu_persistent_hook/README.md | 19 + utils/qemu_persistent_hook/read_into_rdi.c | 34 + utils/qemu_persistent_hook/test.c | 35 + utils/socket_fuzzing/Makefile | 61 ++ utils/socket_fuzzing/README.md | 11 + utils/socket_fuzzing/socketfuzz.c | 110 ++++ 156 files changed, 7496 insertions(+), 7494 deletions(-) delete mode 100644 examples/README.md delete mode 100644 examples/afl_frida/GNUmakefile delete mode 100644 examples/afl_frida/Makefile delete mode 100644 examples/afl_frida/README.md delete mode 100644 examples/afl_frida/afl-frida.c delete mode 100644 examples/afl_frida/afl-frida.h delete mode 100644 examples/afl_frida/libtestinstr.c delete mode 100644 examples/afl_network_proxy/GNUmakefile delete mode 100644 examples/afl_network_proxy/Makefile delete mode 100644 examples/afl_network_proxy/README.md delete mode 100644 examples/afl_network_proxy/afl-network-client.c delete mode 100644 examples/afl_network_proxy/afl-network-server.c delete mode 100644 examples/afl_proxy/Makefile delete mode 100644 examples/afl_proxy/README.md delete mode 100644 examples/afl_proxy/afl-proxy.c delete mode 100644 examples/afl_untracer/Makefile delete mode 100644 examples/afl_untracer/README.md delete mode 100644 examples/afl_untracer/TODO delete mode 100644 examples/afl_untracer/afl-untracer.c delete mode 100644 examples/afl_untracer/ghidra_get_patchpoints.java delete mode 100644 examples/afl_untracer/ida_get_patchpoints.py delete mode 100644 examples/afl_untracer/libtestinstr.c delete mode 100755 examples/afl_untracer/libtestinstr.so delete mode 100644 examples/afl_untracer/patches.txt delete mode 100644 examples/aflpp_driver/GNUmakefile delete mode 100644 examples/aflpp_driver/Makefile delete mode 100644 examples/aflpp_driver/aflpp_driver.c delete mode 100644 examples/aflpp_driver/aflpp_driver_test.c delete mode 100644 examples/aflpp_driver/aflpp_qemu_driver.c delete mode 100644 examples/aflpp_driver/aflpp_qemu_driver_hook.c delete mode 100755 examples/analysis_scripts/queue2csv.sh delete mode 100644 examples/argv_fuzzing/Makefile delete mode 100644 examples/argv_fuzzing/README.md delete mode 100644 examples/argv_fuzzing/argv-fuzz-inl.h delete mode 100644 examples/argv_fuzzing/argvfuzz.c delete mode 100755 examples/asan_cgroups/limit_memory.sh delete mode 100644 examples/bash_shellshock/shellshock-fuzz.diff delete mode 100644 examples/canvas_harness/canvas_harness.html delete mode 100755 examples/clang_asm_normalize/as delete mode 100755 examples/crash_triage/triage_crashes.sh delete mode 100644 examples/custom_mutators/Makefile delete mode 100644 examples/custom_mutators/README.md delete mode 100644 examples/custom_mutators/XmlMutatorMin.py delete mode 100644 examples/custom_mutators/common.py delete mode 100644 examples/custom_mutators/custom_mutator_helpers.h delete mode 100644 examples/custom_mutators/example.c delete mode 100644 examples/custom_mutators/example.py delete mode 100644 examples/custom_mutators/post_library_gif.so.c delete mode 100644 examples/custom_mutators/post_library_png.so.c delete mode 100644 examples/custom_mutators/simple-chunk-replace.py delete mode 100644 examples/custom_mutators/simple_example.c delete mode 100644 examples/custom_mutators/wrapper_afl_min.py delete mode 100644 examples/defork/Makefile delete mode 100644 examples/defork/README.md delete mode 100644 examples/defork/defork.c delete mode 100644 examples/defork/forking_target.c delete mode 100755 examples/distributed_fuzzing/sync_script.sh delete mode 100644 examples/libpng_no_checksum/libpng-nocrc.patch delete mode 100644 examples/persistent_mode/Makefile delete mode 100644 examples/persistent_mode/persistent_demo.c delete mode 100644 examples/persistent_mode/persistent_demo_new.c delete mode 100644 examples/persistent_mode/test-instr.c delete mode 100644 examples/qemu_persistent_hook/Makefile delete mode 100644 examples/qemu_persistent_hook/README.md delete mode 100644 examples/qemu_persistent_hook/read_into_rdi.c delete mode 100644 examples/qemu_persistent_hook/test.c delete mode 100644 examples/socket_fuzzing/Makefile delete mode 100644 examples/socket_fuzzing/README.md delete mode 100644 examples/socket_fuzzing/socketfuzz.c create mode 100644 utils/README.md create mode 100644 utils/afl_frida/GNUmakefile create mode 100644 utils/afl_frida/Makefile create mode 100644 utils/afl_frida/README.md create mode 100644 utils/afl_frida/afl-frida.c create mode 100644 utils/afl_frida/afl-frida.h create mode 100644 utils/afl_frida/libtestinstr.c create mode 100644 utils/afl_network_proxy/GNUmakefile create mode 100644 utils/afl_network_proxy/Makefile create mode 100644 utils/afl_network_proxy/README.md create mode 100644 utils/afl_network_proxy/afl-network-client.c create mode 100644 utils/afl_network_proxy/afl-network-server.c create mode 100644 utils/afl_proxy/Makefile create mode 100644 utils/afl_proxy/README.md create mode 100644 utils/afl_proxy/afl-proxy.c create mode 100644 utils/afl_untracer/Makefile create mode 100644 utils/afl_untracer/README.md create mode 100644 utils/afl_untracer/TODO create mode 100644 utils/afl_untracer/afl-untracer.c create mode 100644 utils/afl_untracer/ghidra_get_patchpoints.java create mode 100644 utils/afl_untracer/ida_get_patchpoints.py create mode 100644 utils/afl_untracer/libtestinstr.c create mode 100644 utils/afl_untracer/patches.txt create mode 100644 utils/aflpp_driver/GNUmakefile create mode 100644 utils/aflpp_driver/Makefile create mode 100644 utils/aflpp_driver/aflpp_driver.c create mode 100644 utils/aflpp_driver/aflpp_driver_test.c create mode 100644 utils/aflpp_driver/aflpp_qemu_driver.c create mode 100644 utils/aflpp_driver/aflpp_qemu_driver_hook.c create mode 100755 utils/analysis_scripts/queue2csv.sh create mode 100644 utils/argv_fuzzing/Makefile create mode 100644 utils/argv_fuzzing/README.md create mode 100644 utils/argv_fuzzing/argv-fuzz-inl.h create mode 100644 utils/argv_fuzzing/argvfuzz.c create mode 100755 utils/asan_cgroups/limit_memory.sh create mode 100644 utils/bash_shellshock/shellshock-fuzz.diff create mode 100644 utils/canvas_harness/canvas_harness.html create mode 100755 utils/clang_asm_normalize/as create mode 100755 utils/crash_triage/triage_crashes.sh create mode 100644 utils/custom_mutators/Makefile create mode 100644 utils/custom_mutators/README.md create mode 100644 utils/custom_mutators/XmlMutatorMin.py create mode 100644 utils/custom_mutators/common.py create mode 100644 utils/custom_mutators/custom_mutator_helpers.h create mode 100644 utils/custom_mutators/example.c create mode 100644 utils/custom_mutators/example.py create mode 100644 utils/custom_mutators/post_library_gif.so.c create mode 100644 utils/custom_mutators/post_library_png.so.c create mode 100644 utils/custom_mutators/simple-chunk-replace.py create mode 100644 utils/custom_mutators/simple_example.c create mode 100644 utils/custom_mutators/wrapper_afl_min.py create mode 100644 utils/defork/Makefile create mode 100644 utils/defork/README.md create mode 100644 utils/defork/defork.c create mode 100644 utils/defork/forking_target.c create mode 100755 utils/distributed_fuzzing/sync_script.sh create mode 100644 utils/libpng_no_checksum/libpng-nocrc.patch create mode 100644 utils/persistent_mode/Makefile create mode 100644 utils/persistent_mode/persistent_demo.c create mode 100644 utils/persistent_mode/persistent_demo_new.c create mode 100644 utils/persistent_mode/test-instr.c create mode 100644 utils/qemu_persistent_hook/Makefile create mode 100644 utils/qemu_persistent_hook/README.md create mode 100644 utils/qemu_persistent_hook/read_into_rdi.c create mode 100644 utils/qemu_persistent_hook/test.c create mode 100644 utils/socket_fuzzing/Makefile create mode 100644 utils/socket_fuzzing/README.md create mode 100644 utils/socket_fuzzing/socketfuzz.c (limited to 'docs/env_variables.md') diff --git a/GNUmakefile b/GNUmakefile index 521ab683..309a7d4c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -500,8 +500,8 @@ code-format: ./.custom-format.py -i instrumentation/*.c @#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-( @#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-( - ./.custom-format.py -i examples/*/*.c* - ./.custom-format.py -i examples/*/*.h + ./.custom-format.py -i utils/*/*.c* + ./.custom-format.py -i utils/*/*.h ./.custom-format.py -i test/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.cc @@ -547,9 +547,9 @@ clean: -$(MAKE) -f GNUmakefile.gcc_plugin clean $(MAKE) -C libdislocator clean $(MAKE) -C libtokencap clean - $(MAKE) -C examples/afl_network_proxy clean - $(MAKE) -C examples/socket_fuzzing clean - $(MAKE) -C examples/argv_fuzzing clean + $(MAKE) -C utils/afl_network_proxy clean + $(MAKE) -C utils/socket_fuzzing clean + $(MAKE) -C utils/argv_fuzzing clean $(MAKE) -C qemu_mode/unsigaction clean $(MAKE) -C qemu_mode/libcompcov clean ifeq "$(IN_REPO)" "1" @@ -572,10 +572,10 @@ distrib: all -$(MAKE) -f GNUmakefile.gcc_plugin $(MAKE) -C libdislocator $(MAKE) -C libtokencap - $(MAKE) -C examples/aflpp_driver - $(MAKE) -C examples/afl_network_proxy - $(MAKE) -C examples/socket_fuzzing - $(MAKE) -C examples/argv_fuzzing + $(MAKE) -C utils/aflpp_driver + $(MAKE) -C utils/afl_network_proxy + $(MAKE) -C utils/socket_fuzzing + $(MAKE) -C utils/argv_fuzzing -cd qemu_mode && sh ./build_qemu_support.sh -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh @@ -583,9 +583,9 @@ distrib: all binary-only: all $(MAKE) -C libdislocator $(MAKE) -C libtokencap - $(MAKE) -C examples/afl_network_proxy - $(MAKE) -C examples/socket_fuzzing - $(MAKE) -C examples/argv_fuzzing + $(MAKE) -C utils/afl_network_proxy + $(MAKE) -C utils/socket_fuzzing + $(MAKE) -C utils/argv_fuzzing -cd qemu_mode && sh ./build_qemu_support.sh -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh @@ -595,7 +595,7 @@ source-only: all -$(MAKE) -f GNUmakefile.gcc_plugin $(MAKE) -C libdislocator $(MAKE) -C libtokencap - $(MAKE) -C examples/aflpp_driver + $(MAKE) -C utils/aflpp_driver %.8: % @echo .TH $* 8 $(BUILD_DATE) "afl++" > $@ @@ -628,11 +628,11 @@ install: all $(MANPAGES) @if [ -f libtokencap.so ]; then set -e; install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f libcompcov.so ]; then set -e; install -m 755 libcompcov.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi - @if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi - @if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi - @if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi - @if [ -f examples/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 examples/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi - @if [ -f examples/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 examples/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi + @if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C utils/socket_fuzzing install; fi + @if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi + @if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; fi + @if [ -f utils/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi + @if [ -f utils/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi -$(MAKE) -f GNUmakefile.llvm install -$(MAKE) -f GNUmakefile.gcc_plugin install ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-gcc diff --git a/README.md b/README.md index d7cad092..b00e5d00 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ behaviours and defaults: * a caching of testcases can now be performed and can be modified by editing config.h for TESTCASE_CACHE or by specifying the env variable `AFL_TESTCACHE_SIZE` (in MB). Good values are between 50-500 (default: 50). + * utils/ got renamed to utils/ ## Contents @@ -760,10 +761,10 @@ cd unicorn_mode If the goal is to fuzz a dynamic library then there are two options available. For both you need to write a small hardness that loads and calls the library. -Faster is the frida solution: [examples/afl_frida/README.md](examples/afl_frida/README.md) +Faster is the frida solution: [utils/afl_frida/README.md](utils/afl_frida/README.md) Another, less precise and slower option is using ptrace with debugger interrupt -instrumentation: [examples/afl_untracer/README.md](examples/afl_untracer/README.md) +instrumentation: [utils/afl_untracer/README.md](utils/afl_untracer/README.md) ### More @@ -1037,7 +1038,7 @@ Here are some of the most important caveats for AFL: wholly wrap the actual data format to be tested. To work around this, you can comment out the relevant checks (see - examples/libpng_no_checksum/ for inspiration); if this is not possible, + utils/libpng_no_checksum/ for inspiration); if this is not possible, you can also write a postprocessor, one of the hooks of custom mutators. See [docs/custom_mutators.md](docs/custom_mutators.md) on how to use `AFL_CUSTOM_MUTATOR_LIBRARY` diff --git a/docs/Changelog.md b/docs/Changelog.md index 7fa7ff53..fd30c7b0 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -11,6 +11,7 @@ sending a mail to . ### Version ++3.00a (develop) - llvm_mode/ and gcc_plugin/ moved to instrumentation/ + - examples/ renamed to utils/ - all compilers combined to afl-cc which emulates the previous ones - afl-llvm/gcc-rt.o merged into afl-compiler-rt.o - afl-fuzz diff --git a/docs/FAQ.md b/docs/FAQ.md index 064638f4..714d50eb 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -63,7 +63,7 @@ x10 - that is a x100 difference!). If modifying the source is not an option (e.g. because you only have a binary and perform binary fuzzing) you can also use a shared library with AFL_PRELOAD to emulate the network. This is also much faster than the real network would be. -See [examples/socket_fuzzing/](../examples/socket_fuzzing/). +See [utils/socket_fuzzing/](../utils/socket_fuzzing/). There is an outdated afl++ branch that implements networking if you are desperate though: [https://github.com/AFLplusplus/AFLplusplus/tree/networking](https://github.com/AFLplusplus/AFLplusplus/tree/networking) - diff --git a/docs/binaryonly_fuzzing.md b/docs/binaryonly_fuzzing.md index cb1288ef..66734452 100644 --- a/docs/binaryonly_fuzzing.md +++ b/docs/binaryonly_fuzzing.md @@ -15,7 +15,7 @@ high enough. Otherwise try retrowrite, afl-dyninst and if these fail too then try standard qemu_mode with AFL_ENTRYPOINT to where you need it. - If your target is a library use examples/afl_frida/. + If your target is a library use utils/afl_frida/. If your target is non-linux then use unicorn_mode/. @@ -65,14 +65,14 @@ ## AFL FRIDA If you want to fuzz a binary-only shared library then you can fuzz it with - frida-gum via examples/afl_frida/, you will have to write a harness to + frida-gum via utils/afl_frida/, you will have to write a harness to call the target function in the library, use afl-frida.c as a template. ## AFL UNTRACER If you want to fuzz a binary-only shared library then you can fuzz it with - examples/afl_untracer/, use afl-untracer.c as a template. + utils/afl_untracer/, use afl-untracer.c as a template. It is slower than AFL FRIDA (see above). diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 53f783fe..6e16ba0f 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -268,8 +268,8 @@ afl-fuzz /path/to/program ## 4) Example -Please see [example.c](../examples/custom_mutators/example.c) and -[example.py](../examples/custom_mutators/example.py) +Please see [example.c](../utils/custom_mutators/example.c) and +[example.py](../utils/custom_mutators/example.py) ## 5) Other Resources diff --git a/docs/env_variables.md b/docs/env_variables.md index f7b4c994..ada89257 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead: in your `$PATH`. - `AFL_PATH` can be used to point afl-gcc to an alternate location of afl-as. - One possible use of this is examples/clang_asm_normalize/, which lets + One possible use of this is utils/clang_asm_normalize/, which lets you instrument hand-written assembly when compiling clang code by plugging a normalizer into the chain. (There is no equivalent feature for GCC.) diff --git a/docs/life_pro_tips.md b/docs/life_pro_tips.md index 323f16f1..77845c63 100644 --- a/docs/life_pro_tips.md +++ b/docs/life_pro_tips.md @@ -78,10 +78,10 @@ Be sure to check out docs/sister_projects.md before writing your own. ## Need to fuzz the command-line arguments of a particular program? -You can find a simple solution in examples/argv_fuzzing. +You can find a simple solution in utils/argv_fuzzing. ## Attacking a format that uses checksums? Remove the checksum-checking code or use a postprocessor! -See examples/custom_mutators/ for more. +See utils/custom_mutators/ for more. diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md index 2e18c15f..f08ae3fb 100644 --- a/docs/notes_for_asan.md +++ b/docs/notes_for_asan.md @@ -20,7 +20,7 @@ Because of this, fuzzing with ASAN is recommended only in four scenarios: - Precisely gauge memory needs using http://jwilk.net/software/recidivm . - Limit the memory available to process using cgroups on Linux (see - examples/asan_cgroups). + utils/asan_cgroups). To compile with ASAN, set AFL_USE_ASAN=1 before calling 'make clean all'. The afl-gcc / afl-clang wrappers will pick that up and add the appropriate flags. @@ -74,7 +74,7 @@ There are also cgroups, but they are Linux-specific, not universally available even on Linux systems, and they require root permissions to set up; I'm a bit hesitant to make afl-fuzz require root permissions just for that. That said, if you are on Linux and want to use cgroups, check out the contributed script -that ships in examples/asan_cgroups/. +that ships in utils/asan_cgroups/. In settings where cgroups aren't available, we have no nice, portable way to avoid counting the ASAN allocation toward the limit. On 32-bit systems, or for diff --git a/docs/parallel_fuzzing.md b/docs/parallel_fuzzing.md index bf57ace8..8f2afe1b 100644 --- a/docs/parallel_fuzzing.md +++ b/docs/parallel_fuzzing.md @@ -152,7 +152,7 @@ write a simple script that performs two actions: done ``` -There is an example of such a script in examples/distributed_fuzzing/. +There is an example of such a script in utils/distributed_fuzzing/. There are other (older) more featured, experimental tools: * https://github.com/richo/roving diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 7dd70d6a..00000000 --- a/examples/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# AFL++ Examples - -Here's a quick overview of the stuff you can find in this directory: - - - afl_network_proxy - fuzz a target over the network: afl-fuzz on - a host, target on an embedded system. - - - afl_proxy - skeleton file example to show how to fuzz - something where you gather coverage data via - different means, e.g. hw debugger - - - afl_untracer - fuzz binary-only libraries much faster but with - less coverage than qemu_mode - - - argv_fuzzing - a simple wrapper to allow cmdline to be fuzzed - (e.g., to test setuid programs). - - - asan_cgroups - a contributed script to simplify fuzzing ASAN - binaries with robust memory limits on Linux. - - - bash_shellshock - a simple hack used to find a bunch of - post-Shellshock bugs in bash. - - - canvas_harness - a test harness used to find browser bugs with a - corpus generated using simple image parsing - binaries & afl-fuzz. - - - clang_asm_normalize - a script that makes it easy to instrument - hand-written assembly, provided that you have clang. - - - crash_triage - a very rudimentary example of how to annotate crashes - with additional gdb metadata. - - - custom_mutators - examples for the afl++ custom mutator interface in - C and Python - - - distributed_fuzzing - a sample script for synchronizing fuzzer instances - across multiple machines (see parallel_fuzzing.md). - - - libpng_no_checksum - a sample patch for removing CRC checks in libpng. - - - persistent_mode - an example of how to use the LLVM persistent process - mode to speed up certain fuzzing jobs. - - - socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin - for fuzzing access with afl++ - -Note that the minimize_corpus.sh tool has graduated from the examples/ -directory and is now available as ../afl-cmin. The LLVM mode has likewise -graduated to ../instrumentation/*. - -Most of the tools in this directory are meant chiefly as examples that need to -be tweaked for your specific needs. They come with some basic documentation, -but are not necessarily production-grade. diff --git a/examples/afl_frida/GNUmakefile b/examples/afl_frida/GNUmakefile deleted file mode 100644 index c154f3a4..00000000 --- a/examples/afl_frida/GNUmakefile +++ /dev/null @@ -1,23 +0,0 @@ -ifdef DEBUG - OPT=-O0 -D_DEBUG=\"1\" -else - OPT=-O3 -funroll-loops -endif - -all: afl-frida libtestinstr.so - -libfrida-gum.a: - @echo Download and extract frida-gum-devkit-VERSION-PLATFORM.tar.xz for your platform from https://github.com/frida/frida/releases/latest - @exit 1 - -afl-frida: afl-frida.c libfrida-gum.a - $(CC) -g $(OPT) -o afl-frida -Wno-format -Wno-pointer-sign -I. -fpermissive -fPIC afl-frida.c ../../afl-llvm-rt.o libfrida-gum.a -ldl -lresolv -pthread - -libtestinstr.so: libtestinstr.c - $(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c - -clean: - rm -f afl-frida *~ core *.o libtestinstr.so - -deepclean: clean - rm -f libfrida-gum.a frida-gum* diff --git a/examples/afl_frida/Makefile b/examples/afl_frida/Makefile deleted file mode 100644 index 0b306dde..00000000 --- a/examples/afl_frida/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - @echo please use GNU make, thanks! diff --git a/examples/afl_frida/README.md b/examples/afl_frida/README.md deleted file mode 100644 index 7743479b..00000000 --- a/examples/afl_frida/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# afl-frida - faster fuzzing of binary-only libraries - -## Introduction - -afl-frida is an example skeleton file which can easily be used to fuzz -a closed source library. - -It requires less memory and is x5-10 faster than qemu_mode but does not -provide interesting features like compcov or cmplog. - -## How-to - -### Modify afl-frida.c - -Read and modify afl-frida.c then `make`. -To adapt afl-frida.c to your needs, read the header of the file and then -search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations. - -### Fuzzing - -Example (after modifying afl-frida.c to your needs and compile it): -``` -LD_LIBRARY_PATH=/path/to/the/target/library afl-fuzz -i in -o out -- ./afl-frida -``` -(or even remote via afl-network-proxy). - -# Speed and stability - -The speed is very good, about x12 of fork() qemu_mode. -However the stability is low. Reason is currently unknown. - -# Background - -This code is copied for a larger part from https://github.com/meme/hotwax diff --git a/examples/afl_frida/afl-frida.c b/examples/afl_frida/afl-frida.c deleted file mode 100644 index 31bf8f25..00000000 --- a/examples/afl_frida/afl-frida.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - american fuzzy lop++ - afl-frida skeleton example - ------------------------------------------------- - - Copyright 2020 AFLplusplus Project. All rights reserved. - - Written mostly by meme -> https://github.com/meme/hotwax - - Modifications by Marc Heuse - - 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 - - HOW-TO - ====== - - You only need to change the following: - - 1. set the defines and function call parameters. - 2. dl load the library you want to fuzz, lookup the functions you need - and setup the calls to these. - 3. in the while loop you call the functions in the necessary order - - incl the cleanup. the cleanup is important! - - Just look these steps up in the code, look for "// STEP x:" - -*/ - -#include -#include -#include -#include -#include -#include -#include - -#ifndef __APPLE__ - #include - #include -#endif - -int debug = 0; - -// STEP 1: - -// The presets are for the example libtestinstr.so: - -/* What is the name of the library to fuzz */ -#define TARGET_LIBRARY "libtestinstr.so" - -/* What is the name of the function to fuzz */ -#define TARGET_FUNCTION "testinstr" - -/* here you need to specify the parameter for the target function */ -static void *(*o_function)(uint8_t *, int); - -// END STEP 1 - -#include "frida-gum.h" - -G_BEGIN_DECLS - -#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type()) -G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM, - FAKE_EVENT_SINK, GObject) - -struct _GumFakeEventSink { - - GObject parent; - GumEventType mask; - -}; - -GumEventSink *gum_fake_event_sink_new(void); -void gum_fake_event_sink_reset(GumFakeEventSink *self); - -G_END_DECLS - -static void gum_fake_event_sink_iface_init(gpointer g_iface, - gpointer iface_data); -static void gum_fake_event_sink_finalize(GObject *obj); -static GumEventType gum_fake_event_sink_query_mask(GumEventSink *sink); -static void gum_fake_event_sink_process(GumEventSink *sink, const GumEvent *ev); -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data); -void afl_setup(void); -void afl_start_forkserver(void); -int __afl_persistent_loop(unsigned int max_cnt); - -static void gum_fake_event_sink_class_init(GumFakeEventSinkClass *klass) { - - GObjectClass *object_class = G_OBJECT_CLASS(klass); - object_class->finalize = gum_fake_event_sink_finalize; - -} - -static void gum_fake_event_sink_iface_init(gpointer g_iface, - gpointer iface_data) { - - GumEventSinkInterface *iface = (GumEventSinkInterface *)g_iface; - iface->query_mask = gum_fake_event_sink_query_mask; - iface->process = gum_fake_event_sink_process; - -} - -G_DEFINE_TYPE_EXTENDED(GumFakeEventSink, gum_fake_event_sink, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE(GUM_TYPE_EVENT_SINK, - gum_fake_event_sink_iface_init)) - -#include "../../config.h" - -// Shared memory fuzzing. -int __afl_sharedmem_fuzzing = 1; -extern unsigned int * __afl_fuzz_len; -extern unsigned char *__afl_fuzz_ptr; - -// Notify AFL about persistent mode. -static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; -int __afl_persistent_loop(unsigned int); - -// Notify AFL about deferred forkserver. -static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; -void __afl_manual_init(); - -// Because we do our own logging. -extern uint8_t * __afl_area_ptr; -static __thread guint64 previous_pc; - -// Frida stuff below. -typedef struct { - - GumAddress base_address; - guint64 code_start, code_end; - -} range_t; - -inline static void afl_maybe_log(guint64 current_pc) { - - // fprintf(stderr, "PC: %p ^ %p\n", current_pc, previous_pc); - - current_pc = (current_pc >> 4) ^ (current_pc << 8); - current_pc &= MAP_SIZE - 1; - - __afl_area_ptr[current_pc ^ previous_pc]++; - previous_pc = current_pc >> 1; - -} - -static void on_basic_block(GumCpuContext *context, gpointer user_data) { - - afl_maybe_log((guint64)user_data); - -} - -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data) { - - range_t *range = (range_t *)user_data; - - const cs_insn *instr; - gboolean begin = TRUE; - while (gum_stalker_iterator_next(iterator, &instr)) { - - if (begin) { - - if (instr->address >= range->code_start && - instr->address <= range->code_end) { - - gum_stalker_iterator_put_callout(iterator, on_basic_block, - (gpointer)instr->address, NULL); - begin = FALSE; - - } - - } - - gum_stalker_iterator_keep(iterator); - - } - -} - -static void gum_fake_event_sink_init(GumFakeEventSink *self) { - -} - -static void gum_fake_event_sink_finalize(GObject *obj) { - - G_OBJECT_CLASS(gum_fake_event_sink_parent_class)->finalize(obj); - -} - -GumEventSink *gum_fake_event_sink_new(void) { - - GumFakeEventSink *sink; - sink = (GumFakeEventSink *)g_object_new(GUM_TYPE_FAKE_EVENT_SINK, NULL); - return GUM_EVENT_SINK(sink); - -} - -void gum_fake_event_sink_reset(GumFakeEventSink *self) { - -} - -static GumEventType gum_fake_event_sink_query_mask(GumEventSink *sink) { - - return 0; - -} - -typedef struct library_list { - - uint8_t *name; - uint64_t addr_start, addr_end; - -} library_list_t; - -#define MAX_LIB_COUNT 256 -static library_list_t liblist[MAX_LIB_COUNT]; -static u32 liblist_cnt; - -void read_library_information() { - -#if defined(__linux__) - FILE *f; - u8 buf[1024], *b, *m, *e, *n; - - if ((f = fopen("/proc/self/maps", "r")) == NULL) { - - fprintf(stderr, "Error: cannot open /proc/self/maps\n"); - exit(-1); - - } - - if (debug) fprintf(stderr, "Library list:\n"); - while (fgets(buf, sizeof(buf), f)) { - - if (strstr(buf, " r-x")) { - - if (liblist_cnt >= MAX_LIB_COUNT) { - - fprintf( - stderr, - "Warning: too many libraries to old, maximum count of %d reached\n", - liblist_cnt); - return; - - } - - b = buf; - m = index(buf, '-'); - e = index(buf, ' '); - if ((n = rindex(buf, '/')) == NULL) n = rindex(buf, ' '); - if (n && - ((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '(')) - n = NULL; - else - n++; - if (b && m && e && n && *n) { - - *m++ = 0; - *e = 0; - if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0; - - if (rindex(n, '/') != NULL) { - - n = rindex(n, '/'); - n++; - - } - - liblist[liblist_cnt].name = strdup(n); - liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16); - liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16); - if (debug) - fprintf( - stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name, - liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, - liblist[liblist_cnt].addr_start, - liblist[liblist_cnt].addr_end - 1); - liblist_cnt++; - - } - - } - - } - - if (debug) fprintf(stderr, "\n"); - -#elif defined(__FreeBSD__) - int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; - char * buf, *start, *end; - size_t miblen = sizeof(mib) / sizeof(mib[0]); - size_t len; - - if (debug) fprintf(stderr, "Library list:\n"); - if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; } - - len = len * 4 / 3; - - buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); - if (buf == MAP_FAILED) { return; } - if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) { - - munmap(buf, len); - return; - - } - - start = buf; - end = buf + len; - - while (start < end) { - - struct kinfo_vmentry *region = (struct kinfo_vmentry *)start; - size_t size = region->kve_structsize; - - if (size == 0) { break; } - - if ((region->kve_protection & KVME_PROT_READ) && - !(region->kve_protection & KVME_PROT_EXEC)) { - - liblist[liblist_cnt].name = - region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0; - liblist[liblist_cnt].addr_start = region->kve_start; - liblist[liblist_cnt].addr_end = region->kve_end; - - if (debug) { - - fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name, - liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, - liblist[liblist_cnt].addr_start, - liblist[liblist_cnt].addr_end - 1); - - } - - liblist_cnt++; - - } - - start += size; - - } - -#endif - -} - -library_list_t *find_library(char *name) { - - char *filename = rindex(name, '/'); - - if (filename) - filename++; - else - filename = name; - -#if defined(__linux__) - u32 i; - for (i = 0; i < liblist_cnt; i++) - if (strcmp(liblist[i].name, filename) == 0) return &liblist[i]; -#elif defined(__APPLE__) && defined(__LP64__) - kern_return_t err; - static library_list_t lib; - - // get the list of all loaded modules from dyld - // the task_info mach API will get the address of the dyld all_image_info - // struct for the given task from which we can get the names and load - // addresses of all modules - task_dyld_info_data_t task_dyld_info; - mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; - err = task_info(mach_task_self(), TASK_DYLD_INFO, - (task_info_t)&task_dyld_info, &count); - - const struct dyld_all_image_infos *all_image_infos = - (const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr; - const struct dyld_image_info *image_infos = all_image_infos->infoArray; - - for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) { - - const char * image_name = image_infos[i].imageFilePath; - mach_vm_address_t image_load_address = - (mach_vm_address_t)image_infos[i].imageLoadAddress; - if (strstr(image_name, name)) { - - lib.name = name; - lib.addr_start = (u64)image_load_address; - lib.addr_end = 0; - return &lib; - - } - - } - -#endif - - return NULL; - -} - -static void gum_fake_event_sink_process(GumEventSink * sink, - const GumEvent *ev) { - -} - -/* Because this CAN be called more than once, it will return the LAST range */ -static int enumerate_ranges(const GumRangeDetails *details, - gpointer user_data) { - - GumMemoryRange *code_range = (GumMemoryRange *)user_data; - memcpy(code_range, details->range, sizeof(*code_range)); - return 0; - -} - -int main() { - -#ifndef __APPLE__ - (void)personality(ADDR_NO_RANDOMIZE); // disable ASLR -#endif - - // STEP 2: load the library you want to fuzz and lookup the functions, - // inclusive of the cleanup functions. - // If there is just one function, then there is nothing to change - // or add here. - - void *dl = dlopen(TARGET_LIBRARY, RTLD_LAZY); - if (!dl) { - - fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY); - exit(-1); - - } - - if (!(o_function = dlsym(dl, TARGET_FUNCTION))) { - - fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION); - exit(-1); - - } - - // END STEP 2 - - read_library_information(); - library_list_t *lib = find_library(TARGET_LIBRARY); - - if (lib == NULL) { - - fprintf(stderr, "Could not find target library\n"); - exit(-1); - - } - - gum_init_embedded(); - if (!gum_stalker_is_supported()) { - - gum_deinit_embedded(); - return 1; - - } - - GumStalker *stalker = gum_stalker_new(); - - /* - This does not work here as we load a shared library. pretty sure this - would also be easily solvable with frida gum, but I already have all the - code I need from afl-untracer - - GumAddress base_address = gum_module_find_base_address(TARGET_LIBRARY); - GumMemoryRange code_range; - gum_module_enumerate_ranges(TARGET_LIBRARY, GUM_PAGE_RX, enumerate_ranges, - &code_range); - guint64 code_start = code_range.base_address - base_address; - guint64 code_end = (code_range.base_address + code_range.size) - base_address; - range_t instr_range = {base_address, code_start, code_end}; - */ - range_t instr_range = {0, lib->addr_start, lib->addr_end}; - - GumStalkerTransformer *transformer = - gum_stalker_transformer_make_from_callback(instr_basic_block, - &instr_range, NULL); - - GumEventSink *event_sink = gum_fake_event_sink_new(); - - // to ensure that the signatures are not optimized out - memcpy(__afl_area_ptr, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT) + 1); - memcpy(__afl_area_ptr + 32, (void *)AFL_DEFER_FORKSVR, - sizeof(AFL_DEFER_FORKSVR) + 1); - __afl_manual_init(); - - // - // any expensive target library initialization that has to be done just once - // - put that here - // - - gum_stalker_follow_me(stalker, transformer, event_sink); - - while (__afl_persistent_loop(UINT32_MAX) != 0) { - - previous_pc = 0; // Required! - -#ifdef _DEBUG - fprintf(stderr, "CLIENT crc: %016llx len: %u\n", - hash64(__afl_fuzz_ptr, *__afl_fuzz_len), *__afl_fuzz_len); - fprintf(stderr, "RECV:"); - for (int i = 0; i < *__afl_fuzz_len; i++) - fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); - fprintf(stderr, "\n"); -#endif - - // STEP 3: ensure the minimum length is present and setup the target - // function to fuzz. - - if (*__afl_fuzz_len > 0) { - - __afl_fuzz_ptr[*__afl_fuzz_len] = 0; // if you need to null terminate - (*o_function)(__afl_fuzz_ptr, *__afl_fuzz_len); - - } - - // END STEP 3 - - } - - gum_stalker_unfollow_me(stalker); - - while (gum_stalker_garbage_collect(stalker)) - g_usleep(10000); - - g_object_unref(stalker); - g_object_unref(transformer); - g_object_unref(event_sink); - gum_deinit_embedded(); - - return 0; - -} - diff --git a/examples/afl_frida/afl-frida.h b/examples/afl_frida/afl-frida.h deleted file mode 100644 index efa3440f..00000000 --- a/examples/afl_frida/afl-frida.h +++ /dev/null @@ -1,53 +0,0 @@ -extern int is_persistent; - -G_BEGIN_DECLS - -#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type()) - -G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM, - FAKE_EVENT_SINK, GObject) - -struct _GumFakeEventSink { - - GObject parent; - GumEventType mask; - -}; - -GumEventSink *gum_fake_event_sink_new(void); -void gum_fake_event_sink_reset(GumFakeEventSink *self); - -G_END_DECLS - -typedef struct { - - GumAddress base_address; - guint64 code_start, code_end; - -} range_t; - -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data); -#pragma once - -void afl_setup(void); -void afl_start_forkserver(void); -int __afl_persistent_loop(unsigned int max_cnt); - -inline static inline void afl_maybe_log(guint64 current_pc) { - - extern unsigned int afl_instr_rms; - extern uint8_t * afl_area_ptr; - - static __thread guint64 previous_pc; - - current_pc = (current_pc >> 4) ^ (current_pc << 8); - current_pc &= MAP_SIZE - 1; - - if (current_pc >= afl_instr_rms) return; - - afl_area_ptr[current_pc ^ previous_pc]++; - previous_pc = current_pc >> 1; - -} - diff --git a/examples/afl_frida/libtestinstr.c b/examples/afl_frida/libtestinstr.c deleted file mode 100644 index 96b1cf21..00000000 --- a/examples/afl_frida/libtestinstr.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - american fuzzy lop++ - a trivial program to test the build - -------------------------------------------------------- - Originally written by Michal Zalewski - Copyright 2014 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - http://www.apache.org/licenses/LICENSE-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include - -void testinstr(char *buf, int len) { - - if (len < 1) return; - buf[len] = 0; - - // we support three input cases - if (buf[0] == '0') - printf("Looks like a zero to me!\n"); - else if (buf[0] == '1') - printf("Pretty sure that is a one!\n"); - else - printf("Neither one or zero? How quaint!\n"); - -} - diff --git a/examples/afl_network_proxy/GNUmakefile b/examples/afl_network_proxy/GNUmakefile deleted file mode 100644 index 25a3df82..00000000 --- a/examples/afl_network_proxy/GNUmakefile +++ /dev/null @@ -1,43 +0,0 @@ -PREFIX ?= /usr/local -BIN_PATH = $(PREFIX)/bin -DOC_PATH = $(PREFIX)/share/doc/afl - -PROGRAMS = afl-network-client afl-network-server - -HASH=\# - -CFLAGS += -Wno-pointer-sign - -ifdef STATIC - CFLAGS += -static -endif - -ifeq "$(shell echo '$(HASH)include @int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" - CFLAGS += -DUSE_DEFLATE=1 - LDFLAGS += -ldeflate - $(info libdeflate-dev was detected, using compression) -else - $(warn did not find libdeflate-dev, cannot use compression) -endif - -all: $(PROGRAMS) - -help: - @echo make options: - @echo STATIC - build as static binaries - @echo COMPRESS_TESTCASES - compress test cases - -afl-network-client: afl-network-client.c - $(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c $(LDFLAGS) - -afl-network-server: afl-network-server.c - $(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" $(LDFLAGS) - -clean: - rm -f $(PROGRAMS) *~ core - -install: all - install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(DOC_PATH) - install -m 755 $(PROGRAMS) $${DESTDIR}$(BIN_PATH) - install -T -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md - diff --git a/examples/afl_network_proxy/Makefile b/examples/afl_network_proxy/Makefile deleted file mode 100644 index 0b306dde..00000000 --- a/examples/afl_network_proxy/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - @echo please use GNU make, thanks! diff --git a/examples/afl_network_proxy/README.md b/examples/afl_network_proxy/README.md deleted file mode 100644 index a5ac3578..00000000 --- a/examples/afl_network_proxy/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# afl-network-proxy - -If you want to run afl-fuzz over the network than this is what you need :) -Note that the impact on fuzzing speed will be huge, expect a loss of 90%. - -## When to use this - -1. when you have to fuzz a target that has to run on a system that cannot - contain the fuzzing output (e.g. /tmp too small and file system is read-only) -2. when the target instantly reboots on crashes -3. ... any other reason you would need this - -## how to get it running - -### Compiling - -Just type `make` and let the autodetection do everything for you. - -Note that you will get a 40-50% performance increase if you have libdeflate-dev -installed. The GNUmakefile will autodetect it if present. - -If your target has large test cases (10+kb) that are ascii only or large chunks -of zero blocks then set `CFLAGS=-DCOMPRESS_TESTCASES=1` to compress them. -For most targets this hurts performance though so it is disabled by default. - -### on the target - -Run `afl-network-server` with your target with the -m and -t values you need. -Important is the -i parameter which is the TCP port to listen on. -e.g.: -``` -afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@ -``` - -### on the (afl-fuzz) master - -Just run afl-fuzz with your normal options, however the target should be -`afl-network-client` with the IP and PORT of the `afl-network-server` and -increase the -t value: -``` -afl-fuzz -i in -o out -t 2000+ -- afl-network-client TARGET-IP 1111 -``` -Note the '+' on the -t parameter value. The afl-network-server will take -care of proper timeouts hence afl-fuzz should not. The '+' increases the -timeout and the value itself should be 500-1000 higher than the one on -afl-network-server. - -### networking - -The TARGET can be an IPv4 or IPv6 address, or a host name that resolves to -either. Note that also the outgoing interface can be specified with a '%' for -`afl-network-client`, e.g. `fe80::1234%eth0`. - -Also make sure your default TCP window size is larger than your MAP_SIZE -(130kb is a good value). -On Linux that is the middle value of `/proc/sys/net/ipv4/tcp_rmem` - -## how to compile and install - -`make && sudo make install` - diff --git a/examples/afl_network_proxy/afl-network-client.c b/examples/afl_network_proxy/afl-network-client.c deleted file mode 100644 index a2451fdc..00000000 --- a/examples/afl_network_proxy/afl-network-client.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - american fuzzy lop++ - afl-network-client - --------------------------------------- - - Written by Marc Heuse - - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - -*/ - -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif -#include "config.h" -#include "types.h" -#include "debug.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#ifndef USEMMAP - #include -#endif -#include -#include -#include -#include -#include - -#ifdef USE_DEFLATE - #include -#endif - -u8 *__afl_area_ptr; - -#ifdef __ANDROID__ -u32 __afl_map_size = MAP_SIZE; -#else -__thread u32 __afl_map_size = MAP_SIZE; -#endif - -/* Error reporting to forkserver controller */ - -void send_forkserver_error(int error) { - - u32 status; - if (!error || error > 0xffff) return; - status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); - if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; - -} - -/* SHM setup. */ - -static void __afl_map_shm(void) { - - char *id_str = getenv(SHM_ENV_VAR); - char *ptr; - - if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { - - u32 val = atoi(ptr); - if (val > 0) __afl_map_size = val; - - } - - if (__afl_map_size > MAP_SIZE) { - - if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { - - fprintf(stderr, - "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " - "be able to run this instrumented program!\n", - __afl_map_size); - if (id_str) { - - send_forkserver_error(FS_ERROR_MAP_SIZE); - exit(-1); - - } - - } else { - - fprintf(stderr, - "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " - "be able to run this instrumented program!\n", - __afl_map_size); - - } - - } - - if (id_str) { - -#ifdef USEMMAP - const char * shm_file_path = id_str; - int shm_fd = -1; - unsigned char *shm_base = NULL; - - /* create the shared memory segment as if it was a file */ - shm_fd = shm_open(shm_file_path, O_RDWR, 0600); - if (shm_fd == -1) { - - fprintf(stderr, "shm_open() failed\n"); - send_forkserver_error(FS_ERROR_SHM_OPEN); - exit(1); - - } - - /* map the shared memory segment to the address space of the process */ - shm_base = - mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - - if (shm_base == MAP_FAILED) { - - close(shm_fd); - shm_fd = -1; - - fprintf(stderr, "mmap() failed\n"); - send_forkserver_error(FS_ERROR_MMAP); - exit(2); - - } - - __afl_area_ptr = shm_base; -#else - u32 shm_id = atoi(id_str); - - __afl_area_ptr = shmat(shm_id, 0, 0); - -#endif - - if (__afl_area_ptr == (void *)-1) { - - send_forkserver_error(FS_ERROR_SHMAT); - exit(1); - - } - - /* Write something into the bitmap so that the parent doesn't give up */ - - __afl_area_ptr[0] = 1; - - } - -} - -/* Fork server logic. */ - -static void __afl_start_forkserver(void) { - - u8 tmp[4] = {0, 0, 0, 0}; - u32 status = 0; - - if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) - status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); - if (status) status |= (FS_OPT_ENABLED); - memcpy(tmp, &status, 4); - - /* Phone home and tell the parent that we're OK. */ - - if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; - -} - -static u32 __afl_next_testcase(u8 *buf, u32 max_len) { - - s32 status, res = 0x0fffffff; // res is a dummy pid - - /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, &status, 4) != 4) return 0; - - /* we have a testcase - read it */ - status = read(0, buf, max_len); - - /* report that we are starting the target */ - if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; - - if (status < 1) - return 0; - else - return status; - -} - -static void __afl_end_testcase(int status) { - - if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); - -} - -/* you just need to modify the while() loop in this main() */ - -int main(int argc, char *argv[]) { - - u8 * interface, *buf, *ptr; - s32 s = -1; - struct addrinfo hints, *hres, *aip; - u32 * lenptr, max_len = 65536; -#ifdef USE_DEFLATE - u8 * buf2; - u32 * lenptr1, *lenptr2, buf2_len, compress_len; - size_t decompress_len; -#endif - - if (argc < 3 || argc > 4) { - - printf("Syntax: %s host port [max-input-size]\n\n", argv[0]); - printf("Requires host and port of the remote afl-proxy-server instance.\n"); - printf( - "IPv4 and IPv6 are supported, also binding to an interface with " - "\"%%\"\n"); - printf("The max-input-size default is %u.\n", max_len); - printf( - "The default map size is %u and can be changed with setting " - "AFL_MAP_SIZE.\n", - __afl_map_size); - exit(-1); - - } - - if ((interface = strchr(argv[1], '%')) != NULL) *interface++ = 0; - - if (argc > 3) - if ((max_len = atoi(argv[3])) < 0) - FATAL("max-input-size may not be negative or larger than 2GB: %s", - argv[3]); - - if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) - if ((__afl_map_size = atoi(ptr)) < 8) - FATAL("illegal map size, may not be < 8 or >= 2^30: %s", ptr); - - if ((buf = malloc(max_len + 4)) == NULL) - PFATAL("can not allocate %u memory", max_len + 4); - lenptr = (u32 *)buf; - -#ifdef USE_DEFLATE - buf2_len = (max_len > __afl_map_size ? max_len : __afl_map_size); - if ((buf2 = malloc(buf2_len + 8)) == NULL) - PFATAL("can not allocate %u memory", buf2_len + 8); - lenptr1 = (u32 *)buf2; - lenptr2 = (u32 *)(buf2 + 4); -#endif - - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = PF_UNSPEC; - - if (getaddrinfo(argv[1], argv[2], &hints, &hres) != 0) - PFATAL("could not resolve target %s", argv[1]); - - for (aip = hres; aip != NULL && s == -1; aip = aip->ai_next) { - - if ((s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) >= 0) { - -#ifdef SO_BINDTODEVICE - if (interface != NULL) - if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface, - strlen(interface) + 1) < 0) - fprintf(stderr, "Warning: could not bind to device %s\n", interface); -#else - fprintf(stderr, - "Warning: binding to interface is not supported for your OS\n"); -#endif - -#ifdef SO_PRIORITY - int priority = 7; - if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < - 0) { - - priority = 6; - if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, - sizeof(priority)) < 0) - WARNF("could not set priority on socket"); - - } - -#endif - - if (connect(s, aip->ai_addr, aip->ai_addrlen) == -1) s = -1; - - } - - } - -#ifdef USE_DEFLATE - struct libdeflate_compressor *compressor; - compressor = libdeflate_alloc_compressor(1); - struct libdeflate_decompressor *decompressor; - decompressor = libdeflate_alloc_decompressor(); - fprintf(stderr, "Compiled with compression support\n"); -#endif - - if (s == -1) - FATAL("could not connect to target tcp://%s:%s", argv[1], argv[2]); - else - fprintf(stderr, "Connected to target tcp://%s:%s\n", argv[1], argv[2]); - - /* we initialize the shared memory map and start the forkserver */ - __afl_map_shm(); - __afl_start_forkserver(); - - int i = 1, j, status, ret, received; - - // fprintf(stderr, "Waiting for first testcase\n"); - while ((*lenptr = __afl_next_testcase(buf + 4, max_len)) > 0) { - - // fprintf(stderr, "Sending testcase with len %u\n", *lenptr); -#ifdef USE_DEFLATE - #ifdef COMPRESS_TESTCASES - // we only compress the testcase if it does not fit in the TCP packet - if (*lenptr > 1500 - 20 - 32 - 4) { - - // set highest byte to signify compression - *lenptr1 = (*lenptr | 0xff000000); - *lenptr2 = (u32)libdeflate_deflate_compress(compressor, buf + 4, *lenptr, - buf2 + 8, buf2_len); - if (send(s, buf2, *lenptr2 + 8, 0) != *lenptr2 + 8) - PFATAL("sending test data failed"); - // fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2); - // for (u32 i = 0; i < *lenptr; i++) - // fprintf(stderr, "%02x", buf[i + 4]); - // fprintf(stderr, "\n"); - // for (u32 i = 0; i < *lenptr2; i++) - // fprintf(stderr, "%02x", buf2[i + 8]); - // fprintf(stderr, "\n"); - - } else { - - #endif -#endif - if (send(s, buf, *lenptr + 4, 0) != *lenptr + 4) - PFATAL("sending test data failed"); -#ifdef USE_DEFLATE - #ifdef COMPRESS_TESTCASES - // fprintf(stderr, "unCOMPRESS (%u)\n", *lenptr); - - } - - #endif -#endif - - received = 0; - while (received < 4 && - (ret = recv(s, &status + received, 4 - received, 0)) > 0) - received += ret; - if (received != 4) - FATAL("did not receive waitpid data (%d, %d)", received, ret); - // fprintf(stderr, "Received status\n"); - - received = 0; -#ifdef USE_DEFLATE - while (received < 4 && - (ret = recv(s, &compress_len + received, 4 - received, 0)) > 0) - received += ret; - if (received != 4) - FATAL("did not receive compress_len (%d, %d)", received, ret); - // fprintf(stderr, "Received status\n"); - - received = 0; - while (received < compress_len && - (ret = recv(s, buf2 + received, buf2_len - received, 0)) > 0) - received += ret; - if (received != compress_len) - FATAL("did not receive coverage data (%d, %d)", received, ret); - - if (libdeflate_deflate_decompress(decompressor, buf2, compress_len, - __afl_area_ptr, __afl_map_size, - &decompress_len) != LIBDEFLATE_SUCCESS || - decompress_len != __afl_map_size) - FATAL("decompression failed"); - // fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len); - // for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x", - // __afl_area_ptr[i]); fprintf(stderr, "\n"); -#else - while (received < __afl_map_size && - (ret = recv(s, __afl_area_ptr + received, __afl_map_size - received, - 0)) > 0) - received += ret; - if (received != __afl_map_size) - FATAL("did not receive coverage data (%d, %d)", received, ret); -#endif - // fprintf(stderr, "Received coverage\n"); - - /* report the test case is done and wait for the next */ - __afl_end_testcase(status); - // fprintf(stderr, "Waiting for next testcase %d\n", ++i); - - } - -#ifdef USE_DEFLATE - libdeflate_free_compressor(compressor); - libdeflate_free_decompressor(decompressor); -#endif - - return 0; - -} - diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c deleted file mode 100644 index 513dc8f2..00000000 --- a/examples/afl_network_proxy/afl-network-server.c +++ /dev/null @@ -1,720 +0,0 @@ -/* - american fuzzy lop++ - network proxy server - ------------------------------------------- - - Originally written by Michal Zalewski - - Forkserver design by Jann Horn - - Now maintained by Marc Heuse , - Heiko Eißfeldt and - Andrea Fioraldi and - Dominik Maier - - Copyright 2016, 2017 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - */ - -#define AFL_MAIN - -#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 "common.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef USE_DEFLATE - #include -struct libdeflate_compressor * compressor; -struct libdeflate_decompressor *decompressor; -#endif - -static u8 *in_file, /* Minimizer input test case */ - *out_file; - -static u8 *in_data; /* Input data for trimming */ -static u8 *buf2; - -static s32 in_len; -static s32 buf2_len; -static u32 map_size = MAP_SIZE; - -static volatile u8 stop_soon; /* Ctrl-C pressed? */ - -/* See if any bytes are set in the bitmap. */ - -static inline u8 anything_set(afl_forkserver_t *fsrv) { - - u32 *ptr = (u32 *)fsrv->trace_bits; - u32 i = (map_size >> 2); - - while (i--) { - - if (*(ptr++)) { return 1; } - - } - - return 0; - -} - -static void at_exit_handler(void) { - - afl_fsrv_killall(); - -} - -/* Write output file. */ - -static s32 write_to_file(u8 *path, u8 *mem, u32 len) { - - s32 ret; - - unlink(path); /* Ignore errors */ - - ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600); - - if (ret < 0) { PFATAL("Unable to create '%s'", path); } - - ck_write(ret, mem, len, path); - - lseek(ret, 0, SEEK_SET); - - return ret; - -} - -/* Execute target application. Returns 0 if the changes are a dud, or - 1 if they should be kept. */ - -static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, - u8 first_run) { - - afl_fsrv_write_to_testcase(fsrv, mem, len); - - fsrv_run_result_t ret = - afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon); - - if (ret == FSRV_RUN_ERROR) { FATAL("Couldn't run child"); } - - if (stop_soon) { - - SAYF(cRST cLRD "\n+++ aborted by user +++\n" cRST); - exit(1); - - } - - return ret; - -} - -/* Handle Ctrl-C and the like. */ - -static void handle_stop_sig(int sig) { - - stop_soon = 1; - afl_fsrv_killall(); - -} - -/* Do basic preparations - persistent fds, filenames, etc. */ - -static void set_up_environment(afl_forkserver_t *fsrv) { - - u8 *x; - - fsrv->dev_null_fd = open("/dev/null", O_RDWR); - if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } - - if (!out_file) { - - u8 *use_dir = "."; - - if (access(use_dir, R_OK | W_OK | X_OK)) { - - use_dir = get_afl_env("TMPDIR"); - if (!use_dir) { use_dir = "/tmp"; } - - } - - out_file = alloc_printf("%s/.afl-input-temp-%u", use_dir, getpid()); - - } - - unlink(out_file); - - fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600); - - if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); } - - /* Set sane defaults... */ - - x = get_afl_env("ASAN_OPTIONS"); - - if (x) { - - if (!strstr(x, "abort_on_error=1")) { - - FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); - - } - - if (!strstr(x, "symbolize=0")) { - - FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!"); - - } - - } - - x = get_afl_env("MSAN_OPTIONS"); - - if (x) { - - if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) { - - FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY( - MSAN_ERROR) " - please fix!"); - - } - - if (!strstr(x, "symbolize=0")) { - - FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); - - } - - } - - setenv("ASAN_OPTIONS", - "abort_on_error=1:" - "detect_leaks=0:" - "symbolize=0:" - "allocator_may_return_null=1", - 0); - - setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" - "symbolize=0:" - "abort_on_error=1:" - "allocator_may_return_null=1:" - "msan_track_origins=0", 0); - - if (get_afl_env("AFL_PRELOAD")) { - - if (fsrv->qemu_mode) { - - u8 *qemu_preload = getenv("QEMU_SET_ENV"); - u8 *afl_preload = getenv("AFL_PRELOAD"); - u8 *buf; - - s32 i, afl_preload_size = strlen(afl_preload); - for (i = 0; i < afl_preload_size; ++i) { - - if (afl_preload[i] == ',') { - - PFATAL( - "Comma (',') is not allowed in AFL_PRELOAD when -Q is " - "specified!"); - - } - - } - - if (qemu_preload) { - - buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s", - qemu_preload, afl_preload, afl_preload); - - } else { - - buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s", - afl_preload, afl_preload); - - } - - setenv("QEMU_SET_ENV", buf, 1); - - afl_free(buf); - - } else { - - setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); - setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); - - } - - } - -} - -/* Setup signal handlers, duh. */ - -static void setup_signal_handlers(void) { - - struct sigaction sa; - - sa.sa_handler = NULL; - sa.sa_flags = SA_RESTART; - sa.sa_sigaction = NULL; - - sigemptyset(&sa.sa_mask); - - /* Various ways of saying "stop". */ - - sa.sa_handler = handle_stop_sig; - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - -} - -/* Display usage hints. */ - -static void usage(u8 *argv0) { - - SAYF( - "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" - - "Required parameters:\n" - - " -i port - the port to listen for the client to connect to\n\n" - - "Execution control settings:\n" - - " -f file - input file read by the tested program (stdin)\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" - " -W - use qemu-based instrumentation with Wine (Wine " - "mode)\n\n" - - "Environment variables used:\n" - "TMPDIR: directory to use for temporary input files\n" - "ASAN_OPTIONS: custom settings for ASAN\n" - " (must contain abort_on_error=1 and symbolize=0)\n" - "MSAN_OPTIONS: custom settings for MSAN\n" - " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" - "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" - " the target was compiled for\n" - "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" - - , argv0, EXEC_TIMEOUT, MEM_LIMIT); - - exit(1); - -} - -int recv_testcase(int s, void **buf) { - - u32 size; - s32 ret; - size_t received; - - received = 0; - while (received < 4 && (ret = recv(s, &size + received, 4 - received, 0)) > 0) - received += ret; - if (received != 4) FATAL("did not receive size information"); - if (size == 0) FATAL("did not receive valid size information"); - // fprintf(stderr, "received size information of %d\n", size); - - if ((size & 0xff000000) != 0xff000000) { - - *buf = afl_realloc(buf, size); - if (unlikely(!*buf)) { PFATAL("Alloc"); } - received = 0; - // fprintf(stderr, "unCOMPRESS (%u)\n", size); - while (received < size && - (ret = recv(s, ((char *)*buf) + received, size - received, 0)) > 0) - received += ret; - - } else { - -#ifdef USE_DEFLATE - u32 clen; - size -= 0xff000000; - *buf = afl_realloc(buf, size); - if (unlikely(!*buf)) { PFATAL("Alloc"); } - received = 0; - while (received < 4 && - (ret = recv(s, &clen + received, 4 - received, 0)) > 0) - received += ret; - if (received != 4) FATAL("did not receive clen1 information"); - // fprintf(stderr, "received clen information of %d\n", clen); - if (clen < 1) - FATAL("did not receive valid compressed len information: %u", clen); - buf2 = afl_realloc((void **)&buf2, clen); - buf2_len = clen; - if (unlikely(!buf2)) { PFATAL("Alloc"); } - received = 0; - while (received < clen && - (ret = recv(s, buf2 + received, clen - received, 0)) > 0) - received += ret; - if (received != clen) FATAL("did not receive compressed information"); - if (libdeflate_deflate_decompress(decompressor, buf2, clen, (char *)*buf, - size, &received) != LIBDEFLATE_SUCCESS) - FATAL("decompression failed"); - // fprintf(stderr, "DECOMPRESS (%u->%u):\n", clen, received); - // for (u32 i = 0; i < clen; i++) fprintf(stderr, "%02x", buf2[i]); - // fprintf(stderr, "\n"); - // for (u32 i = 0; i < received; i++) fprintf(stderr, "%02x", - // ((u8*)(*buf))[i]); fprintf(stderr, "\n"); -#else - FATAL("Received compressed data but not compiled with compression support"); -#endif - - } - - // fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len); - if (received != size) - FATAL("did not receive testcase data %lu != %u, %d", received, size, ret); - // fprintf(stderr, "received testcase\n"); - return size; - -} - -/* Main entry point */ - -int main(int argc, char **argv_orig, char **envp) { - - s32 opt, s, sock, on = 1, port = -1; - u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; - char **use_argv; - struct sockaddr_in6 serveraddr, clientaddr; - int addrlen = sizeof(clientaddr); - char str[INET6_ADDRSTRLEN]; - char ** argv = argv_cpy_dup(argc, argv_orig); - u8 * send_buf; -#ifdef USE_DEFLATE - u32 *lenptr; -#endif - - afl_forkserver_t fsrv_var = {0}; - afl_forkserver_t *fsrv = &fsrv_var; - afl_fsrv_init(fsrv); - map_size = get_map_size(); - fsrv->map_size = map_size; - - if ((send_buf = malloc(map_size + 4)) == NULL) PFATAL("malloc"); - - while ((opt = getopt(argc, argv, "+i:f:m:t:QUWh")) > 0) { - - switch (opt) { - - case 'i': - - if (port > 0) { FATAL("Multiple -i options not supported"); } - port = atoi(optarg); - if (port < 1 || port > 65535) - FATAL("invalid port definition, must be between 1-65535: %s", optarg); - break; - - case 'f': - - if (out_file) { FATAL("Multiple -f options not supported"); } - fsrv->use_stdin = 0; - out_file = optarg; - break; - - case 'm': { - - u8 suffix = 'M'; - - if (mem_limit_given) { FATAL("Multiple -m options not supported"); } - mem_limit_given = 1; - - if (!optarg) { FATAL("Wrong usage of -m"); } - - if (!strcmp(optarg, "none")) { - - fsrv->mem_limit = 0; - break; - - } - - if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 || - optarg[0] == '-') { - - FATAL("Bad syntax used for -m"); - - } - - switch (suffix) { - - case 'T': - fsrv->mem_limit *= 1024 * 1024; - break; - case 'G': - fsrv->mem_limit *= 1024; - break; - case 'k': - fsrv->mem_limit /= 1024; - break; - case 'M': - break; - - default: - FATAL("Unsupported suffix or bad syntax for -m"); - - } - - if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); } - - if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) { - - FATAL("Value of -m out of range on 32-bit systems"); - - } - - } - - break; - - case 't': - - if (timeout_given) { FATAL("Multiple -t options not supported"); } - timeout_given = 1; - - if (!optarg) { FATAL("Wrong usage of -t"); } - - fsrv->exec_tmout = atoi(optarg); - - if (fsrv->exec_tmout < 10 || optarg[0] == '-') { - - FATAL("Dangerously low value of -t"); - - } - - break; - - case 'Q': - - if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } - if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; } - - fsrv->qemu_mode = 1; - break; - - case 'U': - - if (unicorn_mode) { FATAL("Multiple -Q options not supported"); } - if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; } - - unicorn_mode = 1; - break; - - case 'W': /* Wine+QEMU mode */ - - if (use_wine) { FATAL("Multiple -W options not supported"); } - fsrv->qemu_mode = 1; - use_wine = 1; - - if (!mem_limit_given) { fsrv->mem_limit = 0; } - - break; - - case 'h': - usage(argv[0]); - return -1; - break; - - default: - usage(argv[0]); - - } - - } - - if (optind == argc || port < 1) { usage(argv[0]); } - - check_environment_vars(envp); - - sharedmem_t shm = {0}; - fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); - - in_data = afl_realloc((void **)&in_data, 65536); - if (unlikely(!in_data)) { PFATAL("Alloc"); } - - atexit(at_exit_handler); - setup_signal_handlers(); - - set_up_environment(fsrv); - - fsrv->target_path = find_binary(argv[optind]); - detect_file_args(argv + optind, out_file, &fsrv->use_stdin); - - if (fsrv->qemu_mode) { - - if (use_wine) { - - use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind, - argv + optind); - - } else { - - use_argv = get_qemu_argv(argv[0], &fsrv->target_path, argc - optind, - argv + optind); - - } - - } else { - - use_argv = argv + optind; - - } - - if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) PFATAL("socket() failed"); - -#ifdef SO_REUSEADDR - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) { - - WARNF("setsockopt(SO_REUSEADDR) failed"); - - } - -#endif - -#ifdef SO_PRIORITY - int priority = 7; - if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < - 0) { - - priority = 6; - if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < - 0) - WARNF("could not set priority on socket"); - - } - -#endif - - memset(&serveraddr, 0, sizeof(serveraddr)); - serveraddr.sin6_family = AF_INET6; - serveraddr.sin6_port = htons(port); - serveraddr.sin6_addr = in6addr_any; - - if (bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) - PFATAL("bind() failed"); - - if (listen(sock, 1) < 0) { PFATAL("listen() failed"); } - - afl_fsrv_start( - fsrv, use_argv, &stop_soon, - (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) - ? 1 - : 0); - -#ifdef USE_DEFLATE - compressor = libdeflate_alloc_compressor(1); - decompressor = libdeflate_alloc_decompressor(); - buf2 = afl_realloc((void **)&buf2, map_size + 16); - buf2_len = map_size + 16; - if (unlikely(!buf2)) { PFATAL("alloc"); } - lenptr = (u32 *)(buf2 + 4); - fprintf(stderr, "Compiled with compression support\n"); -#endif - - fprintf(stderr, - "Waiting for incoming connection from afl-network-client on port %d " - "...\n", - port); - - if ((s = accept(sock, NULL, NULL)) < 0) { PFATAL("accept() failed"); } - fprintf(stderr, "Received connection, starting ...\n"); - -#ifdef SO_PRIORITY - priority = 7; - if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) { - - priority = 6; - if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) - WARNF("could not set priority on socket"); - - } - -#endif - - while ((in_len = recv_testcase(s, (void **)&in_data)) > 0) { - - // fprintf(stderr, "received %u\n", in_len); - (void)run_target(fsrv, use_argv, in_data, in_len, 1); - - memcpy(send_buf + 4, fsrv->trace_bits, fsrv->map_size); - -#ifdef USE_DEFLATE - memcpy(buf2, &fsrv->child_status, 4); - *lenptr = (u32)libdeflate_deflate_compress( - compressor, send_buf + 4, fsrv->map_size, buf2 + 8, buf2_len - 8); - // fprintf(stderr, "COMPRESS (%u->%u): ", fsrv->map_size, *lenptr); - // for (u32 i = 0; i < fsrv->map_size; i++) fprintf(stderr, "%02x", - // fsrv->trace_bits[i]); fprintf(stderr, "\n"); - if (send(s, buf2, *lenptr + 8, 0) != 8 + *lenptr) - FATAL("could not send data"); -#else - memcpy(send_buf, &fsrv->child_status, 4); - if (send(s, send_buf, fsrv->map_size + 4, 0) != 4 + fsrv->map_size) - FATAL("could not send data"); -#endif - - // fprintf(stderr, "sent result\n"); - - } - - unlink(out_file); - if (out_file) { ck_free(out_file); } - out_file = NULL; - - afl_shm_deinit(&shm); - afl_fsrv_deinit(fsrv); - if (fsrv->target_path) { ck_free(fsrv->target_path); } - afl_free(in_data); -#if USE_DEFLATE - afl_free(buf2); - libdeflate_free_compressor(compressor); - libdeflate_free_decompressor(decompressor); -#endif - - argv_cpy_free(argv); - - exit(0); - -} - diff --git a/examples/afl_proxy/Makefile b/examples/afl_proxy/Makefile deleted file mode 100644 index 4b368f8d..00000000 --- a/examples/afl_proxy/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: afl-proxy - -afl-proxy: afl-proxy.c - $(CC) -I../../include -o afl-proxy afl-proxy.c - -clean: - rm -f afl-proxy *~ core diff --git a/examples/afl_proxy/README.md b/examples/afl_proxy/README.md deleted file mode 100644 index 3c768a19..00000000 --- a/examples/afl_proxy/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# afl-proxy - -afl-proxy is an example skeleton file which can easily be used to fuzz -and instrument non-standard things. - -You only need to change the while() loop of the main() to send the -data of buf[] with length len to the target and write the coverage -information to __afl_area_ptr[__afl_map_size] - diff --git a/examples/afl_proxy/afl-proxy.c b/examples/afl_proxy/afl-proxy.c deleted file mode 100644 index f2dfeac1..00000000 --- a/examples/afl_proxy/afl-proxy.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - american fuzzy lop++ - afl-proxy skeleton example - --------------------------------------------------- - - Written by Marc Heuse - - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - - HOW-TO - ====== - - You only need to change the while() loop of the main() to send the - data of buf[] with length len to the target and write the coverage - information to __afl_area_ptr[__afl_map_size] - - -*/ - -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif -#include "config.h" -#include "types.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -u8 *__afl_area_ptr; - -#ifdef __ANDROID__ -u32 __afl_map_size = MAP_SIZE; -#else -__thread u32 __afl_map_size = MAP_SIZE; -#endif - -/* Error reporting to forkserver controller */ - -void send_forkserver_error(int error) { - - u32 status; - if (!error || error > 0xffff) return; - status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); - if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; - -} - -/* SHM setup. */ - -static void __afl_map_shm(void) { - - char *id_str = getenv(SHM_ENV_VAR); - char *ptr; - - if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { - - u32 val = atoi(ptr); - if (val > 0) __afl_map_size = val; - - } - - if (__afl_map_size > MAP_SIZE) { - - if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { - - fprintf(stderr, - "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " - "be able to run this instrumented program!\n", - __afl_map_size); - if (id_str) { - - send_forkserver_error(FS_ERROR_MAP_SIZE); - exit(-1); - - } - - } else { - - fprintf(stderr, - "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " - "be able to run this instrumented program!\n", - __afl_map_size); - - } - - } - - if (id_str) { - -#ifdef USEMMAP - const char * shm_file_path = id_str; - int shm_fd = -1; - unsigned char *shm_base = NULL; - - /* create the shared memory segment as if it was a file */ - shm_fd = shm_open(shm_file_path, O_RDWR, 0600); - if (shm_fd == -1) { - - fprintf(stderr, "shm_open() failed\n"); - send_forkserver_error(FS_ERROR_SHM_OPEN); - exit(1); - - } - - /* map the shared memory segment to the address space of the process */ - shm_base = - mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - - if (shm_base == MAP_FAILED) { - - close(shm_fd); - shm_fd = -1; - - fprintf(stderr, "mmap() failed\n"); - send_forkserver_error(FS_ERROR_MMAP); - exit(2); - - } - - __afl_area_ptr = shm_base; -#else - u32 shm_id = atoi(id_str); - - __afl_area_ptr = shmat(shm_id, 0, 0); - -#endif - - if (__afl_area_ptr == (void *)-1) { - - send_forkserver_error(FS_ERROR_SHMAT); - exit(1); - - } - - /* Write something into the bitmap so that the parent doesn't give up */ - - __afl_area_ptr[0] = 1; - - } - -} - -/* Fork server logic. */ - -static void __afl_start_forkserver(void) { - - u8 tmp[4] = {0, 0, 0, 0}; - u32 status = 0; - - if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) - status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); - if (status) status |= (FS_OPT_ENABLED); - memcpy(tmp, &status, 4); - - /* Phone home and tell the parent that we're OK. */ - - if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; - -} - -static u32 __afl_next_testcase(u8 *buf, u32 max_len) { - - s32 status, res = 0xffffff; - - /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, &status, 4) != 4) return 0; - - /* we have a testcase - read it */ - status = read(0, buf, max_len); - - /* report that we are starting the target */ - if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; - - if (status < 1) - return 0; - else - return status; - -} - -static void __afl_end_testcase(void) { - - int status = 0xffffff; - - if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); - -} - -/* you just need to modify the while() loop in this main() */ - -int main(int argc, char *argv[]) { - - /* This is were the testcase data is written into */ - u8 buf[1024]; // this is the maximum size for a test case! set it! - u32 len; - - /* here you specify the map size you need that you are reporting to - afl-fuzz. */ - __afl_map_size = MAP_SIZE; // default is 65536 - - /* then we initialize the shared memory map and start the forkserver */ - __afl_map_shm(); - __afl_start_forkserver(); - - while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { - - /* here you have to create the magic that feeds the buf/len to the - target and write the coverage to __afl_area_ptr */ - - // ... the magic ... - - /* report the test case is done and wait for the next */ - __afl_end_testcase(); - - } - - return 0; - -} - diff --git a/examples/afl_untracer/Makefile b/examples/afl_untracer/Makefile deleted file mode 100644 index 14a09b41..00000000 --- a/examples/afl_untracer/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -ifdef DEBUG - OPT=-O0 -else - OPT=-O3 -endif - -all: afl-untracer libtestinstr.so - -afl-untracer: afl-untracer.c - $(CC) $(OPT) -I../../include -g -o afl-untracer afl-untracer.c -ldl - -libtestinstr.so: libtestinstr.c - $(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c - -clean: - rm -f afl-untracer libtestinstr.so *~ core diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md deleted file mode 100644 index ada0c916..00000000 --- a/examples/afl_untracer/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# afl-untracer - fast fuzzing of binary-only libraries - -## Introduction - -afl-untracer is an example skeleton file which can easily be used to fuzz -a closed source library. - -It requires less memory and is x3-5 faster than qemu_mode however it is way -more course grained and does not provide interesting features like compcov -or cmplog. - -Supported is so far Intel (i386/x86_64) and AARCH64. - -## How-to - -### Modify afl-untracer.c - -Read and modify afl-untracer.c then `make`. -To adapt afl-untracer.c to your needs, read the header of the file and then -search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations. - -### Generate patches.txt file - -To generate the `patches.txt` file for your target library use the -`ida_get_patchpoints.py` script for IDA Pro or -`ghidra_get_patchpoints.java` for Ghidra. - -The patches.txt file has to be pointed to by `AFL_UNTRACER_FILE`. - -To easily run the scripts without needing to run the GUI with Ghidra: -``` -/opt/ghidra/support/analyzeHeadless /tmp/ tmp$$ -import libtestinstr.so -postscript ./ghidra_get_patchpoints.java -rm -rf /tmp/tmp$$ -``` -The file is created at `~/Desktop/patches.txt` - -### Fuzzing - -Example (after modifying afl-untracer.c to your needs, compiling and creating -patches.txt): -``` -LD_LIBRARY_PATH=/path/to/target/library AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer -``` -(or even remote via afl-network-proxy). - -### Testing and debugging - -For testing/debugging you can try: -``` -make DEBUG=1 -AFL_UNTRACER_FILE=./patches.txt AFL_DEBUG=1 gdb ./afl-untracer -``` -and then you can easily set breakpoints to "breakpoint" and "fuzz". - -# Background - -This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL) -and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz). -This implementation is slower because the traps are not patched out with each -run, but on the other hand gives much better coverage information. diff --git a/examples/afl_untracer/TODO b/examples/afl_untracer/TODO deleted file mode 100644 index fffffacf..00000000 --- a/examples/afl_untracer/TODO +++ /dev/null @@ -1,2 +0,0 @@ - * add shmem fuzzing - * add snapshot feature? diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c deleted file mode 100644 index cb6f948c..00000000 --- a/examples/afl_untracer/afl-untracer.c +++ /dev/null @@ -1,768 +0,0 @@ -/* - american fuzzy lop++ - afl-untracer skeleton example - --------------------------------------------------- - - Written by Marc Heuse - - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - - HOW-TO - ====== - - You only need to change the following: - - 1. decide if you want to receive data from stdin [DEFAULT] or file(name) - -> use_stdin = 0 if via file, and what the maximum input size is - 2. dl load the library you want to fuzz, lookup the functions you need - and setup the calls to these - 3. in the while loop you call the functions in the necessary order - - incl the cleanup. the cleanup is important! - - Just look these steps up in the code, look for "// STEP x:" - - -*/ - -#define __USE_GNU -#define _GNU_SOURCE - -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif -#include "config.h" -#include "types.h" -#include "debug.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if defined(__linux__) - #include -#elif defined(__APPLE__) && defined(__LP64__) - #include -#elif defined(__FreeBSD__) - #include - #include -#else - #error "Unsupported platform" -#endif - -#define MEMORY_MAP_DECREMENT 0x200000000000 -#define MAX_LIB_COUNT 128 - -// STEP 1: - -/* here you need to specify the parameter for the target function */ -static void *(*o_function)(u8 *buf, int len); - -/* use stdin (1) or a file on the commandline (0) */ -static u32 use_stdin = 1; - -/* This is were the testcase data is written into */ -static u8 buf[10000]; // this is the maximum size for a test case! set it! - -/* If you want to have debug output set this to 1, can also be set with - AFL_DEBUG */ -static u32 debug = 0; - -// END STEP 1 - -typedef struct library_list { - - u8 *name; - u64 addr_start, addr_end; - -} library_list_t; - -#ifdef __ANDROID__ -u32 __afl_map_size = MAP_SIZE; -u32 do_exit; -#else -__thread u32 __afl_map_size = MAP_SIZE; -__thread u32 do_exit; -#endif - -static pid_t pid = 65537; -static pthread_t __afl_thread; -static u8 __afl_dummy[MAP_SIZE]; -static u8 * __afl_area_ptr = __afl_dummy; -static u8 * inputfile; // this will point to argv[1] -static u32 len; - -static library_list_t liblist[MAX_LIB_COUNT]; -static u32 liblist_cnt; - -static void sigtrap_handler(int signum, siginfo_t *si, void *context); -static void fuzz(void); - -/* read the library information */ -void read_library_information(void) { - -#if defined(__linux__) - FILE *f; - u8 buf[1024], *b, *m, *e, *n; - - if ((f = fopen("/proc/self/maps", "r")) == NULL) - FATAL("cannot open /proc/self/maps"); - - if (debug) fprintf(stderr, "Library list:\n"); - while (fgets(buf, sizeof(buf), f)) { - - if (strstr(buf, " r-x")) { - - if (liblist_cnt >= MAX_LIB_COUNT) { - - WARNF("too many libraries to old, maximum count of %d reached", - liblist_cnt); - return; - - } - - b = buf; - m = index(buf, '-'); - e = index(buf, ' '); - if ((n = rindex(buf, '/')) == NULL) n = rindex(buf, ' '); - if (n && - ((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '(')) - n = NULL; - else - n++; - if (b && m && e && n && *n) { - - *m++ = 0; - *e = 0; - if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0; - - liblist[liblist_cnt].name = strdup(n); - liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16); - liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16); - if (debug) - fprintf( - stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name, - liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, - liblist[liblist_cnt].addr_start, - liblist[liblist_cnt].addr_end - 1); - liblist_cnt++; - - } - - } - - } - - if (debug) fprintf(stderr, "\n"); - -#elif defined(__FreeBSD__) - int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; - char * buf, *start, *end; - size_t miblen = sizeof(mib) / sizeof(mib[0]); - size_t len; - - if (debug) fprintf(stderr, "Library list:\n"); - if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; } - - len = len * 4 / 3; - - buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); - if (buf == MAP_FAILED) { return; } - - if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) { - - munmap(buf, len); - return; - - } - - start = buf; - end = buf + len; - - while (start < end) { - - struct kinfo_vmentry *region = (struct kinfo_vmentry *)start; - size_t size = region->kve_structsize; - - if (size == 0) { break; } - - if ((region->kve_protection & KVME_PROT_READ) && - !(region->kve_protection & KVME_PROT_EXEC)) { - - liblist[liblist_cnt].name = - region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0; - liblist[liblist_cnt].addr_start = region->kve_start; - liblist[liblist_cnt].addr_end = region->kve_end; - - if (debug) { - - fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name, - liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, - liblist[liblist_cnt].addr_start, - liblist[liblist_cnt].addr_end - 1); - - } - - liblist_cnt++; - - } - - start += size; - - } - -#endif - -} - -library_list_t *find_library(char *name) { - -#if defined(__linux__) - u32 i; - - for (i = 0; i < liblist_cnt; i++) - if (strncmp(liblist[i].name, name, strlen(name)) == 0) return &liblist[i]; -#elif defined(__APPLE__) && defined(__LP64__) - kern_return_t err; - static library_list_t lib; - - // get the list of all loaded modules from dyld - // the task_info mach API will get the address of the dyld all_image_info - // struct for the given task from which we can get the names and load - // addresses of all modules - task_dyld_info_data_t task_dyld_info; - mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; - err = task_info(mach_task_self(), TASK_DYLD_INFO, - (task_info_t)&task_dyld_info, &count); - - const struct dyld_all_image_infos *all_image_infos = - (const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr; - const struct dyld_image_info *image_infos = all_image_infos->infoArray; - - for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) { - - const char * image_name = image_infos[i].imageFilePath; - mach_vm_address_t image_load_address = - (mach_vm_address_t)image_infos[i].imageLoadAddress; - if (strstr(image_name, name)) { - - lib.name = name; - lib.addr_start = (u64)image_load_address; - lib.addr_end = 0; - return &lib; - - } - - } - -#endif - - return NULL; - -} - -/* for having an easy breakpoint location after loading the shared library */ -// this seems to work for clang too. nice :) requires gcc 4.4+ -#pragma GCC push_options -#pragma GCC optimize("O0") -void breakpoint(void) { - - if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n"); - -} - -#pragma GCC pop_options - -/* Error reporting to forkserver controller */ - -void send_forkserver_error(int error) { - - u32 status; - if (!error || error > 0xffff) return; - status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); - if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; - -} - -/* SHM setup. */ - -static void __afl_map_shm(void) { - - char *id_str = getenv(SHM_ENV_VAR); - char *ptr; - - if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { - - u32 val = atoi(ptr); - if (val > 0) __afl_map_size = val; - - } - - if (__afl_map_size > MAP_SIZE) { - - if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { - - fprintf(stderr, - "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " - "be able to run this instrumented program!\n", - __afl_map_size); - if (id_str) { - - send_forkserver_error(FS_ERROR_MAP_SIZE); - exit(-1); - - } - - } else { - - fprintf(stderr, - "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " - "be able to run this instrumented program!\n", - __afl_map_size); - - } - - } - - if (id_str) { - -#ifdef USEMMAP - const char * shm_file_path = id_str; - int shm_fd = -1; - unsigned char *shm_base = NULL; - - /* create the shared memory segment as if it was a file */ - shm_fd = shm_open(shm_file_path, O_RDWR, 0600); - if (shm_fd == -1) { - - fprintf(stderr, "shm_open() failed\n"); - send_forkserver_error(FS_ERROR_SHM_OPEN); - exit(1); - - } - - /* map the shared memory segment to the address space of the process */ - shm_base = - mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - - if (shm_base == MAP_FAILED) { - - close(shm_fd); - shm_fd = -1; - - fprintf(stderr, "mmap() failed\n"); - send_forkserver_error(FS_ERROR_MMAP); - exit(2); - - } - - __afl_area_ptr = shm_base; -#else - u32 shm_id = atoi(id_str); - - __afl_area_ptr = shmat(shm_id, 0, 0); - -#endif - - if (__afl_area_ptr == (void *)-1) { - - send_forkserver_error(FS_ERROR_SHMAT); - exit(1); - - } - - /* Write something into the bitmap so that the parent doesn't give up */ - - __afl_area_ptr[0] = 1; - - } - -} - -/* Fork server logic. */ -inline static void __afl_start_forkserver(void) { - - u8 tmp[4] = {0, 0, 0, 0}; - u32 status = 0; - - if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) - status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); - if (status) status |= (FS_OPT_ENABLED); - memcpy(tmp, &status, 4); - - /* Phone home and tell the parent that we're OK. */ - if (write(FORKSRV_FD + 1, tmp, 4) != 4) do_exit = 1; - // fprintf(stderr, "write0 %d\n", do_exit); - -} - -inline static u32 __afl_next_testcase(u8 *buf, u32 max_len) { - - s32 status; - - /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, &status, 4) != 4) do_exit = 1; - // fprintf(stderr, "read %d\n", do_exit); - - /* we have a testcase - read it if we read from stdin */ - if (use_stdin) { - - if ((status = read(0, buf, max_len)) <= 0) exit(-1); - - } else - - status = 1; - // fprintf(stderr, "stdin: %d %d\n", use_stdin, status); - - /* report that we are starting the target */ - if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1; - // fprintf(stderr, "write1 %d\n", do_exit); - - __afl_area_ptr[0] = 1; // put something in the map - - return status; - -} - -inline static void __afl_end_testcase(int status) { - - if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1; - // fprintf(stderr, "write2 %d\n", do_exit); - if (do_exit) exit(0); - -} - -#ifdef __aarch64__ - #define SHADOW(addr) \ - ((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \ - MEMORY_MAP_DECREMENT - \ - ((uintptr_t)addr & 0x7) * 0x10000000000)) -#else - #define SHADOW(addr) \ - ((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \ - MEMORY_MAP_DECREMENT - \ - ((uintptr_t)addr & 0x3) * 0x10000000000)) -#endif - -void setup_trap_instrumentation(void) { - - library_list_t *lib_base = NULL; - size_t lib_size = 0; - u8 * lib_addr; - char * line = NULL; - size_t nread, len = 0; - char * filename = getenv("AFL_UNTRACER_FILE"); - if (!filename) filename = getenv("TRAPFUZZ_FILE"); - if (!filename) FATAL("AFL_UNTRACER_FILE environment variable not set"); - - FILE *patches = fopen(filename, "r"); - if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename); - - // Index into the coverage bitmap for the current trap instruction. -#ifdef __aarch64__ - uint64_t bitmap_index = 0; -#else - uint32_t bitmap_index = 0; -#endif - - while ((nread = getline(&line, &len, patches)) != -1) { - - char *end = line + len; - - char *col = strchr(line, ':'); - if (col) { - - // It's a library:size pair - *col++ = 0; - - lib_base = find_library(line); - if (!lib_base) FATAL("Library %s does not appear to be loaded", line); - - // we ignore the defined lib_size - lib_size = strtoul(col, NULL, 16); -#if (__linux__) - if (lib_size < lib_base->addr_end - lib_base->addr_start) - lib_size = lib_base->addr_end - lib_base->addr_start; -#endif - if (lib_size % 0x1000 != 0) - WARNF("Invalid library size 0x%zx. Must be multiple of 0x1000", - lib_size); - - lib_addr = (u8 *)lib_base->addr_start; - - // Make library code writable. - if (mprotect((void *)lib_addr, lib_size, - PROT_READ | PROT_WRITE | PROT_EXEC) != 0) - FATAL("Failed to mprotect library %s writable", line); - - // Create shadow memory. -#ifdef __aarch64__ - for (int i = 0; i < 8; i++) { - -#else - for (int i = 0; i < 4; i++) { - -#endif - - void *shadow_addr = SHADOW(lib_addr + i); - void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0); - if (debug) - fprintf(stderr, "Shadow: %s %d = %p-%p for %p\n", line, i, shadow, - shadow + lib_size - 1, lib_addr); - if (shadow == MAP_FAILED) FATAL("Failed to mmap shadow memory"); - - } - - // Done, continue with next line. - continue; - - } - - // It's an offset, parse it and do the patching. - unsigned long offset = strtoul(line, NULL, 16); - - if (offset > lib_size) - FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large", - offset, lib_size); - - if (bitmap_index >= __afl_map_size) - FATAL("Too many basic blocks to instrument"); - -#ifdef __arch64__ - uint64_t -#else - uint32_t -#endif - *shadow = SHADOW(lib_addr + offset); - if (*shadow != 0) continue; // skip duplicates - - // Make lookup entry in shadow memory. - -#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \ - defined(__i386__)) - - // this is for Intel x64 - - uint8_t orig_byte = lib_addr[offset]; - *shadow = (bitmap_index << 8) | orig_byte; - lib_addr[offset] = 0xcc; // replace instruction with debug trap - if (debug) - fprintf(stderr, - "Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %08x\n", - lib_addr, offset, lib_addr + offset, orig_byte, shadow, - bitmap_index, *shadow); - -#elif defined(__aarch64__) - - // this is for aarch64 - - uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset); - uint32_t orig_bytes = *patch_bytes; - *shadow = (bitmap_index << 32) | orig_bytes; - *patch_bytes = 0xd4200000; // replace instruction with debug trap - if (debug) - fprintf(stderr, - "Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %016x\n", - lib_addr, offset, lib_addr + offset, orig_bytes, shadow, - bitmap_index, *shadow); - -#else - // this will be ARM and AARCH64 - // for ARM we will need to identify if the code is in thumb or ARM - #error "non x86_64/aarch64 not supported yet" - //__arm__: - // linux thumb: 0xde01 - // linux arm: 0xe7f001f0 - //__aarch64__: - // linux aarch64: 0xd4200000 -#endif - - bitmap_index++; - - } - - free(line); - fclose(patches); - - // Install signal handler for SIGTRAP. - struct sigaction s; - s.sa_flags = SA_SIGINFO; - s.sa_sigaction = sigtrap_handler; - sigemptyset(&s.sa_mask); - sigaction(SIGTRAP, &s, 0); - - if (debug) fprintf(stderr, "Patched %u locations.\n", bitmap_index); - __afl_map_size = bitmap_index; - if (__afl_map_size % 8) __afl_map_size = (((__afl_map_size + 7) >> 3) << 3); - -} - -/* the signal handler for the traps / debugging interrupts - No debug output here because this would cost speed */ -static void sigtrap_handler(int signum, siginfo_t *si, void *context) { - - uint64_t addr; - // Must re-execute the instruction, so decrement PC by one instruction. - ucontext_t *ctx = (ucontext_t *)context; -#if defined(__APPLE__) && defined(__LP64__) - ctx->uc_mcontext->__ss.__rip -= 1; - addr = ctx->uc_mcontext->__ss.__rip; -#elif defined(__linux__) - #if defined(__x86_64__) || defined(__i386__) - ctx->uc_mcontext.gregs[REG_RIP] -= 1; - addr = ctx->uc_mcontext.gregs[REG_RIP]; - #elif defined(__aarch64__) - ctx->uc_mcontext.pc -= 4; - addr = ctx->uc_mcontext.pc; - #else - #error "Unsupported processor" - #endif -#elif defined(__FreeBSD__) && defined(__LP64__) - ctx->uc_mcontext.mc_rip -= 1; - addr = ctx->uc_mcontext.mc_rip; -#else - #error "Unsupported platform" -#endif - - // fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr, - // si->si_addr); - - // If the trap didn't come from our instrumentation, then we probably will - // just segfault here - uint8_t *faultaddr; - if (unlikely(si->si_addr)) - faultaddr = (u8 *)si->si_addr - 1; - else - faultaddr = (u8 *)addr; - // if (debug) fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr)); - uint32_t shadow = *SHADOW(faultaddr); - uint8_t orig_byte = shadow & 0xff; - uint32_t index = shadow >> 8; - - // if (debug) fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n", - // shadow, orig_byte, index); - - // Index zero is invalid so that it is still possible to catch actual trap - // instructions in instrumented libraries. - if (unlikely(index == 0)) abort(); - - // Restore original instruction - *faultaddr = orig_byte; - - __afl_area_ptr[index] = 128; - -} - -/* the MAIN function */ -int main(int argc, char *argv[]) { - - (void)personality(ADDR_NO_RANDOMIZE); // disable ASLR - - pid = getpid(); - if (getenv("AFL_DEBUG")) debug = 1; - - /* by default we use stdin, but also a filename can be passed, in this - case the input is argv[1] and we have to disable stdin */ - if (argc > 1) { - - use_stdin = 0; - inputfile = argv[1]; - - } - - // STEP 2: load the library you want to fuzz and lookup the functions, - // inclusive of the cleanup functions - // NOTE: above the main() you have to define the functions! - - void *dl = dlopen("./libtestinstr.so", RTLD_LAZY); - if (!dl) FATAL("could not find target library"); - o_function = dlsym(dl, "testinstr"); - if (!o_function) FATAL("could not resolve target function from library"); - if (debug) fprintf(stderr, "Function address: %p\n", o_function); - - // END STEP 2 - - /* setup instrumentation, shared memory and forkserver */ - breakpoint(); - read_library_information(); - setup_trap_instrumentation(); - __afl_map_shm(); - __afl_start_forkserver(); - - while (1) { - - // instead of fork() we could also use the snapshot lkm or do our own mini - // snapshot feature like in https://github.com/marcinguy/fuzzer - // -> snapshot.c - if ((pid = fork()) == -1) PFATAL("fork failed"); - - if (pid) { - - u32 status; - if (waitpid(pid, &status, 0) < 0) exit(1); - /* report the test case is done and wait for the next */ - __afl_end_testcase(status); - - } else { - - pid = getpid(); - while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { - - // in this function the fuzz magic happens, this is STEP 3 - fuzz(); - - // we can use _exit which is faster because our target library - // was loaded via dlopen and therefore cannot have deconstructors - // registered. - _exit(0); - - } - - } - - } - - return 0; - -} - -#ifndef _DEBUG -inline -#endif - static void - fuzz(void) { - - // STEP 3: call the function to fuzz, also the functions you might - // need to call to prepare the function and - important! - - // to clean everything up - - // in this example we use the input file, not stdin! - (*o_function)(buf, len); - - // normally you also need to cleanup - //(*o_LibFree)(foo); - - // END STEP 3 - -} - diff --git a/examples/afl_untracer/ghidra_get_patchpoints.java b/examples/afl_untracer/ghidra_get_patchpoints.java deleted file mode 100644 index d341bea4..00000000 --- a/examples/afl_untracer/ghidra_get_patchpoints.java +++ /dev/null @@ -1,84 +0,0 @@ -/* ### - * IP: GHIDRA - * - * 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 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// Find patch points for untracer tools (e.g. afl++ examples/afl_untracer) -// -// Copy to ..../Ghidra/Features/Search/ghidra_scripts/ -// Writes the results to ~/Desktop/patches.txt -// -// This is my very first Ghidra script. I am sure this could be done better. -// -//@category Search - -import ghidra.app.script.GhidraScript; -import ghidra.program.model.address.*; -import ghidra.program.model.block.*; -import ghidra.program.model.listing.*; -import ghidra.program.model.symbol.*; -import ghidra.program.model.mem.*; - -import java.io.*; - -public class ghidra_get_patchpoints extends GhidraScript { - - @Override - public void run() throws Exception { - - long segment_start = 0; - Memory memory = currentProgram.getMemory(); - MultEntSubModel model = new MultEntSubModel(currentProgram); - CodeBlockIterator subIter = model.getCodeBlocks(monitor); - BufferedWriter out = new BufferedWriter(new FileWriter(System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "patches.txt")); - - while (subIter.hasNext()) { - - CodeBlock multiEntryBlock = subIter.next(); - SimpleBlockModel basicBlockModel = new SimpleBlockModel(currentProgram); - CodeBlockIterator bbIter = basicBlockModel.getCodeBlocksContaining(multiEntryBlock, monitor); - - while (bbIter.hasNext()) { - - CodeBlock basicBlock = bbIter.next(); - - if (segment_start == 0) { - - Address firstAddr = basicBlock.getFirstStartAddress(); - long firstBlockAddr = firstAddr.getAddressableWordOffset(); - MemoryBlock mb = memory.getBlock(firstAddr); - Address startAddr = mb.getStart(); - Address endAddr = mb.getEnd(); - segment_start = startAddr.getAddressableWordOffset(); - if ((firstBlockAddr - segment_start) >= 0x1000) - segment_start += 0x1000; - long segment_end = endAddr.getAddressableWordOffset(); - long segment_size = segment_end - segment_start; - if ((segment_size % 0x1000) > 0) - segment_size = (((segment_size / 0x1000) + 1) * 0x1000); - out.write(currentProgram.getName() + ":0x" + Long.toHexString(segment_size) + "\n"); - //println("Start: " + Long.toHexString(segment_start)); - //println("End: " + Long.toHexString(segment_end)); - - } - - if (basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start > 0) - out.write("0x" + Long.toHexString(basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start) + "\n"); - - } - } - - out.close(); - - } -} diff --git a/examples/afl_untracer/ida_get_patchpoints.py b/examples/afl_untracer/ida_get_patchpoints.py deleted file mode 100644 index 43cf6d89..00000000 --- a/examples/afl_untracer/ida_get_patchpoints.py +++ /dev/null @@ -1,62 +0,0 @@ -# -# IDAPython script for IDA Pro -# Slightly modified from https://github.com/googleprojectzero/p0tools/blob/master/TrapFuzz/findPatchPoints.py -# - -import idautils -import idaapi -import ida_nalt -import idc - -# See https://www.hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml - -from os.path import expanduser -home = expanduser("~") - -patchpoints = set() - -max_offset = 0 -for seg_ea in idautils.Segments(): - name = idc.get_segm_name(seg_ea) - #print("Segment: " + name) - if name != "__text" and name != ".text": - continue - - start = idc.get_segm_start(seg_ea) - end = idc.get_segm_end(seg_ea) - first = 0 - subtract_addr = 0 - #print("Start: " + hex(start) + " End: " + hex(end)) - for func_ea in idautils.Functions(start, end): - f = idaapi.get_func(func_ea) - if not f: - continue - for block in idaapi.FlowChart(f): - if start <= block.start_ea < end: - if first == 0: - if block.start_ea >= 0x1000: - subtract_addr = 0x1000 - first = 1 - - max_offset = max(max_offset, block.start_ea) - patchpoints.add(block.start_ea - subtract_addr) - #else: - # print("Warning: broken CFG?") - -# Round up max_offset to page size -size = max_offset -rem = size % 0x1000 -if rem != 0: - size += 0x1000 - rem - -print("Writing to " + home + "/Desktop/patches.txt") - -with open(home + "/Desktop/patches.txt", "w") as f: - f.write(ida_nalt.get_root_filename() + ':' + hex(size) + '\n') - f.write('\n'.join(map(hex, sorted(patchpoints)))) - f.write('\n') - -print("Done, found {} patchpoints".format(len(patchpoints))) - -# For headless script running remove the comment from the next line -#ida_pro.qexit() diff --git a/examples/afl_untracer/libtestinstr.c b/examples/afl_untracer/libtestinstr.c deleted file mode 100644 index 96b1cf21..00000000 --- a/examples/afl_untracer/libtestinstr.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - american fuzzy lop++ - a trivial program to test the build - -------------------------------------------------------- - Originally written by Michal Zalewski - Copyright 2014 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - http://www.apache.org/licenses/LICENSE-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include - -void testinstr(char *buf, int len) { - - if (len < 1) return; - buf[len] = 0; - - // we support three input cases - if (buf[0] == '0') - printf("Looks like a zero to me!\n"); - else if (buf[0] == '1') - printf("Pretty sure that is a one!\n"); - else - printf("Neither one or zero? How quaint!\n"); - -} - diff --git a/examples/afl_untracer/libtestinstr.so b/examples/afl_untracer/libtestinstr.so deleted file mode 100755 index 389a946c..00000000 Binary files a/examples/afl_untracer/libtestinstr.so and /dev/null differ diff --git a/examples/afl_untracer/patches.txt b/examples/afl_untracer/patches.txt deleted file mode 100644 index 7e964249..00000000 --- a/examples/afl_untracer/patches.txt +++ /dev/null @@ -1,34 +0,0 @@ -libtestinstr.so:0x1000 -0x10 -0x12 -0x20 -0x36 -0x30 -0x40 -0x50 -0x63 -0x6f -0x78 -0x80 -0xa4 -0xb0 -0xb8 -0x100 -0xc0 -0xc9 -0xd7 -0xe3 -0xe8 -0xf8 -0x105 -0x11a -0x135 -0x141 -0x143 -0x14e -0x15a -0x15c -0x168 -0x16a -0x16b -0x170 diff --git a/examples/aflpp_driver/GNUmakefile b/examples/aflpp_driver/GNUmakefile deleted file mode 100644 index c1a087d7..00000000 --- a/examples/aflpp_driver/GNUmakefile +++ /dev/null @@ -1,46 +0,0 @@ -ifeq "" "$(LLVM_CONFIG)" - LLVM_CONFIG=llvm-config -endif - -LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null) -ifneq "" "$(LLVM_BINDIR)" - LLVM_BINDIR := $(LLVM_BINDIR)/ -endif - -CFLAGS := -O3 -funroll-loops -g - -all: libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so - -aflpp_driver.o: aflpp_driver.c - -$(LLVM_BINDIR)clang -I. -I../../include $(CFLAGS) -c aflpp_driver.c - -libAFLDriver.a: aflpp_driver.o - ar ru libAFLDriver.a aflpp_driver.o - cp -vf libAFLDriver.a ../../ - -debug: - $(LLVM_BINDIR)clang -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c - $(LLVM_BINDIR)clang -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c - #$(LLVM_BINDIR)clang -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c - #$(LLVM_BINDIR)clang -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c - ar ru libAFLDriver.a afl-performance.o aflpp_driver.o - -aflpp_qemu_driver.o: aflpp_qemu_driver.c - $(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c - -libAFLQemuDriver.a: aflpp_qemu_driver.o - ar ru libAFLQemuDriver.a aflpp_qemu_driver.o - cp -vf libAFLQemuDriver.a ../../ - -aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o - $(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so - -aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c - $(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c - -test: debug - #clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c - afl-clang-fast -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test aflpp_driver_test.c libAFLDriver.a afl-performance.o - -clean: - rm -f *.o libAFLDriver*.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so *~ core aflpp_driver_test diff --git a/examples/aflpp_driver/Makefile b/examples/aflpp_driver/Makefile deleted file mode 100644 index 3666a74d..00000000 --- a/examples/aflpp_driver/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - @gmake all || echo please install GNUmake diff --git a/examples/aflpp_driver/aflpp_driver.c b/examples/aflpp_driver/aflpp_driver.c deleted file mode 100644 index 017aa72b..00000000 --- a/examples/aflpp_driver/aflpp_driver.c +++ /dev/null @@ -1,326 +0,0 @@ -//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -//===----------------------------------------------------------------------===// - -/* This file allows to fuzz libFuzzer-style target functions - (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode. - -Usage: -################################################################################ -cat << EOF > test_fuzzer.cc -#include -#include -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - - if (size > 0 && data[0] == 'H') - if (size > 1 && data[1] == 'I') - if (size > 2 && data[2] == '!') - __builtin_trap(); - return 0; - -} - -EOF -# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang. -clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c -# Build afl-llvm-rt.o.c from the AFL distribution. -clang -c -w $AFL_HOME/instrumentation/afl-llvm-rt.o.c -# Build this file, link it with afl-llvm-rt.o.o and the target code. -clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o -# Run AFL: -rm -rf IN OUT; mkdir IN OUT; echo z > IN/z; -$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out -################################################################################ -AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file -specified. If the file does not exist, it is created. This is useful for getting -stack traces (when using ASAN for example) or original error messages on hard -to reproduce bugs. Note that any content written to stderr will be written to -this file instead of stderr's usual location. - -AFL_DRIVER_CLOSE_FD_MASK: Similar to libFuzzer's -close_fd_mask behavior option. -If 1, close stdout at startup. If 2 close stderr; if 3 close both. - -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "cmplog.h" - -#ifdef _DEBUG - #include "hash.h" -#endif - -#ifndef MAP_FIXED_NOREPLACE - #define MAP_FIXED_NOREPLACE 0x100000 -#endif - -#define MAX_DUMMY_SIZE 256000 - -// Platform detection. Copied from FuzzerInternal.h -#ifdef __linux__ - #define LIBFUZZER_LINUX 1 - #define LIBFUZZER_APPLE 0 - #define LIBFUZZER_NETBSD 0 - #define LIBFUZZER_FREEBSD 0 - #define LIBFUZZER_OPENBSD 0 -#elif __APPLE__ - #define LIBFUZZER_LINUX 0 - #define LIBFUZZER_APPLE 1 - #define LIBFUZZER_NETBSD 0 - #define LIBFUZZER_FREEBSD 0 - #define LIBFUZZER_OPENBSD 0 -#elif __NetBSD__ - #define LIBFUZZER_LINUX 0 - #define LIBFUZZER_APPLE 0 - #define LIBFUZZER_NETBSD 1 - #define LIBFUZZER_FREEBSD 0 - #define LIBFUZZER_OPENBSD 0 -#elif __FreeBSD__ - #define LIBFUZZER_LINUX 0 - #define LIBFUZZER_APPLE 0 - #define LIBFUZZER_NETBSD 0 - #define LIBFUZZER_FREEBSD 1 - #define LIBFUZZER_OPENBSD 0 -#elif __OpenBSD__ - #define LIBFUZZER_LINUX 0 - #define LIBFUZZER_APPLE 0 - #define LIBFUZZER_NETBSD 0 - #define LIBFUZZER_FREEBSD 0 - #define LIBFUZZER_OPENBSD 1 -#else - #error "Support for your platform has not been implemented" -#endif - -int __afl_sharedmem_fuzzing = 1; -extern unsigned int * __afl_fuzz_len; -extern unsigned char *__afl_fuzz_ptr; - -// libFuzzer interface is thin, so we don't include any libFuzzer headers. -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); -__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); - -// Notify AFL about persistent mode. -static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; -int __afl_persistent_loop(unsigned int); - -// Notify AFL about deferred forkserver. -static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; -void __afl_manual_init(); - -// Use this optionally defined function to output sanitizer messages even if -// user asks to close stderr. -__attribute__((weak)) void __sanitizer_set_report_fd(void *); - -// Keep track of where stderr content is being written to, so that -// dup_and_close_stderr can use the correct one. -static FILE *output_file; - -// Experimental feature to use afl_driver without AFL's deferred mode. -// Needs to run before __afl_auto_init. -__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) { - - if (getenv("AFL_DRIVER_DONT_DEFER")) { - - if (unsetenv("__AFL_DEFER_FORKSRV")) { - - perror("Failed to unset __AFL_DEFER_FORKSRV"); - abort(); - - } - - } - -} - -// If the user asks us to duplicate stderr, then do it. -static void maybe_duplicate_stderr() { - - char *stderr_duplicate_filename = - getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); - - if (!stderr_duplicate_filename) return; - - FILE *stderr_duplicate_stream = - freopen(stderr_duplicate_filename, "a+", stderr); - - if (!stderr_duplicate_stream) { - - fprintf( - stderr, - "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); - abort(); - - } - - output_file = stderr_duplicate_stream; - -} - -// Most of these I/O functions were inspired by/copied from libFuzzer's code. -static void discard_output(int fd) { - - FILE *temp = fopen("/dev/null", "w"); - if (!temp) abort(); - dup2(fileno(temp), fd); - fclose(temp); - -} - -static void close_stdout() { - - discard_output(STDOUT_FILENO); - -} - -// Prevent the targeted code from writing to "stderr" but allow sanitizers and -// this driver to do so. -static void dup_and_close_stderr() { - - int output_fileno = fileno(output_file); - int output_fd = dup(output_fileno); - if (output_fd <= 0) abort(); - FILE *new_output_file = fdopen(output_fd, "w"); - if (!new_output_file) abort(); - if (!__sanitizer_set_report_fd) return; - __sanitizer_set_report_fd((void *)(long int)output_fd); - discard_output(output_fileno); - -} - -// Close stdout and/or stderr if user asks for it. -static void maybe_close_fd_mask() { - - char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK"); - if (!fd_mask_str) return; - int fd_mask = atoi(fd_mask_str); - if (fd_mask & 2) dup_and_close_stderr(); - if (fd_mask & 1) close_stdout(); - -} - -// Define LLVMFuzzerMutate to avoid link failures for targets that use it -// with libFuzzer's LLVMFuzzerCustomMutator. -size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { - - // assert(false && "LLVMFuzzerMutate should not be called from afl_driver"); - return 0; - -} - -// Execute any files provided as parameters. -static int ExecuteFilesOnyByOne(int argc, char **argv) { - - unsigned char *buf = malloc(MAX_FILE); - for (int i = 1; i < argc; i++) { - - int fd = open(argv[i], O_RDONLY); - if (fd == -1) continue; - ssize_t length = read(fd, buf, MAX_FILE); - if (length > 0) { - - printf("Reading %zu bytes from %s\n", length, argv[i]); - LLVMFuzzerTestOneInput(buf, length); - printf("Execution successful.\n"); - - } - - } - - free(buf); - return 0; - -} - -int main(int argc, char **argv) { - - printf( - "======================= INFO =========================\n" - "This binary is built for afl++.\n" - "To run the target function on individual input(s) execute this:\n" - " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" - "To fuzz with afl-fuzz execute this:\n" - " afl-fuzz [afl-flags] -- %s [-N]\n" - "afl-fuzz will run N iterations before re-spawning the process (default: " - "1000)\n" - "======================================================\n", - argv[0], argv[0]); - - output_file = stderr; - maybe_duplicate_stderr(); - maybe_close_fd_mask(); - if (LLVMFuzzerInitialize) { - - fprintf(stderr, "Running LLVMFuzzerInitialize ...\n"); - LLVMFuzzerInitialize(&argc, &argv); - fprintf(stderr, "continue...\n"); - - } - - // Do any other expensive one-time initialization here. - - uint8_t dummy_input[64] = {0}; - memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT)); - memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR, - sizeof(AFL_DEFER_FORKSVR)); - int N = INT_MAX; - if (argc == 2 && argv[1][0] == '-') - N = atoi(argv[1] + 1); - else if (argc == 2 && (N = atoi(argv[1])) > 0) - printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N); - else if (argc > 1) { - - __afl_sharedmem_fuzzing = 0; - __afl_manual_init(); - return ExecuteFilesOnyByOne(argc, argv); - - } - - assert(N > 0); - - // if (!getenv("AFL_DRIVER_DONT_DEFER")) - __afl_manual_init(); - - // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization - // on the first execution of LLVMFuzzerTestOneInput is ignored. - LLVMFuzzerTestOneInput(dummy_input, 1); - - int num_runs = 0; - while (__afl_persistent_loop(N)) { - -#ifdef _DEBUG - fprintf(stderr, "CLIENT crc: %016llx len: %u\n", - hash64(__afl_fuzz_ptr, *__afl_fuzz_len, 0xa5b35705), - *__afl_fuzz_len); - fprintf(stderr, "RECV:"); - for (int i = 0; i < *__afl_fuzz_len; i++) - fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); - fprintf(stderr, "\n"); -#endif - if (*__afl_fuzz_len) { - - num_runs++; - LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len); - - } - - } - - printf("%s: successfully executed %d input(s)\n", argv[0], num_runs); - -} - diff --git a/examples/aflpp_driver/aflpp_driver_test.c b/examples/aflpp_driver/aflpp_driver_test.c deleted file mode 100644 index b4ff6bc6..00000000 --- a/examples/aflpp_driver/aflpp_driver_test.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include -#include - -#include "hash.h" - -void __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) { - - if (Size < 5) return; - - if (Data[0] == 'F') - if (Data[1] == 'A') - if (Data[2] == '$') - if (Data[3] == '$') - if (Data[4] == '$') abort(); - -} - -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - - if (Size) - fprintf(stderr, "FUNC crc: %016llx len: %lu\n", - hash64((u8 *)Data, (unsigned int)Size, - (unsigned long long int)0xa5b35705), - Size); - - crashme(Data, Size); - - return 0; - -} - diff --git a/examples/aflpp_driver/aflpp_qemu_driver.c b/examples/aflpp_driver/aflpp_qemu_driver.c deleted file mode 100644 index 4f3e5f71..00000000 --- a/examples/aflpp_driver/aflpp_qemu_driver.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include - -// libFuzzer interface is thin, so we don't include any libFuzzer headers. -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); -__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); - -static const size_t kMaxAflInputSize = 1 * 1024 * 1024; -static uint8_t AflInputBuf[kMaxAflInputSize]; - -void __attribute__((noinline)) afl_qemu_driver_stdin_input(void) { - - size_t l = read(0, AflInputBuf, kMaxAflInputSize); - LLVMFuzzerTestOneInput(AflInputBuf, l); - -} - -int main(int argc, char **argv) { - - if (LLVMFuzzerInitialize) LLVMFuzzerInitialize(&argc, &argv); - // Do any other expensive one-time initialization here. - - if (getenv("AFL_QEMU_DRIVER_NO_HOOK")) { - - afl_qemu_driver_stdin_input(); - - } else { - - uint8_t dummy_input[1024000] = {0}; - LLVMFuzzerTestOneInput(dummy_input, 1); - - } - - return 0; - -} - diff --git a/examples/aflpp_driver/aflpp_qemu_driver_hook.c b/examples/aflpp_driver/aflpp_qemu_driver_hook.c deleted file mode 100644 index 823cc42d..00000000 --- a/examples/aflpp_driver/aflpp_qemu_driver_hook.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -#define g2h(x) ((void *)((unsigned long)(x) + guest_base)) - -#define REGS_RDI 7 -#define REGS_RSI 6 - -void afl_persistent_hook(uint64_t *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_len) { - - memcpy(g2h(regs[REGS_RDI]), input_buf, input_len); - regs[REGS_RSI] = input_len; - -} - -int afl_persistent_hook_init(void) { - - return 1; - -} - diff --git a/examples/analysis_scripts/queue2csv.sh b/examples/analysis_scripts/queue2csv.sh deleted file mode 100755 index 2528b438..00000000 --- a/examples/analysis_scripts/queue2csv.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash - -test -z "$1" -o -z "$2" -o "$1" = "-h" -o "$1" = "-hh" -o "$1" = "--help" -o '!' -d "$1" && { - echo "Syntax: [-n] $0 out-directory file.csv [\"tools/target --opt @@\"]" - echo Option -n will suppress the CSV header. - echo If the target execution command is supplied then also edge coverage is gathered. - exit 1 -} - -function getval() { - VAL="" - if [ "$file" != "${file/$1/}" ]; then - TMP="${file/*$1:/}" - VAL="${TMP/,*/}" - fi -} - -SKIP= -if [ "$1" = "-n" ]; then - SKIP=1 - shift -fi - -test -n "$4" && { echo "Error: too many commandline options. Target command and options including @@ have to be passed within \"\"!"; exit 1; } - -test -d "$1"/queue && OUT="$1/queue" || OUT="$1" - -OK=`ls $OUT/id:000000,time:0,orig:* 2> /dev/null` -if [ -n "$OK" ]; then - LISTCMD="ls $OUT/id:"* -else - LISTCMD="ls -tr $OUT/" -fi - -ID=;SRC=;TIME=;OP=;POS=;REP=;EDGES=;EDGES_TOTAL=; -DIR="$OUT/../stats" -rm -rf "$DIR" -> "$2" || exit 1 -mkdir "$DIR" || exit 1 -> "$DIR/../edges.txt" || exit 1 - -{ - - if [ -z "$SKIP" ]; then - echo "time;\"filename\";id;src;new_cov;edges;total_edges;\"op\";pos;rep;unique_edges" - fi - - $LISTCMD | grep -v ,sync: | sed 's/.*id:/id:/g' | while read file; do - - if [ -n "$3" ]; then - - TMP=${3/@@/$OUT/$file} - - if [ "$TMP" = "$3" ]; then - - cat "$OUT/$file" | afl-showmap -o "$DIR/$file" -q -- $3 >/dev/null 2>&1 - - else - - afl-showmap -o "$DIR/$file" -q -- $TMP >/dev/null 2>&1 - - fi - - { cat "$DIR/$file" | sed 's/:.*//' ; cat "$DIR/../edges.txt" ; } | sort -nu > $DIR/../edges.txt.tmp - mv $DIR/../edges.txt.tmp $DIR/../edges.txt - EDGES=$(cat "$DIR/$file" | wc -l) - EDGES_TOTAL=$(cat "$DIR/../edges.txt" | wc -l) - - fi - - getval id; ID="$VAL" - getval src; SRC="$VAL" - getval time; TIME="$VAL" - getval op; OP="$VAL" - getval pos; POS="$VAL" - getval rep; REP="$VAL" - if [ "$file" != "${file/+cov/}" ]; then - COV=1 - else - COV="" - fi - - if [ -n "$3" -a -s "$DIR/../edges.txt" ]; then - echo "$TIME;\"$file\";$ID;$SRC;$COV;$EDGES;$EDGES_TOTAL;\"$OP\";$POS;$REP;UNIQUE$file" - else - echo "$TIME;\"$file\";$ID;$SRC;$COV;;;\"$OP\";$POS;$REP;" - fi - - done - -} | tee "$DIR/../queue.csv" > "$2" || exit 1 - -if [ -n "$3" -a -s "$DIR/../edges.txt" ]; then - - cat "$DIR/"* | sed 's/:.*//' | sort -n | uniq -c | egrep '^[ \t]*1 ' | awk '{print$2}' > $DIR/../unique.txt - - if [ -s "$DIR/../unique.txt" ]; then - - ls "$DIR/id:"* | grep -v ",sync:" |sed 's/.*\/id:/id:/g' | while read file; do - - CNT=$(sed 's/:.*//' "$DIR/$file" | tee "$DIR/../tmp.txt" | wc -l) - DIFF=$(diff -u "$DIR/../tmp.txt" "$DIR/../unique.txt" | egrep '^-[0-9]' | wc -l) - UNIQUE=$(($CNT - $DIFF)) - sed -i "s/;UNIQUE$file/;$UNIQUE/" "$DIR/../queue.csv" "$2" - - done - - rm -f "$DIR/../tmp.txt" - - else - - sed -i 's/;UNIQUE.*/;/' "$DIR/../queue.csv" "$2" - - fi - -fi - -mv "$DIR/../queue.csv" "$DIR/queue.csv" -if [ -e "$DIR/../edges.txt" ]; then mv "$DIR/../edges.txt" "$DIR/edges.txt"; fi -if [ -e "$DIR/../unique.txt" ]; then mv "$DIR/../unique.txt" "$DIR/unique.txt"; fi - -echo "Created $2" diff --git a/examples/argv_fuzzing/Makefile b/examples/argv_fuzzing/Makefile deleted file mode 100644 index 5a0ac6e6..00000000 --- a/examples/argv_fuzzing/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -# -# american fuzzy lop++ - argvfuzz -# -------------------------------- -# -# Copyright 2019-2020 Kjell Braden -# -# 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 -# - -.PHONY: all install clean - -PREFIX ?= /usr/local -BIN_PATH = $(PREFIX)/bin -HELPER_PATH = $(PREFIX)/lib/afl - -CFLAGS = -fPIC -Wall -Wextra -LDFLAGS = -shared - -UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?) -UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$? - -_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=) -LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl) -LDFLAGS += $(LDFLAGS_ADD) - -# on gcc for arm there is no -m32, but -mbe32 -M32FLAG = -m32 -M64FLAG = -m64 - -CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?) -CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$? -CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?) -CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$? - -_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER) -__M32FLAG=$(_M32FLAG:00=-mbe32) -___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32) -M32FLAG=$(___M32FLAG) - -all: argvfuzz32.so argvfuzz64.so - -argvfuzz32.so: argvfuzz.c - -@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz32 build failure (that's fine)" - -argvfuzz64.so: argvfuzz.c - -@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz64 build failure (that's fine)" - -install: argvfuzz32.so argvfuzz64.so - install -d -m 755 $(DESTDIR)$(HELPER_PATH)/ - if [ -f argvfuzz32.so ]; then set -e; install -m 755 argvfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi - if [ -f argvfuzz64.so ]; then set -e; install -m 755 argvfuzz64.so $(DESTDIR)$(HELPER_PATH)/; fi - -clean: - rm -f argvfuzz32.so argvfuzz64.so diff --git a/examples/argv_fuzzing/README.md b/examples/argv_fuzzing/README.md deleted file mode 100644 index fa8cad80..00000000 --- a/examples/argv_fuzzing/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# argvfuzz - -afl supports fuzzing file inputs or stdin. When source is available, -`argv-fuzz-inl.h` can be used to change `main()` to build argv from stdin. - -`argvfuzz` tries to provide the same functionality for binaries. When loaded -using `LD_PRELOAD`, it will hook the call to `__libc_start_main` and replace -argv using the same logic of `argv-fuzz-inl.h`. - -A few conditions need to be fulfilled for this mechanism to work correctly: - -1. As it relies on hooking the loader, it cannot work on static binaries. -2. If the target binary does not use the default libc's `_start` implementation - (crt1.o), the hook may not run. -3. The hook will replace argv with pointers to `.data` of `argvfuzz.so`. If the - target binary expects argv to be living on the stack, things may go wrong. diff --git a/examples/argv_fuzzing/argv-fuzz-inl.h b/examples/argv_fuzzing/argv-fuzz-inl.h deleted file mode 100644 index c15c0271..00000000 --- a/examples/argv_fuzzing/argv-fuzz-inl.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - american fuzzy lop++ - sample argv fuzzing wrapper - ------------------------------------------------ - - Originally written by Michal Zalewski - - Copyright 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 - - This file shows a simple way to fuzz command-line parameters with stock - afl-fuzz. To use, add: - - #include "/path/to/argv-fuzz-inl.h" - - ...to the file containing main(), ideally placing it after all the - standard includes. Next, put AFL_INIT_ARGV(); near the very beginning of - main(). - - This will cause the program to read NUL-delimited input from stdin and - put it in argv[]. Two subsequent NULs terminate the array. Empty - params are encoded as a lone 0x02. Lone 0x02 can't be generated, but - that shouldn't matter in real life. - - If you would like to always preserve argv[0], use this instead: - AFL_INIT_SET0("prog_name"); - -*/ - -#ifndef _HAVE_ARGV_FUZZ_INL -#define _HAVE_ARGV_FUZZ_INL - -#include - -#define AFL_INIT_ARGV() \ - do { \ - \ - argv = afl_init_argv(&argc); \ - \ - } while (0) - -#define AFL_INIT_SET0(_p) \ - do { \ - \ - argv = afl_init_argv(&argc); \ - argv[0] = (_p); \ - if (!argc) argc = 1; \ - \ - } while (0) - -#define MAX_CMDLINE_LEN 100000 -#define MAX_CMDLINE_PAR 50000 - -static char **afl_init_argv(int *argc) { - - static char in_buf[MAX_CMDLINE_LEN]; - static char *ret[MAX_CMDLINE_PAR]; - - char *ptr = in_buf; - int rc = 0; - - if (read(0, in_buf, MAX_CMDLINE_LEN - 2) < 0) {} - - while (*ptr && rc < MAX_CMDLINE_PAR) { - - ret[rc] = ptr; - if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++; - rc++; - - while (*ptr) - ptr++; - ptr++; - - } - - *argc = rc; - - return ret; - -} - -#undef MAX_CMDLINE_LEN -#undef MAX_CMDLINE_PAR - -#endif /* !_HAVE_ARGV_FUZZ_INL */ - diff --git a/examples/argv_fuzzing/argvfuzz.c b/examples/argv_fuzzing/argvfuzz.c deleted file mode 100644 index 4251ca4c..00000000 --- a/examples/argv_fuzzing/argvfuzz.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - american fuzzy lop++ - LD_PRELOAD for fuzzing argv in binaries - ------------------------------------------------------------ - - Copyright 2019-2020 Kjell Braden - - 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 - - */ - -#define _GNU_SOURCE /* for RTLD_NEXT */ -#include -#include -#include -#include -#include "argv-fuzz-inl.h" - -int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv, - void (*init)(void), void (*fini)(void), - void (*rtld_fini)(void), void *stack_end) { - - int (*orig)(int (*main)(int, char **, char **), int argc, char **argv, - void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), - void *stack_end); - int sub_argc; - char **sub_argv; - - (void)argc; - (void)argv; - - orig = dlsym(RTLD_NEXT, __func__); - - if (!orig) { - - fprintf(stderr, "hook did not find original %s: %s\n", __func__, dlerror()); - exit(EXIT_FAILURE); - - } - - sub_argv = afl_init_argv(&sub_argc); - - return orig(main, sub_argc, sub_argv, init, fini, rtld_fini, stack_end); - -} - diff --git a/examples/asan_cgroups/limit_memory.sh b/examples/asan_cgroups/limit_memory.sh deleted file mode 100755 index 1f0f04ad..00000000 --- a/examples/asan_cgroups/limit_memory.sh +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env bash -# -# american fuzzy lop++ - limit memory using cgroups -# ----------------------------------------------- -# -# Written by Samir Khakimov and -# David A. Wheeler -# -# Edits to bring the script in line with afl-cmin and other companion scripts -# by Michal Zalewski. All bugs are my fault. -# -# Copyright 2015 Institute for Defense Analyses. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# This tool allows the amount of actual memory allocated to a program -# to be limited on Linux systems using cgroups, instead of the traditional -# setrlimit() API. This helps avoid the address space problems discussed in -# docs/notes_for_asan.md. -# -# Important: the limit covers *both* afl-fuzz and the fuzzed binary. In some -# hopefully rare circumstances, afl-fuzz could be killed before the fuzzed -# task. -# - -echo "cgroup tool for afl-fuzz by and " -echo - -unset NEW_USER -MEM_LIMIT="50" - -while getopts "+u:m:" opt; do - - case "$opt" in - - "u") - NEW_USER="$OPTARG" - ;; - - "m") - MEM_LIMIT="$[OPTARG]" - ;; - - "?") - exit 1 - ;; - - esac - -done - -if [ "$MEM_LIMIT" -lt "5" ]; then - echo "[-] Error: malformed or dangerously low value of -m." 1>&2 - exit 1 -fi - -shift $((OPTIND-1)) - -TARGET_BIN="$1" - -if [ "$TARGET_BIN" = "" -o "$NEW_USER" = "" ]; then - - cat 1>&2 <<_EOF_ -Usage: $0 [ options ] -- /path/to/afl-fuzz [ ...afl options... ] - -Required parameters: - - -u user - run the fuzzer as a specific user after setting up limits - -Optional parameters: - - -m megs - set memory limit to a specified value ($MEM_LIMIT MB) - -This tool configures cgroups-based memory limits for a fuzzing job to simplify -the task of fuzzing ASAN or MSAN binaries. You would normally want to use it in -conjunction with '-m none' passed to the afl-fuzz binary itself, say: - - $0 -u joe ./afl-fuzz -i input -o output -m none /path/to/target - -_EOF_ - - exit 1 - -fi - -# Basic sanity checks - -if [ ! "`uname -s`" = "Linux" ]; then - echo "[-] Error: this tool does not support non-Linux systems." 1>&2 - exit 1 -fi - -if [ ! "`id -u`" = "0" ]; then - echo "[-] Error: you need to run this script as root (sorry!)." 1>&2 - exit 1 -fi - -if ! type cgcreate 2>/dev/null 1>&2; then - - echo "[-] Error: you need to install cgroup tools first." 1>&2 - - if type apt-get 2>/dev/null 1>&2; then - echo " (Perhaps 'apt-get install cgroup-bin' will work.)" 1>&2 - elif type yum 2>/dev/null 1>&2; then - echo " (Perhaps 'yum install libcgroup-tools' will work.)" 1>&2 - fi - - exit 1 - -fi - -if ! id -u "$NEW_USER" 2>/dev/null 1>&2; then - echo "[-] Error: user '$NEW_USER' does not seem to exist." 1>&2 - exit 1 -fi - -# Create a new cgroup path if necessary... We used PID-keyed groups to keep -# parallel afl-fuzz tasks separate from each other. - -CID="afl-$NEW_USER-$$" - -CPATH="/sys/fs/cgroup/memory/$CID" - -if [ ! -d "$CPATH" ]; then - - cgcreate -a "$NEW_USER" -g memory:"$CID" || exit 1 - -fi - -# Set the appropriate limit... - -if [ -f "$CPATH/memory.memsw.limit_in_bytes" ]; then - - echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" 2>/dev/null - echo "${MEM_LIMIT}M" > "$CPATH/memory.memsw.limit_in_bytes" || exit 1 - echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1 - -elif grep -qE 'partition|file' /proc/swaps; then - - echo "[-] Error: your system requires swap to be disabled first (swapoff -a)." 1>&2 - exit 1 - -else - - echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1 - -fi - -# All right. At this point, we can just run the command. - -cgexec -g "memory:$CID" su -c "$*" "$NEW_USER" - -cgdelete -g "memory:$CID" diff --git a/examples/bash_shellshock/shellshock-fuzz.diff b/examples/bash_shellshock/shellshock-fuzz.diff deleted file mode 100644 index 3fa05bf8..00000000 --- a/examples/bash_shellshock/shellshock-fuzz.diff +++ /dev/null @@ -1,59 +0,0 @@ -This patch shows a very simple way to find post-Shellshock bugs in bash, as -discussed here: - - http://lcamtuf.blogspot.com/2014/10/bash-bug-how-we-finally-cracked.html - -In essence, it shows a way to fuzz environmental variables. Instructions: - -1) Download bash 4.3, apply this patch, compile with: - - CC=/path/to/afl-gcc ./configure - make clean all - - Note that the harness puts the fuzzed output in $TEST_VARIABLE. With - Florian's Shellshock patch (bash43-028), this is no longer passed down - to the parser. - -2) Create and cd to an empty directory, put the compiled bash binary in - there, and run these commands: - - mkdir in_dir - echo -n '() { a() { a; }; : >b; }' >in_dir/script.txt - -3) Run the fuzzer with: - - /path/to/afl-fuzz -d -i in_dir -o out_dir ./bash -c : - - The -d parameter is advisable only if the tested shell is fairly slow - or if you are in a hurry; will cover more ground faster, but - less systematically. - -4) Watch for crashes in out_dir/crashes/. Also watch for any new files - created in cwd if you're interested in non-crash RCEs (files will be - created whenever the shell executes "foo>bar" or something like - that). You can correlate their creation date with new entries in - out_dir/queue/. - - You can also modify the bash binary to directly check for more subtle - fault conditions, or use the synthesized entries in out_dir/queue/ - as a seed for other, possibly slower or more involved testing regimes. - - Expect several hours to get decent coverage. - ---- bash-4.3/shell.c.orig 2014-01-14 14:04:32.000000000 +0100 -+++ bash-4.3/shell.c 2015-04-30 05:56:46.000000000 +0200 -@@ -371,6 +371,14 @@ - env = environ; - #endif /* __OPENNT */ - -+ { -+ -+ static char val[1024 * 16]; -+ read(0, val, sizeof(val) - 1); -+ setenv("TEST_VARIABLE", val, 1); -+ -+ } -+ - USE_VAR(argc); - USE_VAR(argv); - USE_VAR(env); diff --git a/examples/canvas_harness/canvas_harness.html b/examples/canvas_harness/canvas_harness.html deleted file mode 100644 index a37b6937..00000000 --- a/examples/canvas_harness/canvas_harness.html +++ /dev/null @@ -1,170 +0,0 @@ - - - - - -
- -
- - - -

Results

- -
    - - - - diff --git a/examples/clang_asm_normalize/as b/examples/clang_asm_normalize/as deleted file mode 100755 index 45537cae..00000000 --- a/examples/clang_asm_normalize/as +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/sh -# -# american fuzzy lop++ - clang assembly normalizer -# ---------------------------------------------- -# -# Originally written by Michal Zalewski -# The idea for this wrapper comes from Ryan Govostes. -# -# Copyright 2013, 2014 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 -# -# This 'as' wrapper should allow you to instrument unruly, hand-written -# assembly with afl-as. -# -# Usage: -# -# export AFL_REAL_PATH=/path/to/directory/with/afl-as/ -# AFL_PATH=/path/to/this/directory/ make clean all - -if [ "$#" -lt "2" ]; then - echo "[-] Error: this utility can't be called directly." 1>&2 - exit 1 -fi - -if [ "$AFL_REAL_PATH" = "" ]; then - echo "[-] Error: AFL_REAL_PATH not set!" 1>&2 - exit 1 -fi - -if [ ! -x "$AFL_REAL_PATH/afl-as" ]; then - echo "[-] Error: AFL_REAL_PATH does not contain the 'afl-as' binary." 1>&2 - exit 1 -fi - -unset __AFL_AS_CMDLINE __AFL_FNAME - -while [ ! "$#" = "0" ]; do - - if [ "$#" = "1" ]; then - __AFL_FNAME="$1" - else - __AFL_AS_CMDLINE="${__AFL_AS_CMDLINE} $1" - fi - - shift - -done - -test "$TMPDIR" = "" && TMPDIR=/tmp - -TMPFILE=`mktemp $TMPDIR/.afl-XXXXXXXXXX.s` - -test "$TMPFILE" = "" && exit 1 - -clang -cc1as -filetype asm -output-asm-variant 0 "${__AFL_FNAME}" >"$TMPFILE" - -ERR="$?" - -if [ ! "$ERR" = "0" ]; then - rm -f "$TMPFILE" - exit $ERR -fi - -"$AFL_REAL_PATH/afl-as" ${__AFL_AS_CMDLINE} "$TMPFILE" - -ERR="$?" - -rm -f "$TMPFILE" - -exit "$ERR" diff --git a/examples/crash_triage/triage_crashes.sh b/examples/crash_triage/triage_crashes.sh deleted file mode 100755 index bf763cba..00000000 --- a/examples/crash_triage/triage_crashes.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/bin/sh -# -# american fuzzy lop++ - crash triage utility -# ----------------------------------------- -# -# Originally written by Michal Zalewski -# -# Copyright 2013, 2014, 2017 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 -# -# Note that this assumes that the targeted application reads from stdin -# and requires no other cmdline parameters. Modify as needed if this is -# not the case. -# -# Note that on OpenBSD, you may need to install a newer version of gdb -# (e.g., from ports). You can set GDB=/some/path to point to it if -# necessary. -# - -echo "crash triage utility for afl-fuzz by Michal Zalewski" -echo - -ulimit -v 100000 2>/dev/null -ulimit -d 100000 2>/dev/null - -if [ "$#" -lt "2" ]; then - echo "Usage: $0 /path/to/afl_output_dir /path/to/tested_binary [...target params...]" 1>&2 - echo 1>&2 - exit 1 -fi - -DIR="$1" -BIN="$2" -shift -shift - -if [ "$AFL_ALLOW_TMP" = "" ]; then - - echo "$DIR" | grep -qE '^(/var)?/tmp/' - T1="$?" - - echo "$BIN" | grep -qE '^(/var)?/tmp/' - T2="$?" - - if [ "$T1" = "0" -o "$T2" = "0" ]; then - echo "[-] Error: do not use shared /tmp or /var/tmp directories with this script." 1>&2 - exit 1 - fi - -fi - -if - [ "$GDB" = "" ]; then - GDB=gdb -fi - -if [ ! -f "$BIN" -o ! -x "$BIN" ]; then - echo "[-] Error: binary '$2' not found or is not executable." 1>&2 - exit 1 -fi - -if [ ! -d "$DIR/queue" ]; then - echo "[-] Error: directory '$1' not found or not created by afl-fuzz." 1>&2 - exit 1 -fi - -CCOUNT=$((`ls -- "$DIR/crashes" 2>/dev/null | wc -l`)) - -if [ "$CCOUNT" = "0" ]; then - echo "No crashes recorded in the target directory - nothing to be done." - exit 0 -fi - -echo - -for crash in $DIR/crashes/id:*; do - - id=`basename -- "$crash" | cut -d, -f1 | cut -d: -f2` - sig=`basename -- "$crash" | cut -d, -f2 | cut -d: -f2` - - # Grab the args, converting @@ to $crash - - use_args="" - use_stdio=1 - - for a in $@; do - - if [ "$a" = "@@" ] ; then - use_args="$use_args $crash" - unset use_stdio - else - use_args="$use_args $a" - fi - - done - - # Strip the trailing space - use_args="${use_args# }" - - echo "+++ ID $id, SIGNAL $sig +++" - echo - - if [ "$use_stdio" = "1" ]; then - $GDB --batch -q --ex "r $use_args <$crash" --ex 'back' --ex 'disass $pc, $pc+16' --ex 'info reg' --ex 'quit' "$BIN" 0 - -#define INITIAL_GROWTH_SIZE (64) - -#define RAND_BELOW(limit) (rand() % (limit)) - -/* Use in a struct: creates a name_buf and a name_size variable. */ -#define BUF_VAR(type, name) \ - type * name##_buf; \ - size_t name##_size; -/* this fills in `&structptr->something_buf, &structptr->something_size`. */ -#define BUF_PARAMS(struct, name) \ - (void **)&struct->name##_buf, &struct->name##_size - -typedef struct { - -} afl_t; - -static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) { - - static s8 interesting_8[] = {INTERESTING_8}; - static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16}; - static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32}; - - switch (RAND_BELOW(12)) { - - case 0: { - - /* Flip a single bit somewhere. Spooky! */ - - s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8); - - out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7); - - break; - - } - - case 1: { - - /* Set byte to interesting value. */ - - u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))]; - out_buf[(RAND_BELOW(end - begin) + begin)] = val; - - break; - - } - - case 2: { - - /* Set word to interesting value, randomly choosing endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u16 *)(out_buf + byte_idx) = - interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]; - break; - case 1: - *(u16 *)(out_buf + byte_idx) = - SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]); - break; - - } - - break; - - } - - case 3: { - - /* Set dword to interesting value, randomly choosing endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u32 *)(out_buf + byte_idx) = - interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; - break; - case 1: - *(u32 *)(out_buf + byte_idx) = - SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); - break; - - } - - break; - - } - - case 4: { - - /* Set qword to interesting value, randomly choosing endian. */ - - if (end - begin < 8) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 7) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u64 *)(out_buf + byte_idx) = - (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; - break; - case 1: - *(u64 *)(out_buf + byte_idx) = SWAP64( - (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); - break; - - } - - break; - - } - - case 5: { - - /* Randomly subtract from byte. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX); - - break; - - } - - case 6: { - - /* Randomly add to byte. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX); - - break; - - } - - case 7: { - - /* Randomly subtract from word, random endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - if (RAND_BELOW(2)) { - - *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u16 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u16 *)(out_buf + byte_idx) = - SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num); - - } - - break; - - } - - case 8: { - - /* Randomly add to word, random endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - if (RAND_BELOW(2)) { - - *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u16 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u16 *)(out_buf + byte_idx) = - SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num); - - } - - break; - - } - - case 9: { - - /* Randomly subtract from dword, random endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - if (RAND_BELOW(2)) { - - *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u32 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u32 *)(out_buf + byte_idx) = - SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num); - - } - - break; - - } - - case 10: { - - /* Randomly add to dword, random endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - if (RAND_BELOW(2)) { - - *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u32 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u32 *)(out_buf + byte_idx) = - SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num); - - } - - break; - - } - - case 11: { - - /* Just set a random byte to a random value. Because, - why not. We use XOR with 1-255 to eliminate the - possibility of a no-op. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255); - - break; - - } - - } - -} - -/* This function calculates the next power of 2 greater or equal its argument. - @return The rounded up power of 2 (if no overflow) or 0 on overflow. -*/ -static inline size_t next_pow2(size_t in) { - - if (in == 0 || in > (size_t)-1) - return 0; /* avoid undefined behaviour under-/overflow */ - size_t out = in - 1; - out |= out >> 1; - out |= out >> 2; - out |= out >> 4; - out |= out >> 8; - out |= out >> 16; - return out + 1; - -} - -/* This function makes sure *size is > size_needed after call. - It will realloc *buf otherwise. - *size will grow exponentially as per: - https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ - Will return NULL and free *buf if size_needed is <1 or realloc failed. - @return For convenience, this function returns *buf. - */ -static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { - - /* No need to realloc */ - if (likely(size_needed && *size >= size_needed)) return *buf; - - /* No initial size was set */ - if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE; - - /* grow exponentially */ - size_t next_size = next_pow2(size_needed); - - /* handle overflow */ - if (!next_size) { next_size = size_needed; } - - /* alloc */ - *buf = realloc(*buf, next_size); - *size = *buf ? next_size : 0; - - return *buf; - -} - -/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ -static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2, - size_t *size2) { - - void * scratch_buf = *buf1; - size_t scratch_size = *size1; - *buf1 = *buf2; - *size1 = *size2; - *buf2 = scratch_buf; - *size2 = scratch_size; - -} - -#undef INITIAL_GROWTH_SIZE - -#endif - diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c deleted file mode 100644 index 23add128..00000000 --- a/examples/custom_mutators/example.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - New Custom Mutator for AFL++ - Written by Khaled Yakdan - Andrea Fioraldi - Shengtuo Hu - Dominik Maier -*/ - -// You need to use -I /path/to/AFLplusplus/include -#include "custom_mutator_helpers.h" - -#include -#include -#include -#include - -#define DATA_SIZE (100) - -static const char *commands[] = { - - "GET", - "PUT", - "DEL", - -}; - -typedef struct my_mutator { - - afl_t *afl; - - // any additional data here! - size_t trim_size_current; - int trimmming_steps; - int cur_step; - - // Reused buffers: - BUF_VAR(u8, fuzz); - BUF_VAR(u8, data); - BUF_VAR(u8, havoc); - BUF_VAR(u8, trim); - BUF_VAR(u8, post_process); - -} my_mutator_t; - -/** - * Initialize this custom mutator - * - * @param[in] afl a pointer to the internal state object. Can be ignored for - * now. - * @param[in] seed A seed for this mutator - the same seed should always mutate - * in the same way. - * @return Pointer to the data object this custom mutator instance should use. - * There may be multiple instances of this mutator in one afl-fuzz run! - * Return NULL on error. - */ -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { - - srand(seed); // needed also by surgical_havoc_mutate() - - my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); - if (!data) { - - perror("afl_custom_init alloc"); - return NULL; - - } - - data->afl = afl; - - return data; - -} - -/** - * Perform custom mutations on a given input - * - * (Optional for now. Required in the future) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[in] buf Pointer to input data to be mutated - * @param[in] buf_size Size of input data - * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on - * error. - * @param[in] add_buf Buffer containing the additional test case - * @param[in] add_buf_size Size of the additional test case - * @param[in] max_size Maximum size of the mutated output. The mutation must not - * produce data larger than max_size. - * @return Size of the mutated output. - */ -size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, - u8 **out_buf, uint8_t *add_buf, - size_t add_buf_size, // add_buf can be NULL - size_t max_size) { - - // Make sure that the packet size does not exceed the maximum size expected by - // the fuzzer - size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size; - - // maybe_grow is optimized to be quick for reused buffers. - u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size); - if (!mutated_out) { - - *out_buf = NULL; - perror("custom mutator allocation (maybe_grow)"); - return 0; /* afl-fuzz will very likely error out after this. */ - - } - - // Randomly select a command string to add as a header to the packet - memcpy(mutated_out, commands[rand() % 3], 3); - - // Mutate the payload of the packet - int i; - for (i = 0; i < 8; ++i) { - - // Randomly perform one of the (no len modification) havoc mutations - surgical_havoc_mutate(mutated_out, 3, mutated_size); - - } - - *out_buf = mutated_out; - return mutated_size; - -} - -/** - * A post-processing function to use right before AFL writes the test case to - * disk in order to execute the target. - * - * (Optional) If this functionality is not needed, simply don't define this - * function. - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[in] buf Buffer containing the test case to be executed - * @param[in] buf_size Size of the test case - * @param[out] out_buf Pointer to the buffer containing the test case after - * processing. External library should allocate memory for out_buf. - * The buf pointer may be reused (up to the given buf_size); - * @return Size of the output buffer after processing or the needed amount. - * A return of 0 indicates an error. - */ -size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf, - size_t buf_size, uint8_t **out_buf) { - - uint8_t *post_process_buf = - maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5); - if (!post_process_buf) { - - perror("custom mutator realloc failed."); - *out_buf = NULL; - return 0; - - } - - memcpy(post_process_buf + 5, buf, buf_size); - post_process_buf[0] = 'A'; - post_process_buf[1] = 'F'; - post_process_buf[2] = 'L'; - post_process_buf[3] = '+'; - post_process_buf[4] = '+'; - - *out_buf = post_process_buf; - - return buf_size + 5; - -} - -/** - * This method is called at the start of each trimming operation and receives - * the initial buffer. It should return the amount of iteration steps possible - * on this input (e.g. if your input has n elements and you want to remove - * them one by one, return n, if you do a binary search, return log(n), - * and so on...). - * - * If your trimming algorithm doesn't allow you to determine the amount of - * (remaining) steps easily (esp. while running), then you can alternatively - * return 1 here and always return 0 in post_trim until you are finished and - * no steps remain. In that case, returning 1 in post_trim will end the - * trimming routine. The whole current index/max iterations stuff is only used - * to show progress. - * - * (Optional) - * - * @param data pointer returned in afl_custom_init for this fuzz case - * @param buf Buffer containing the test case - * @param buf_size Size of the test case - * @return The amount of possible iteration steps to trim the input. - * negative on error. - */ -int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, - size_t buf_size) { - - // We simply trim once - data->trimmming_steps = 1; - - data->cur_step = 0; - - if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) { - - perror("init_trim grow"); - return -1; - - } - - memcpy(data->trim_buf, buf, buf_size); - - data->trim_size_current = buf_size; - - return data->trimmming_steps; - -} - -/** - * This method is called for each trimming operation. It doesn't have any - * arguments because we already have the initial buffer from init_trim and we - * can memorize the current state in *data. This can also save - * reparsing steps for each iteration. It should return the trimmed input - * buffer, where the returned data must not exceed the initial input data in - * length. Returning anything that is larger than the original data (passed - * to init_trim) will result in a fatal abort of AFLFuzz. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[out] out_buf Pointer to the buffer containing the trimmed test case. - * External library should allocate memory for out_buf. - * AFL++ will not release the memory after saving the test case. - * Keep a ref in *data. - * *out_buf = NULL is treated as error. - * @return Pointer to the size of the trimmed test case - */ -size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) { - - *out_buf = data->trim_buf; - - // Remove the last byte of the trimming input - return data->trim_size_current - 1; - -} - -/** - * This method is called after each trim operation to inform you if your - * trimming step was successful or not (in terms of coverage). If you receive - * a failure here, you should reset your input to the last known good state. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param success Indicates if the last trim operation was successful. - * @return The next trim iteration index (from 0 to the maximum amount of - * steps returned in init_trim). negative ret on failure. - */ -int32_t afl_custom_post_trim(my_mutator_t *data, int success) { - - if (success) { - - ++data->cur_step; - return data->cur_step; - - } - - return data->trimmming_steps; - -} - -/** - * Perform a single custom mutation on a given input. - * This mutation is stacked with the other muatations in havoc. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[in] buf Pointer to the input data to be mutated and the mutated - * output - * @param[in] buf_size Size of input data - * @param[out] out_buf The output buffer. buf can be reused, if the content - * fits. *out_buf = NULL is treated as error. - * @param[in] max_size Maximum size of the mutated output. The mutation must - * not produce data larger than max_size. - * @return Size of the mutated output. - */ -size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size, - u8 **out_buf, size_t max_size) { - - if (buf_size == 0) { - - *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1); - if (!*out_buf) { - - perror("custom havoc: maybe_grow"); - return 0; - - } - - **out_buf = rand() % 256; - buf_size = 1; - - } else { - - // We reuse buf here. It's legal and faster. - *out_buf = buf; - - } - - size_t victim = rand() % buf_size; - (*out_buf)[victim] += rand() % 10; - - return buf_size; - -} - -/** - * Return the probability (in percentage) that afl_custom_havoc_mutation - * is called in havoc. By default it is 6 %. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @return The probability (0-100). - */ -uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) { - - return 5; // 5 % - -} - -/** - * Determine whether the fuzzer should fuzz the queue entry or not. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param filename File name of the test case in the queue entry - * @return Return True(1) if the fuzzer will fuzz the queue entry, and - * False(0) otherwise. - */ -uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) { - - return 1; - -} - -/** - * Allow for additional analysis (e.g. calling a different tool that does a - * different kind of coverage and saves this for the custom mutator). - * - * (Optional) - * - * @param data pointer returned in afl_custom_init for this fuzz case - * @param filename_new_queue File name of the new queue entry - * @param filename_orig_queue File name of the original queue entry - */ -void afl_custom_queue_new_entry(my_mutator_t * data, - const uint8_t *filename_new_queue, - const uint8_t *filename_orig_queue) { - - /* Additional analysis on the original or new test case */ - -} - -/** - * Deinitialize everything - * - * @param data The data ptr from afl_custom_init - */ -void afl_custom_deinit(my_mutator_t *data) { - - free(data->post_process_buf); - free(data->havoc_buf); - free(data->data_buf); - free(data->fuzz_buf); - free(data->trim_buf); - free(data); - -} - diff --git a/examples/custom_mutators/example.py b/examples/custom_mutators/example.py deleted file mode 100644 index cf659e5a..00000000 --- a/examples/custom_mutators/example.py +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -''' -Example Python Module for AFLFuzz - -@author: Christian Holler (:decoder) - -@license: - -This Source Code Form is subject to the terms of the Mozilla Public -License, v. 2.0. If a copy of the MPL was not distributed with this -file, You can obtain one at http://mozilla.org/MPL/2.0/. - -@contact: choller@mozilla.com -''' - -import random - - -COMMANDS = [ - b"GET", - b"PUT", - b"DEL", - b"AAAAAAAAAAAAAAAAA", -] - - -def init(seed): - ''' - Called once when AFLFuzz starts up. Used to seed our RNG. - - @type seed: int - @param seed: A 32-bit random value - ''' - random.seed(seed) - - -def deinit(): - pass - - -def fuzz(buf, add_buf, max_size): - ''' - Called per fuzzing iteration. - - @type buf: bytearray - @param buf: The buffer that should be mutated. - - @type add_buf: bytearray - @param add_buf: A second buffer that can be used as mutation source. - - @type max_size: int - @param max_size: Maximum size of the mutated output. The mutation must not - produce data larger than max_size. - - @rtype: bytearray - @return: A new bytearray containing the mutated data - ''' - ret = bytearray(100) - - ret[:3] = random.choice(COMMANDS) - - return ret - -# Uncomment and implement the following methods if you want to use a custom -# trimming algorithm. See also the documentation for a better API description. - -# def init_trim(buf): -# ''' -# Called per trimming iteration. -# -# @type buf: bytearray -# @param buf: The buffer that should be trimmed. -# -# @rtype: int -# @return: The maximum number of trimming steps. -# ''' -# global ... -# -# # Initialize global variables -# -# # Figure out how many trimming steps are possible. -# # If this is not possible for your trimming, you can -# # return 1 instead and always return 0 in post_trim -# # until you are done (then you return 1). -# -# return steps -# -# def trim(): -# ''' -# Called per trimming iteration. -# -# @rtype: bytearray -# @return: A new bytearray containing the trimmed data. -# ''' -# global ... -# -# # Implement the actual trimming here -# -# return bytearray(...) -# -# def post_trim(success): -# ''' -# Called after each trimming operation. -# -# @type success: bool -# @param success: Indicates if the last trim operation was successful. -# -# @rtype: int -# @return: The next trim index (0 to max number of steps) where max -# number of steps indicates the trimming is done. -# ''' -# global ... -# -# if not success: -# # Restore last known successful input, determine next index -# else: -# # Just determine the next index, based on what was successfully -# # removed in the last step -# -# return next_index -# -# def post_process(buf): -# ''' -# Called just before the execution to write the test case in the format -# expected by the target -# -# @type buf: bytearray -# @param buf: The buffer containing the test case to be executed -# -# @rtype: bytearray -# @return: The buffer containing the test case after -# ''' -# return buf -# -# def havoc_mutation(buf, max_size): -# ''' -# Perform a single custom mutation on a given input. -# -# @type buf: bytearray -# @param buf: The buffer that should be mutated. -# -# @type max_size: int -# @param max_size: Maximum size of the mutated output. The mutation must not -# produce data larger than max_size. -# -# @rtype: bytearray -# @return: A new bytearray containing the mutated data -# ''' -# return mutated_buf -# -# def havoc_mutation_probability(): -# ''' -# Called for each `havoc_mutation`. Return the probability (in percentage) -# that `havoc_mutation` is called in havoc. Be default it is 6%. -# -# @rtype: int -# @return: The probability (0-100) -# ''' -# return prob -# -# def queue_get(filename): -# ''' -# Called at the beginning of each fuzz iteration to determine whether the -# test case should be fuzzed -# -# @type filename: str -# @param filename: File name of the test case in the current queue entry -# -# @rtype: bool -# @return: Return True if the custom mutator decides to fuzz the test case, -# and False otherwise -# ''' -# return True -# -# def queue_new_entry(filename_new_queue, filename_orig_queue): -# ''' -# Called after adding a new test case to the queue -# -# @type filename_new_queue: str -# @param filename_new_queue: File name of the new queue entry -# -# @type filename_orig_queue: str -# @param filename_orig_queue: File name of the original queue entry -# ''' -# pass diff --git a/examples/custom_mutators/post_library_gif.so.c b/examples/custom_mutators/post_library_gif.so.c deleted file mode 100644 index ac10f409..00000000 --- a/examples/custom_mutators/post_library_gif.so.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - american fuzzy lop++ - postprocessor library example - -------------------------------------------------- - - Originally written by Michal Zalewski - Edited by Dominik Maier, 2020 - - Copyright 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 - - Postprocessor libraries can be passed to afl-fuzz to perform final cleanup - of any mutated test cases - for example, to fix up checksums in PNG files. - - Please heed the following warnings: - - 1) In almost all cases, it is more productive to comment out checksum logic - in the targeted binary (as shown in ../libpng_no_checksum/). One possible - exception is the process of fuzzing binary-only software in QEMU mode. - - 2) The use of postprocessors for anything other than checksums is - questionable and may cause more harm than good. AFL is normally pretty good - about dealing with length fields, magic values, etc. - - 3) Postprocessors that do anything non-trivial must be extremely robust to - gracefully handle malformed data and other error conditions - otherwise, - they will crash and take afl-fuzz down with them. Be wary of reading past - *len and of integer overflows when calculating file offsets. - - In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really, - honestly know what you're doing =) - - With that out of the way: the postprocessor library is passed to afl-fuzz - via AFL_POST_LIBRARY. The library must be compiled with: - - gcc -shared -Wall -O3 post_library.so.c -o post_library.so - - AFL will call the afl_custom_post_process() function for every mutated output - buffer. From there, you have three choices: - - 1) If you don't want to modify the test case, simply set `*out_buf = in_buf` - and return the original `len`. - - 2) If you want to skip this test case altogether and have AFL generate a - new one, return 0 or set `*out_buf = NULL`. - Use this sparingly - it's faster than running the target program - with patently useless inputs, but still wastes CPU time. - - 3) If you want to modify the test case, allocate an appropriately-sized - buffer, move the data into that buffer, make the necessary changes, and - then return the new pointer as out_buf. Return an appropriate len - afterwards. - - Note that the buffer will *not* be freed for you. To avoid memory leaks, - you need to free it or reuse it on subsequent calls (as shown below). - - *** Feel free to reuse the original 'in_buf' BUFFER and return it. *** - - Aight. The example below shows a simple postprocessor that tries to make - sure that all input files start with "GIF89a". - - PS. If you don't like C, you can try out the unix-based wrapper from - Ben Nagy instead: https://github.com/bnagy/aflfix - - */ - -#include -#include -#include - -/* Header that must be present at the beginning of every test case: */ - -#define HEADER "GIF89a" - -typedef struct post_state { - - unsigned char *buf; - size_t size; - -} post_state_t; - -void *afl_custom_init(void *afl) { - - post_state_t *state = malloc(sizeof(post_state_t)); - if (!state) { - - perror("malloc"); - return NULL; - - } - - state->buf = calloc(sizeof(unsigned char), 4096); - if (!state->buf) { - - free(state); - perror("calloc"); - return NULL; - - } - - return state; - -} - -/* The actual postprocessor routine called by afl-fuzz: */ - -size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf, - unsigned int len, unsigned char **out_buf) { - - /* Skip execution altogether for buffers shorter than 6 bytes (just to - show how it's done). We can trust len to be sane. */ - - if (len < strlen(HEADER)) return 0; - - /* Do nothing for buffers that already start with the expected header. */ - - if (!memcmp(in_buf, HEADER, strlen(HEADER))) { - - *out_buf = in_buf; - return len; - - } - - /* Allocate memory for new buffer, reusing previous allocation if - possible. */ - - *out_buf = realloc(data->buf, len); - - /* If we're out of memory, the most graceful thing to do is to return the - original buffer and give up on modifying it. Let AFL handle OOM on its - own later on. */ - - if (!*out_buf) { - - *out_buf = in_buf; - return len; - - } - - /* Copy the original data to the new location. */ - - memcpy(*out_buf, in_buf, len); - - /* Insert the new header. */ - - memcpy(*out_buf, HEADER, strlen(HEADER)); - - /* Return the new len. It hasn't changed, so it's just len. */ - - return len; - -} - -/* Gets called afterwards */ -void afl_custom_deinit(post_state_t *data) { - - free(data->buf); - free(data); - -} - diff --git a/examples/custom_mutators/post_library_png.so.c b/examples/custom_mutators/post_library_png.so.c deleted file mode 100644 index 941f7e55..00000000 --- a/examples/custom_mutators/post_library_png.so.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - american fuzzy lop++ - postprocessor for PNG - ------------------------------------------ - - Originally written by Michal Zalewski - - Copyright 2015 Google Inc. All rights reserved. - Adapted to the new API, 2020 by Dominik Maier - - 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 - - See post_library.so.c for a general discussion of how to implement - postprocessors. This specific postprocessor attempts to fix up PNG - checksums, providing a slightly more complicated example than found - in post_library.so.c. - - Compile with: - - gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz - - */ - -#include -#include -#include -#include -#include - -#include - -/* A macro to round an integer up to 4 kB. */ - -#define UP4K(_i) ((((_i) >> 12) + 1) << 12) - -typedef struct post_state { - - unsigned char *buf; - size_t size; - -} post_state_t; - -void *afl_custom_init(void *afl) { - - post_state_t *state = malloc(sizeof(post_state_t)); - if (!state) { - - perror("malloc"); - return NULL; - - } - - state->buf = calloc(sizeof(unsigned char), 4096); - if (!state->buf) { - - free(state); - perror("calloc"); - return NULL; - - } - - return state; - -} - -size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf, - unsigned int len, - const unsigned char **out_buf) { - - unsigned char *new_buf = (unsigned char *)in_buf; - unsigned int pos = 8; - - /* Don't do anything if there's not enough room for the PNG header - (8 bytes). */ - - if (len < 8) { - - *out_buf = in_buf; - return len; - - } - - /* Minimum size of a zero-length PNG chunk is 12 bytes; if we - don't have that, we can bail out. */ - - while (pos + 12 <= len) { - - unsigned int chunk_len, real_cksum, file_cksum; - - /* Chunk length is the first big-endian dword in the chunk. */ - - chunk_len = ntohl(*(uint32_t *)(in_buf + pos)); - - /* Bail out if chunk size is too big or goes past EOF. */ - - if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break; - - /* Chunk checksum is calculated for chunk ID (dword) and the actual - payload. */ - - real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4)); - - /* The in-file checksum is the last dword past the chunk data. */ - - file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len); - - /* If the checksums do not match, we need to fix the file. */ - - if (real_cksum != file_cksum) { - - /* First modification? Make a copy of the input buffer. Round size - up to 4 kB to minimize the number of reallocs needed. */ - - if (new_buf == in_buf) { - - if (len <= data->size) { - - new_buf = data->buf; - - } else { - - new_buf = realloc(data->buf, UP4K(len)); - if (!new_buf) { - - *out_buf = in_buf; - return len; - - } - - data->buf = new_buf; - data->size = UP4K(len); - memcpy(new_buf, in_buf, len); - - } - - } - - *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum; - - } - - /* Skip the entire chunk and move to the next one. */ - - pos += 12 + chunk_len; - - } - - *out_buf = new_buf; - return len; - -} - -/* Gets called afterwards */ -void afl_custom_deinit(post_state_t *data) { - - free(data->buf); - free(data); - -} - diff --git a/examples/custom_mutators/simple-chunk-replace.py b/examples/custom_mutators/simple-chunk-replace.py deleted file mode 100644 index df2f4ca7..00000000 --- a/examples/custom_mutators/simple-chunk-replace.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -''' -Simple Chunk Cross-Over Replacement Module for AFLFuzz - -@author: Christian Holler (:decoder) - -@license: - -This Source Code Form is subject to the terms of the Mozilla Public -License, v. 2.0. If a copy of the MPL was not distributed with this -file, You can obtain one at http://mozilla.org/MPL/2.0/. - -@contact: choller@mozilla.com -''' - -import random - - -def init(seed): - ''' - Called once when AFLFuzz starts up. Used to seed our RNG. - - @type seed: int - @param seed: A 32-bit random value - ''' - # Seed our RNG - random.seed(seed) - - -def fuzz(buf, add_buf, max_size): - ''' - Called per fuzzing iteration. - - @type buf: bytearray - @param buf: The buffer that should be mutated. - - @type add_buf: bytearray - @param add_buf: A second buffer that can be used as mutation source. - - @type max_size: int - @param max_size: Maximum size of the mutated output. The mutation must not - produce data larger than max_size. - - @rtype: bytearray - @return: A new bytearray containing the mutated data - ''' - # Make a copy of our input buffer for returning - ret = bytearray(buf) - - # Take a random fragment length between 2 and 32 (or less if add_buf is shorter) - fragment_len = random.randint(1, min(len(add_buf), 32)) - - # Determine a random source index where to take the data chunk from - rand_src_idx = random.randint(0, len(add_buf) - fragment_len) - - # Determine a random destination index where to put the data chunk - rand_dst_idx = random.randint(0, len(buf)) - - # Make the chunk replacement - ret[rand_dst_idx:rand_dst_idx + fragment_len] = add_buf[rand_src_idx:rand_src_idx + fragment_len] - - # Return data - return ret diff --git a/examples/custom_mutators/simple_example.c b/examples/custom_mutators/simple_example.c deleted file mode 100644 index d888ec1f..00000000 --- a/examples/custom_mutators/simple_example.c +++ /dev/null @@ -1,74 +0,0 @@ -// This simple example just creates random buffer <= 100 filled with 'A' -// needs -I /path/to/AFLplusplus/include -#include "custom_mutator_helpers.h" - -#include -#include -#include -#include - -#ifndef _FIXED_CHAR - #define _FIXED_CHAR 0x41 -#endif - -typedef struct my_mutator { - - afl_t *afl; - - // Reused buffers: - BUF_VAR(u8, fuzz); - -} my_mutator_t; - -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { - - srand(seed); - my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); - if (!data) { - - perror("afl_custom_init alloc"); - return NULL; - - } - - data->afl = afl; - - return data; - -} - -size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, - u8 **out_buf, uint8_t *add_buf, - size_t add_buf_size, // add_buf can be NULL - size_t max_size) { - - int size = (rand() % 100) + 1; - if (size > max_size) size = max_size; - u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size); - if (!mutated_out) { - - *out_buf = NULL; - perror("custom mutator allocation (maybe_grow)"); - return 0; /* afl-fuzz will very likely error out after this. */ - - } - - memset(mutated_out, _FIXED_CHAR, size); - - *out_buf = mutated_out; - return size; - -} - -/** - * Deinitialize everything - * - * @param data The data ptr from afl_custom_init - */ -void afl_custom_deinit(my_mutator_t *data) { - - free(data->fuzz_buf); - free(data); - -} - diff --git a/examples/custom_mutators/wrapper_afl_min.py b/examples/custom_mutators/wrapper_afl_min.py deleted file mode 100644 index ecb03b55..00000000 --- a/examples/custom_mutators/wrapper_afl_min.py +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env python - -from XmlMutatorMin import XmlMutatorMin - -# Default settings (production mode) - -__mutator__ = None -__seed__ = "RANDOM" -__log__ = False -__log_file__ = "wrapper.log" - - -# AFL functions -def log(text): - """ - Logger - """ - - global __seed__ - global __log__ - global __log_file__ - - if __log__: - with open(__log_file__, "a") as logf: - logf.write("[%s] %s\n" % (__seed__, text)) - - -def init(seed): - """ - Called once when AFL starts up. Seed is used to identify the AFL instance in log files - """ - - global __mutator__ - global __seed__ - - # Get the seed - __seed__ = seed - - # Create a global mutation class - try: - __mutator__ = XmlMutatorMin(__seed__, verbose=__log__) - log("init(): Mutator created") - except RuntimeError as e: - log("init(): Can't create mutator: %s" % e.message) - - -def fuzz(buf, add_buf, max_size): - """ - Called for each fuzzing iteration. - """ - - global __mutator__ - - # Do we have a working mutator object? - if __mutator__ is None: - log("fuzz(): Can't fuzz, no mutator available") - return buf - - # Try to use the AFL buffer - via_buffer = True - - # Interpret the AFL buffer (an array of bytes) as a string - if via_buffer: - try: - buf_str = str(buf) - log("fuzz(): AFL buffer converted to a string") - except Exception: - via_buffer = False - log("fuzz(): Can't convert AFL buffer to a string") - - # Load XML from the AFL string - if via_buffer: - try: - __mutator__.init_from_string(buf_str) - log("fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" % len(buf_str)) - except Exception: - via_buffer = False - log("fuzz(): Can't initialize mutator with AFL buffer") - - # If init from AFL buffer wasn't succesful - if not via_buffer: - log("fuzz(): Returning unmodified AFL buffer") - return buf - - # Sucessful initialization -> mutate - try: - __mutator__.mutate(max=5) - log("fuzz(): Input mutated") - except Exception: - log("fuzz(): Can't mutate input => returning buf") - return buf - - # Convert mutated data to a array of bytes - try: - data = bytearray(__mutator__.save_to_string()) - log("fuzz(): Mutated data converted as bytes") - except Exception: - log("fuzz(): Can't convert mutated data to bytes => returning buf") - return buf - - # Everything went fine, returning mutated content - log("fuzz(): Returning %d bytes" % len(data)) - return data - - -# Main (for debug) -if __name__ == '__main__': - - __log__ = True - __log_file__ = "/dev/stdout" - __seed__ = "RANDOM" - - init(__seed__) - - in_1 = bytearray("ffffzzzzzzzzzzzz") - in_2 = bytearray("") - out = fuzz(in_1, in_2) - print(out) diff --git a/examples/defork/Makefile b/examples/defork/Makefile deleted file mode 100644 index e8240dba..00000000 --- a/examples/defork/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -# -# american fuzzy lop++ - defork -# ---------------------------------- -# -# 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 -# - -.PHONY: all install clean - -PREFIX ?= /usr/local -BIN_PATH = $(PREFIX)/bin -HELPER_PATH = $(PREFIX)/lib/afl - -CFLAGS = -fPIC -Wall -Wextra -LDFLAGS = -shared - -UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?) -UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$? - -_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=) -LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl) -LDFLAGS += $(LDFLAGS_ADD) - -# on gcc for arm there is no -m32, but -mbe32 -M32FLAG = -m32 -M64FLAG = -m64 - -CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?) -CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$? -CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?) -CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$? - -_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER) -__M32FLAG=$(_M32FLAG:00=-mbe32) -___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32) -M32FLAG=$(___M32FLAG) -#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" "" -# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)")) -# M32FLAG = -mbe32 -# endif -#endif - -all: defork32.so defork64.so - -defork32.so: defork.c - -@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork32 build failure (that's fine)" - -defork64.so: defork.c - -@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork64 build failure (that's fine)" - -install: defork32.so defork64.so - install -d -m 755 $(DESTDIR)$(HELPER_PATH)/ - if [ -f defork32.so ]; then set -e; install -m 755 defork32.so $(DESTDIR)$(HELPER_PATH)/; fi - if [ -f defork64.so ]; then set -e; install -m 755 defork64.so $(DESTDIR)$(HELPER_PATH)/; fi - -target: - ../../afl-clang forking_target.c -o forking_target -Wall -Wextra -Werror - -clean: - rm -f defork32.so defork64.so forking_target diff --git a/examples/defork/README.md b/examples/defork/README.md deleted file mode 100644 index 7e950323..00000000 --- a/examples/defork/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# defork - -when the target forks, this breaks all normal fuzzing runs. -Sometimes, though, it is enough to just run the child process. -If this is the case, then this LD_PRELOAD library will always return 0 on fork, -the target will belive it is running as the child, post-fork. - -This is defork.c from the amazing preeny project -https://github.com/zardus/preeny - -It is altered for afl++ to work with its fork-server: the initial fork will go through, the second fork will be blocked. diff --git a/examples/defork/defork.c b/examples/defork/defork.c deleted file mode 100644 index f71d1124..00000000 --- a/examples/defork/defork.c +++ /dev/null @@ -1,50 +0,0 @@ -#define __GNU_SOURCE -#include -#include -#include -#include - -#include "../../include/config.h" - -/* we want to fork once (for the afl++ forkserver), - then immediately return as child on subsequent forks. */ -static bool forked = 0; - -pid_t (*original_fork)(void); - -/* In case we are not running in afl, we use a dummy original_fork */ -static pid_t nop(void) { - - return 0; - -} - -__attribute__((constructor)) void preeny_fork_orig() { - - if (getenv(SHM_ENV_VAR)) { - - printf("defork: running in AFL++. Allowing forkserver.\n"); - original_fork = dlsym(RTLD_NEXT, "socket"); - - } else { - - printf("defork: no AFL++ detected. Disabling fork from the start.\n"); - original_fork = &nop; - - } - -} - -pid_t fork(void) { - - /* If we forked before, or if we're in the child (pid==0), - we don't want to fork anymore, else, we are still in the forkserver. - The forkserver parent needs to fork infinite times, each child should never - fork again. This can be written without branches and I hate myself for it. - */ - pid_t ret = !forked && original_fork(); - forked = !ret; - return ret; - -} - diff --git a/examples/defork/forking_target.c b/examples/defork/forking_target.c deleted file mode 100644 index 628d23c9..00000000 --- a/examples/defork/forking_target.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include - -/* This is an example target for defork.c - fuzz using -``` -mkdir in; echo a > ./in/a -AFL_PRELOAD=./defork64.so ../../afl-fuzz -i in -o out -- ./forking_target @@ -``` -*/ - -int main(int argc, char **argv) { - - if (argc < 2) { - - printf("Example tool to test defork.\nUsage ./forking_target \n"); - return -1; - - } - - pid_t pid = fork(); - if (pid == 0) { - - printf("We're in the child.\n"); - FILE *f = fopen(argv[1], "r"); - char buf[4096]; - fread(buf, 1, 4096, f); - fclose(f); - uint32_t offset = buf[100] + (buf[101] << 8); - char test_val = buf[offset]; - return test_val < 100; - - } else if (pid < 0) { - - perror("fork"); - return -1; - - } else { - - printf("We are in the parent - defork didn't work! :( (pid=%d)\n", - (int)pid); - - } - - return 0; - -} - diff --git a/examples/distributed_fuzzing/sync_script.sh b/examples/distributed_fuzzing/sync_script.sh deleted file mode 100755 index b28ff6cd..00000000 --- a/examples/distributed_fuzzing/sync_script.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/sh -# -# american fuzzy lop++ - fuzzer synchronization tool -# -------------------------------------------------- -# -# Originally written by Michal Zalewski -# -# Copyright 2014 Google Inc. All rights reserved. -# Copyright 2019-2020 AFLplusplus Project. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# To make this script work: -# -# - Edit FUZZ_HOSTS, FUZZ_DOMAIN, FUZZ_USER, and SYNC_DIR to reflect your -# environment. -# -# - Make sure that the system you are running this on can log into FUZZ_HOSTS -# without a password (authorized_keys or otherwise). -# -# - Make sure that every fuzzer is running with -o pointing to SYNC_DIR and -S -# that consists of its local host name, followed by an underscore, and then -# by some host-local fuzzer ID. -# - -# Hosts to synchronize the data across. -FUZZ_HOSTS='host1 host2 host3 host4' - -# Domain for all hosts -FUZZ_DOMAIN='example.com' - -# Remote user for SSH -FUZZ_USER=bob - -# Directory to synchronize -SYNC_DIR='/home/bob/sync_dir' - -# We only capture -M main nodes, set the name to your chosen naming scheme -MAIN_NAME='main' - -# Interval (seconds) between sync attempts (eg one hour) -SYNC_INTERVAL=$((60 * 60)) - -if [ "$AFL_ALLOW_TMP" = "" ]; then - - if [ "$PWD" = "/tmp" -o "$PWD" = "/var/tmp" ]; then - echo "[-] Error: do not use shared /tmp or /var/tmp directories with this script." 1>&2 - exit 1 - fi - -fi - -rm -rf .sync_tmp 2>/dev/null -mkdir .sync_tmp || exit 1 - -while :; do - - # Pull data in... - - for host in $FUZZ_HOSTS; do - - echo "[*] Retrieving data from ${host}.${FUZZ_DOMAIN}..." - - ssh -o 'passwordauthentication no' ${FUZZ_USER}@${host}.$FUZZ_DOMAIN \ - "cd '$SYNC_DIR' && tar -czf - ${host}_${MAIN_NAME}*/" > ".sync_tmp/${host}.tgz" - - done - - # Distribute data. For large fleets, see tips in the docs/ directory. - - for dst_host in $FUZZ_HOSTS; do - - echo "[*] Distributing data to ${dst_host}.${FUZZ_DOMAIN}..." - - for src_host in $FUZZ_HOSTS; do - - test "$src_host" = "$dst_host" && continue - - echo " Sending fuzzer data from ${src_host}.${FUZZ_DOMAIN}..." - - ssh -o 'passwordauthentication no' ${FUZZ_USER}@$dst_host \ - "cd '$SYNC_DIR' && tar -xkzf - " < ".sync_tmp/${src_host}.tgz" - - done - - done - - echo "[+] Done. Sleeping for $SYNC_INTERVAL seconds (Ctrl-C to quit)." - - sleep $SYNC_INTERVAL - -done - diff --git a/examples/libpng_no_checksum/libpng-nocrc.patch b/examples/libpng_no_checksum/libpng-nocrc.patch deleted file mode 100644 index 0a3793a0..00000000 --- a/examples/libpng_no_checksum/libpng-nocrc.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- pngrutil.c.orig 2014-06-12 03:35:16.000000000 +0200 -+++ pngrutil.c 2014-07-01 05:08:31.000000000 +0200 -@@ -268,7 +268,11 @@ - if (need_crc != 0) - { - crc = png_get_uint_32(crc_bytes); -- return ((int)(crc != png_ptr->crc)); -+ -+ if (crc != png_ptr->crc) -+ fprintf(stderr, "NOTE: CRC in the file is 0x%08x, change to 0x%08x\n", crc, png_ptr->crc); -+ -+ return ((int)(1 != 1)); - } - - else diff --git a/examples/persistent_mode/Makefile b/examples/persistent_mode/Makefile deleted file mode 100644 index 6fa1c30e..00000000 --- a/examples/persistent_mode/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -all: - afl-clang-fast -o persistent_demo persistent_demo.c - afl-clang-fast -o persistent_demo_new persistent_demo_new.c - AFL_DONT_OPTIMIZE=1 afl-clang-fast -o test-instr test-instr.c - -document: - AFL_DONT_OPTIMIZE=1 afl-clang-fast -D_AFL_DOCUMENT_MUTATIONS -o test-instr test-instr.c - -clean: - rm -f persistent_demo persistent_demo_new test-instr diff --git a/examples/persistent_mode/persistent_demo.c b/examples/persistent_mode/persistent_demo.c deleted file mode 100644 index 4cedc32c..00000000 --- a/examples/persistent_mode/persistent_demo.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - american fuzzy lop++ - persistent mode example - -------------------------------------------- - - Originally written by Michal Zalewski - - Copyright 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 - - This file demonstrates the high-performance "persistent mode" that may be - suitable for fuzzing certain fast and well-behaved libraries, provided that - they are stateless or that their internal state can be easily reset - across runs. - - To make this work, the library and this shim need to be compiled in LLVM - mode using afl-clang-fast (other compiler wrappers will *not* work). - - */ - -#include -#include -#include -#include -#include - -/* Main entry point. */ - -int main(int argc, char **argv) { - - ssize_t len; /* how much input did we read? */ - char buf[100]; /* Example-only buffer, you'd replace it with other global or - local variables appropriate for your use case. */ - - /* The number passed to __AFL_LOOP() controls the maximum number of - iterations before the loop exits and the program is allowed to - terminate normally. This limits the impact of accidental memory leaks - and similar hiccups. */ - - __AFL_INIT(); - while (__AFL_LOOP(1000)) { - - /*** PLACEHOLDER CODE ***/ - - /* STEP 1: Fully re-initialize all critical variables. In our example, this - involves zeroing buf[], our input buffer. */ - - memset(buf, 0, 100); - - /* STEP 2: Read input data. When reading from stdin, no special preparation - is required. When reading from a named file, you need to close - the old descriptor and reopen the file first! - - Beware of reading from buffered FILE* objects such as stdin. Use - raw file descriptors or call fopen() / fdopen() in every pass. */ - - len = read(0, buf, 100); - - /* STEP 3: This is where we'd call the tested library on the read data. - We just have some trivial inline code that faults on 'foo!'. */ - - /* do we have enough data? */ - if (len < 8) continue; - - if (buf[0] == 'f') { - - printf("one\n"); - if (buf[1] == 'o') { - - printf("two\n"); - if (buf[2] == 'o') { - - printf("three\n"); - if (buf[3] == '!') { - - printf("four\n"); - if (buf[4] == '!') { - - printf("five\n"); - if (buf[5] == '!') { - - printf("six\n"); - abort(); - - } - - } - - } - - } - - } - - } - - /*** END PLACEHOLDER CODE ***/ - - } - - /* Once the loop is exited, terminate normally - AFL will restart the process - when this happens, with a clean slate when it comes to allocated memory, - leftover file descriptors, etc. */ - - return 0; - -} - diff --git a/examples/persistent_mode/persistent_demo_new.c b/examples/persistent_mode/persistent_demo_new.c deleted file mode 100644 index a29792ff..00000000 --- a/examples/persistent_mode/persistent_demo_new.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - american fuzzy lop++ - persistent mode example - -------------------------------------------- - - Originally written by Michal Zalewski - - Copyright 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 - - This file demonstrates the high-performance "persistent mode" that may be - suitable for fuzzing certain fast and well-behaved libraries, provided that - they are stateless or that their internal state can be easily reset - across runs. - - To make this work, the library and this shim need to be compiled in LLVM - mode using afl-clang-fast (other compiler wrappers will *not* work). - - */ - -#include -#include -#include -#include -#include - -/* this lets the source compile without afl-clang-fast/lto */ -#ifndef __AFL_FUZZ_TESTCASE_LEN - -ssize_t fuzz_len; -unsigned char fuzz_buf[1024000]; - - #define __AFL_FUZZ_TESTCASE_LEN fuzz_len - #define __AFL_FUZZ_TESTCASE_BUF fuzz_buf - #define __AFL_FUZZ_INIT() void sync(void); - #define __AFL_LOOP(x) \ - ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0) - #define __AFL_INIT() sync() - -#endif - -__AFL_FUZZ_INIT(); - -/* Main entry point. */ - -int main(int argc, char **argv) { - - ssize_t len; /* how much input did we read? */ - unsigned char *buf; /* test case buffer pointer */ - - /* The number passed to __AFL_LOOP() controls the maximum number of - iterations before the loop exits and the program is allowed to - terminate normally. This limits the impact of accidental memory leaks - and similar hiccups. */ - - __AFL_INIT(); - buf = __AFL_FUZZ_TESTCASE_BUF; // this must be assigned before __AFL_LOOP! - - while (__AFL_LOOP(1000)) { // increase if you have good stability - - len = __AFL_FUZZ_TESTCASE_LEN; // do not use the macro directly in a call! - - fprintf(stderr, "input: %zd \"%s\"\n", len, buf); - - /* do we have enough data? */ - if (len < 8) continue; - - if (strcmp((char *)buf, "thisisateststring") == 0) printf("teststring\n"); - - if (buf[0] == 'f') { - - printf("one\n"); - if (buf[1] == 'o') { - - printf("two\n"); - if (buf[2] == 'o') { - - printf("three\n"); - if (buf[3] == '!') { - - printf("four\n"); - if (buf[4] == '!') { - - printf("five\n"); - if (buf[6] == '!') { - - printf("six\n"); - abort(); - - } - - } - - } - - } - - } - - } - - /*** END PLACEHOLDER CODE ***/ - - } - - /* Once the loop is exited, terminate normally - AFL will restart the process - when this happens, with a clean slate when it comes to allocated memory, - leftover file descriptors, etc. */ - - return 0; - -} - diff --git a/examples/persistent_mode/test-instr.c b/examples/persistent_mode/test-instr.c deleted file mode 100644 index a6188b22..00000000 --- a/examples/persistent_mode/test-instr.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - american fuzzy lop++ - a trivial program to test the build - -------------------------------------------------------- - Originally written by Michal Zalewski - Copyright 2014 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - http://www.apache.org/licenses/LICENSE-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include - -__AFL_FUZZ_INIT(); - -int main(int argc, char **argv) { - - __AFL_INIT(); - unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; - - while (__AFL_LOOP(2147483647)) { // MAX_INT if you have 100% stability - - unsigned int len = __AFL_FUZZ_TESTCASE_LEN; - -#ifdef _AFL_DOCUMENT_MUTATIONS - static unsigned int counter = 0; - char fn[32]; - sprintf(fn, "%09u:test-instr", counter); - int fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (fd_doc >= 0) { - - if (write(fd_doc, buf, len) != __afl_fuzz_len) { - - fprintf(stderr, "write of mutation file failed: %s\n", fn); - unlink(fn); - - } - - close(fd_doc); - - } - - counter++; -#endif - - // fprintf(stderr, "len: %u\n", len); - - if (!len) continue; - - if (buf[0] == '0') - printf("Looks like a zero to me!\n"); - else if (buf[0] == '1') - printf("Pretty sure that is a one!\n"); - else - printf("Neither one or zero? How quaint!\n"); - - } - - return 0; - -} - diff --git a/examples/qemu_persistent_hook/Makefile b/examples/qemu_persistent_hook/Makefile deleted file mode 100644 index 85db1b46..00000000 --- a/examples/qemu_persistent_hook/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -all: - $(CC) -no-pie test.c -o test - $(CC) -fPIC -shared read_into_rdi.c -o read_into_rdi.so - -clean: - rm -rf in out test read_into_rdi.so diff --git a/examples/qemu_persistent_hook/README.md b/examples/qemu_persistent_hook/README.md deleted file mode 100644 index 3f908c22..00000000 --- a/examples/qemu_persistent_hook/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# QEMU persistent hook example - -Compile the test binary and the library: - -``` -make -``` - -Fuzz with: - -``` -export AFL_QEMU_PERSISTENT_ADDR=0x$(nm test | grep "T target_func" | awk '{print $1}') -export AFL_QEMU_PERSISTENT_HOOK=./read_into_rdi.so - -mkdir in -echo 0000 > in/in - -../../afl-fuzz -Q -i in -o out -- ./test -``` diff --git a/examples/qemu_persistent_hook/read_into_rdi.c b/examples/qemu_persistent_hook/read_into_rdi.c deleted file mode 100644 index f4a8ae59..00000000 --- a/examples/qemu_persistent_hook/read_into_rdi.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "../../qemu_mode/qemuafl/qemuafl/api.h" - -#include -#include - -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { -\ -#define g2h(x) ((void *)((unsigned long)(x) + guest_base)) -#define h2g(x) ((uint64_t)(x)-guest_base) - - // In this example the register RDI is pointing to the memory location - // of the target buffer, and the length of the input is in RSI. - // This can be seen with a debugger, e.g. gdb (and "disass main") - - printf("Placing input into 0x%lx\n", regs->rdi); - - if (input_buf_len > 1024) input_buf_len = 1024; - memcpy(g2h(regs->rdi), input_buf, input_buf_len); - regs->rsi = input_buf_len; - -#undef g2h -#undef h2g - -} - -int afl_persistent_hook_init(void) { - - // 1 for shared memory input (faster), 0 for normal input (you have to use - // read(), input_buf will be NULL) - return 1; - -} - diff --git a/examples/qemu_persistent_hook/test.c b/examples/qemu_persistent_hook/test.c deleted file mode 100644 index afeff202..00000000 --- a/examples/qemu_persistent_hook/test.c +++ /dev/null @@ -1,35 +0,0 @@ -#include - -int target_func(unsigned char *buf, int size) { - - printf("buffer:%p, size:%p\n", buf, size); - switch (buf[0]) { - - case 1: - if (buf[1] == '\x44') { puts("a"); } - break; - case 0xff: - if (buf[2] == '\xff') { - - if (buf[1] == '\x44') { puts("b"); } - - } - - break; - default: - break; - - } - - return 1; - -} - -char data[1024]; - -int main() { - - target_func(data, 1024); - -} - diff --git a/examples/socket_fuzzing/Makefile b/examples/socket_fuzzing/Makefile deleted file mode 100644 index 9476e2d5..00000000 --- a/examples/socket_fuzzing/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -# -# american fuzzy lop++ - socket_fuzz -# ---------------------------------- -# -# 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 -# - -.PHONY: all install clean - -PREFIX ?= /usr/local -BIN_PATH = $(PREFIX)/bin -HELPER_PATH = $(PREFIX)/lib/afl - -CFLAGS = -fPIC -Wall -Wextra -LDFLAGS = -shared - -UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?) -UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$? - -_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=) -LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl) -LDFLAGS += $(LDFLAGS_ADD) - -# on gcc for arm there is no -m32, but -mbe32 -M32FLAG = -m32 -M64FLAG = -m64 - -CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?) -CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$? -CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?) -CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$? - -_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER) -__M32FLAG=$(_M32FLAG:00=-mbe32) -___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32) -M32FLAG=$(___M32FLAG) -#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" "" -# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)")) -# M32FLAG = -mbe32 -# endif -#endif - -all: socketfuzz32.so socketfuzz64.so - -socketfuzz32.so: socketfuzz.c - -@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz32 build failure (that's fine)" - -socketfuzz64.so: socketfuzz.c - -@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz64 build failure (that's fine)" - -install: socketfuzz32.so socketfuzz64.so - install -d -m 755 $(DESTDIR)$(HELPER_PATH)/ - if [ -f socketfuzz32.so ]; then set -e; install -m 755 socketfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi - if [ -f socketfuzz64.so ]; then set -e; install -m 755 socketfuzz64.so $(DESTDIR)$(HELPER_PATH)/; fi - -clean: - rm -f socketfuzz32.so socketfuzz64.so diff --git a/examples/socket_fuzzing/README.md b/examples/socket_fuzzing/README.md deleted file mode 100644 index 79f28bea..00000000 --- a/examples/socket_fuzzing/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# socketfuzz - -when you want to fuzz a network service and you can not/do not want to modify -the source (or just have a binary), then this LD_PRELOAD library will allow -for sending input to stdin which the target binary will think is coming from -a network socket. - -This is desock_dup.c from the amazing preeny project -https://github.com/zardus/preeny - -It is packaged in afl++ to have it at hand if needed diff --git a/examples/socket_fuzzing/socketfuzz.c b/examples/socket_fuzzing/socketfuzz.c deleted file mode 100644 index 3ec8383b..00000000 --- a/examples/socket_fuzzing/socketfuzz.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * This is desock_dup.c from the amazing preeny project - * https://github.com/zardus/preeny - * - * It is packaged in afl++ to have it at hand if needed - * - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include // -#include // -#include // -#include // -#include -#include -#include -#include -#include -#include -#include -//#include "logging.h" // switche from preeny_info() to fprintf(stderr, "Info: " - -// -// originals -// -int (*original_close)(int); -int (*original_dup2)(int, int); -__attribute__((constructor)) void preeny_desock_dup_orig() { - - original_close = dlsym(RTLD_NEXT, "close"); - original_dup2 = dlsym(RTLD_NEXT, "dup2"); - -} - -int close(int sockfd) { - - if (sockfd <= 2) { - - fprintf(stderr, "Info: Disabling close on %d\n", sockfd); - return 0; - - } else { - - return original_close(sockfd); - - } - -} - -int dup2(int old, int new) { - - if (new <= 2) { - - fprintf(stderr, "Info: Disabling dup from %d to %d\n", old, new); - return 0; - - } else { - - return original_dup2(old, new); - - } - -} - -int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - - (void)sockfd; - (void)addr; - (void)addrlen; - fprintf(stderr, "Info: Emulating accept on %d\n", sockfd); - return 0; - -} - -int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { - - (void)sockfd; - (void)addr; - (void)addrlen; - fprintf(stderr, "Info: Emulating bind on port %d\n", - ntohs(((struct sockaddr_in *)addr)->sin_port)); - return 0; - -} - -int listen(int sockfd, int backlog) { - - (void)sockfd; - (void)backlog; - return 0; - -} - -int setsockopt(int sockfd, int level, int optid, const void *optdata, - socklen_t optdatalen) { - - (void)sockfd; - (void)level; - (void)optid; - (void)optdata; - (void)optdatalen; - return 0; - -} - diff --git a/instrumentation/README.gcc_plugin.md b/instrumentation/README.gcc_plugin.md index 6ccb5fd3..12449efd 100644 --- a/instrumentation/README.gcc_plugin.md +++ b/instrumentation/README.gcc_plugin.md @@ -147,7 +147,7 @@ The numerical value specified within the loop controls the maximum number of iterations before AFL will restart the process from scratch. This minimizes the impact of memory leaks and similar glitches; 1000 is a good starting point. -A more detailed template is shown in ../examples/persistent_mode/. +A more detailed template is shown in ../utils/persistent_mode/. Similarly to the previous mode, the feature works only with afl-gcc-fast or afl-clang-fast; #ifdef guards can be used to suppress it when using other compilers. diff --git a/instrumentation/README.persistent_mode.md b/instrumentation/README.persistent_mode.md index 49f5ee8b..2cf76adf 100644 --- a/instrumentation/README.persistent_mode.md +++ b/instrumentation/README.persistent_mode.md @@ -11,7 +11,7 @@ and that its state can be resetted so that multiple calls can be performed without resource leaks and former runs having no impact on following runs (this can be seen by the `stability` indicator in the `afl-fuzz` UI). -Examples can be found in [examples/persistent_mode](../examples/persistent_mode). +Examples can be found in [utils/persistent_mode](../utils/persistent_mode). ## 2) TLDR; @@ -150,7 +150,7 @@ the impact of memory leaks and similar glitches; 1000 is a good starting point, and going much higher increases the likelihood of hiccups without giving you any real performance benefits. -A more detailed template is shown in ../examples/persistent_mode/. +A more detailed template is shown in ../utils/persistent_mode/. Similarly to the previous mode, the feature works only with afl-clang-fast; #ifdef guards can be used to suppress it when using other compilers. diff --git a/qemu_mode/README.md b/qemu_mode/README.md index 1c5d240c..58e48e91 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -179,7 +179,7 @@ match. ## 12) Gotchas, feedback, bugs If you need to fix up checksums or do other cleanup on mutated test cases, see -examples/custom_mutators/ for a viable solution. +utils/custom_mutators/ for a viable solution. Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate the "shadow VM" trick employed by the sanitizers and will probably just diff --git a/qemu_mode/README.persistent.md b/qemu_mode/README.persistent.md index d9e7e1cc..2ca5c873 100644 --- a/qemu_mode/README.persistent.md +++ b/qemu_mode/README.persistent.md @@ -172,4 +172,4 @@ and so the input_buf variables of the hook becomes meaningful. Otherwise, you have to read the input from a file like stdin. An example that you can use with little modification for your target can -be found here: [examples/qemu_persistent_hook](../examples/qemu_persistent_hook) +be found here: [utils/qemu_persistent_hook](../utils/qemu_persistent_hook) diff --git a/src/afl-as.c b/src/afl-as.c index 7d70bfcd..3d6f7d5e 100644 --- a/src/afl-as.c +++ b/src/afl-as.c @@ -27,7 +27,7 @@ utility has right now is to be able to skip them gracefully and allow the compilation process to continue. - That said, see examples/clang_asm_normalize/ for a solution that may + That said, see utils/clang_asm_normalize/ for a solution that may allow clang users to make things work even with hand-crafted assembly. Just note that there is no equivalent for GCC. diff --git a/test/test-custom-mutators.sh b/test/test-custom-mutators.sh index d4d21048..24c95ac7 100755 --- a/test/test-custom-mutators.sh +++ b/test/test-custom-mutators.sh @@ -5,7 +5,7 @@ $ECHO "$BLUE[*] Testing: custom mutator" test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { # normalize path - CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../examples/custom_mutators;pwd) + CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../utils/custom_mutators;pwd) test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && { unset AFL_CC # Compile the vulnerable program for single mutator @@ -29,8 +29,8 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { } } # Compile the custom mutator - cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../examples/custom_mutators/simple_example.c -o libexamplemutator.so > /dev/null 2>&1 - cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../examples/custom_mutators/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1 + cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator.so > /dev/null 2>&1 + cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1 test -e test-custom-mutator -a -e ./libexamplemutator.so && { # Create input directory mkdir -p in @@ -109,7 +109,7 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { #test "$CODE" = 1 && { $ECHO "$YELLOW[!] custom mutator tests currently will not fail travis" ; CODE=0 ; } - make -C ../examples/custom_mutators clean > /dev/null 2>&1 + make -C ../utils/custom_mutators clean > /dev/null 2>&1 rm -f test-custom-mutator rm -f test-custom-mutators } || { diff --git a/test/test-gcc-plugin.sh b/test/test-gcc-plugin.sh index af8674c9..71d86364 100755 --- a/test/test-gcc-plugin.sh +++ b/test/test-gcc-plugin.sh @@ -94,7 +94,7 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && { CODE=1 } rm -f test-compcov test.out instrumentlist.txt - ../afl-gcc-fast -o test-persistent ../examples/persistent_mode/persistent_demo.c > /dev/null 2>&1 + ../afl-gcc-fast -o test-persistent ../utils/persistent_mode/persistent_demo.c > /dev/null 2>&1 test -e test-persistent && { echo foo | ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && { $ECHO "$GREEN[+] gcc_plugin persistent mode feature works correctly" diff --git a/test/test-llvm-lto.sh b/test/test-llvm-lto.sh index bdb08559..e10f4cf7 100755 --- a/test/test-llvm-lto.sh +++ b/test/test-llvm-lto.sh @@ -57,7 +57,7 @@ test -e ../afl-clang-lto -a -e ../afl-llvm-lto-instrumentation.so && { CODE=1 } rm -f test-compcov test.out instrumentlist.txt - ../afl-clang-lto -o test-persistent ../examples/persistent_mode/persistent_mode.c > /dev/null 2>&1 + ../afl-clang-lto -o test-persistent ../utils/persistent_mode/persistent_mode.c > /dev/null 2>&1 test -e test-persistent && { echo foo | ../afl-showmap -m none -o /dev/null -q -r ./test-persistent && { $ECHO "$GREEN[+] llvm_mode LTO persistent mode feature works correctly" diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 14778e1c..4fcaf367 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -209,7 +209,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { INCOMPLETE=1 } rm -rf errors test-cmplog in core.* - ../afl-clang-fast -o test-persistent ../examples/persistent_mode/persistent_demo.c > /dev/null 2>&1 + ../afl-clang-fast -o test-persistent ../utils/persistent_mode/persistent_demo.c > /dev/null 2>&1 test -e test-persistent && { echo foo | ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -q -r ./test-persistent && { $ECHO "$GREEN[+] llvm_mode persistent mode feature works correctly" diff --git a/utils/README.md b/utils/README.md new file mode 100644 index 00000000..336b6b6c --- /dev/null +++ b/utils/README.md @@ -0,0 +1,54 @@ +# AFL++ Examples + +Here's a quick overview of the stuff you can find in this directory: + + - afl_network_proxy - fuzz a target over the network: afl-fuzz on + a host, target on an embedded system. + + - afl_proxy - skeleton file example to show how to fuzz + something where you gather coverage data via + different means, e.g. hw debugger + + - afl_untracer - fuzz binary-only libraries much faster but with + less coverage than qemu_mode + + - argv_fuzzing - a simple wrapper to allow cmdline to be fuzzed + (e.g., to test setuid programs). + + - asan_cgroups - a contributed script to simplify fuzzing ASAN + binaries with robust memory limits on Linux. + + - bash_shellshock - a simple hack used to find a bunch of + post-Shellshock bugs in bash. + + - canvas_harness - a test harness used to find browser bugs with a + corpus generated using simple image parsing + binaries & afl-fuzz. + + - clang_asm_normalize - a script that makes it easy to instrument + hand-written assembly, provided that you have clang. + + - crash_triage - a very rudimentary example of how to annotate crashes + with additional gdb metadata. + + - custom_mutators - examples for the afl++ custom mutator interface in + C and Python + + - distributed_fuzzing - a sample script for synchronizing fuzzer instances + across multiple machines (see parallel_fuzzing.md). + + - libpng_no_checksum - a sample patch for removing CRC checks in libpng. + + - persistent_mode - an example of how to use the LLVM persistent process + mode to speed up certain fuzzing jobs. + + - socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin + for fuzzing access with afl++ + +Note that the minimize_corpus.sh tool has graduated from the utils/ +directory and is now available as ../afl-cmin. The LLVM mode has likewise +graduated to ../instrumentation/*. + +Most of the tools in this directory are meant chiefly as examples that need to +be tweaked for your specific needs. They come with some basic documentation, +but are not necessarily production-grade. diff --git a/utils/afl_frida/GNUmakefile b/utils/afl_frida/GNUmakefile new file mode 100644 index 00000000..c154f3a4 --- /dev/null +++ b/utils/afl_frida/GNUmakefile @@ -0,0 +1,23 @@ +ifdef DEBUG + OPT=-O0 -D_DEBUG=\"1\" +else + OPT=-O3 -funroll-loops +endif + +all: afl-frida libtestinstr.so + +libfrida-gum.a: + @echo Download and extract frida-gum-devkit-VERSION-PLATFORM.tar.xz for your platform from https://github.com/frida/frida/releases/latest + @exit 1 + +afl-frida: afl-frida.c libfrida-gum.a + $(CC) -g $(OPT) -o afl-frida -Wno-format -Wno-pointer-sign -I. -fpermissive -fPIC afl-frida.c ../../afl-llvm-rt.o libfrida-gum.a -ldl -lresolv -pthread + +libtestinstr.so: libtestinstr.c + $(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c + +clean: + rm -f afl-frida *~ core *.o libtestinstr.so + +deepclean: clean + rm -f libfrida-gum.a frida-gum* diff --git a/utils/afl_frida/Makefile b/utils/afl_frida/Makefile new file mode 100644 index 00000000..0b306dde --- /dev/null +++ b/utils/afl_frida/Makefile @@ -0,0 +1,2 @@ +all: + @echo please use GNU make, thanks! diff --git a/utils/afl_frida/README.md b/utils/afl_frida/README.md new file mode 100644 index 00000000..7743479b --- /dev/null +++ b/utils/afl_frida/README.md @@ -0,0 +1,34 @@ +# afl-frida - faster fuzzing of binary-only libraries + +## Introduction + +afl-frida is an example skeleton file which can easily be used to fuzz +a closed source library. + +It requires less memory and is x5-10 faster than qemu_mode but does not +provide interesting features like compcov or cmplog. + +## How-to + +### Modify afl-frida.c + +Read and modify afl-frida.c then `make`. +To adapt afl-frida.c to your needs, read the header of the file and then +search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations. + +### Fuzzing + +Example (after modifying afl-frida.c to your needs and compile it): +``` +LD_LIBRARY_PATH=/path/to/the/target/library afl-fuzz -i in -o out -- ./afl-frida +``` +(or even remote via afl-network-proxy). + +# Speed and stability + +The speed is very good, about x12 of fork() qemu_mode. +However the stability is low. Reason is currently unknown. + +# Background + +This code is copied for a larger part from https://github.com/meme/hotwax diff --git a/utils/afl_frida/afl-frida.c b/utils/afl_frida/afl-frida.c new file mode 100644 index 00000000..31bf8f25 --- /dev/null +++ b/utils/afl_frida/afl-frida.c @@ -0,0 +1,542 @@ +/* + american fuzzy lop++ - afl-frida skeleton example + ------------------------------------------------- + + Copyright 2020 AFLplusplus Project. All rights reserved. + + Written mostly by meme -> https://github.com/meme/hotwax + + Modifications by Marc Heuse + + 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 + + HOW-TO + ====== + + You only need to change the following: + + 1. set the defines and function call parameters. + 2. dl load the library you want to fuzz, lookup the functions you need + and setup the calls to these. + 3. in the while loop you call the functions in the necessary order - + incl the cleanup. the cleanup is important! + + Just look these steps up in the code, look for "// STEP x:" + +*/ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __APPLE__ + #include + #include +#endif + +int debug = 0; + +// STEP 1: + +// The presets are for the example libtestinstr.so: + +/* What is the name of the library to fuzz */ +#define TARGET_LIBRARY "libtestinstr.so" + +/* What is the name of the function to fuzz */ +#define TARGET_FUNCTION "testinstr" + +/* here you need to specify the parameter for the target function */ +static void *(*o_function)(uint8_t *, int); + +// END STEP 1 + +#include "frida-gum.h" + +G_BEGIN_DECLS + +#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type()) +G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM, + FAKE_EVENT_SINK, GObject) + +struct _GumFakeEventSink { + + GObject parent; + GumEventType mask; + +}; + +GumEventSink *gum_fake_event_sink_new(void); +void gum_fake_event_sink_reset(GumFakeEventSink *self); + +G_END_DECLS + +static void gum_fake_event_sink_iface_init(gpointer g_iface, + gpointer iface_data); +static void gum_fake_event_sink_finalize(GObject *obj); +static GumEventType gum_fake_event_sink_query_mask(GumEventSink *sink); +static void gum_fake_event_sink_process(GumEventSink *sink, const GumEvent *ev); +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data); +void afl_setup(void); +void afl_start_forkserver(void); +int __afl_persistent_loop(unsigned int max_cnt); + +static void gum_fake_event_sink_class_init(GumFakeEventSinkClass *klass) { + + GObjectClass *object_class = G_OBJECT_CLASS(klass); + object_class->finalize = gum_fake_event_sink_finalize; + +} + +static void gum_fake_event_sink_iface_init(gpointer g_iface, + gpointer iface_data) { + + GumEventSinkInterface *iface = (GumEventSinkInterface *)g_iface; + iface->query_mask = gum_fake_event_sink_query_mask; + iface->process = gum_fake_event_sink_process; + +} + +G_DEFINE_TYPE_EXTENDED(GumFakeEventSink, gum_fake_event_sink, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE(GUM_TYPE_EVENT_SINK, + gum_fake_event_sink_iface_init)) + +#include "../../config.h" + +// Shared memory fuzzing. +int __afl_sharedmem_fuzzing = 1; +extern unsigned int * __afl_fuzz_len; +extern unsigned char *__afl_fuzz_ptr; + +// Notify AFL about persistent mode. +static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; +int __afl_persistent_loop(unsigned int); + +// Notify AFL about deferred forkserver. +static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; +void __afl_manual_init(); + +// Because we do our own logging. +extern uint8_t * __afl_area_ptr; +static __thread guint64 previous_pc; + +// Frida stuff below. +typedef struct { + + GumAddress base_address; + guint64 code_start, code_end; + +} range_t; + +inline static void afl_maybe_log(guint64 current_pc) { + + // fprintf(stderr, "PC: %p ^ %p\n", current_pc, previous_pc); + + current_pc = (current_pc >> 4) ^ (current_pc << 8); + current_pc &= MAP_SIZE - 1; + + __afl_area_ptr[current_pc ^ previous_pc]++; + previous_pc = current_pc >> 1; + +} + +static void on_basic_block(GumCpuContext *context, gpointer user_data) { + + afl_maybe_log((guint64)user_data); + +} + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data) { + + range_t *range = (range_t *)user_data; + + const cs_insn *instr; + gboolean begin = TRUE; + while (gum_stalker_iterator_next(iterator, &instr)) { + + if (begin) { + + if (instr->address >= range->code_start && + instr->address <= range->code_end) { + + gum_stalker_iterator_put_callout(iterator, on_basic_block, + (gpointer)instr->address, NULL); + begin = FALSE; + + } + + } + + gum_stalker_iterator_keep(iterator); + + } + +} + +static void gum_fake_event_sink_init(GumFakeEventSink *self) { + +} + +static void gum_fake_event_sink_finalize(GObject *obj) { + + G_OBJECT_CLASS(gum_fake_event_sink_parent_class)->finalize(obj); + +} + +GumEventSink *gum_fake_event_sink_new(void) { + + GumFakeEventSink *sink; + sink = (GumFakeEventSink *)g_object_new(GUM_TYPE_FAKE_EVENT_SINK, NULL); + return GUM_EVENT_SINK(sink); + +} + +void gum_fake_event_sink_reset(GumFakeEventSink *self) { + +} + +static GumEventType gum_fake_event_sink_query_mask(GumEventSink *sink) { + + return 0; + +} + +typedef struct library_list { + + uint8_t *name; + uint64_t addr_start, addr_end; + +} library_list_t; + +#define MAX_LIB_COUNT 256 +static library_list_t liblist[MAX_LIB_COUNT]; +static u32 liblist_cnt; + +void read_library_information() { + +#if defined(__linux__) + FILE *f; + u8 buf[1024], *b, *m, *e, *n; + + if ((f = fopen("/proc/self/maps", "r")) == NULL) { + + fprintf(stderr, "Error: cannot open /proc/self/maps\n"); + exit(-1); + + } + + if (debug) fprintf(stderr, "Library list:\n"); + while (fgets(buf, sizeof(buf), f)) { + + if (strstr(buf, " r-x")) { + + if (liblist_cnt >= MAX_LIB_COUNT) { + + fprintf( + stderr, + "Warning: too many libraries to old, maximum count of %d reached\n", + liblist_cnt); + return; + + } + + b = buf; + m = index(buf, '-'); + e = index(buf, ' '); + if ((n = rindex(buf, '/')) == NULL) n = rindex(buf, ' '); + if (n && + ((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '(')) + n = NULL; + else + n++; + if (b && m && e && n && *n) { + + *m++ = 0; + *e = 0; + if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0; + + if (rindex(n, '/') != NULL) { + + n = rindex(n, '/'); + n++; + + } + + liblist[liblist_cnt].name = strdup(n); + liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16); + liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16); + if (debug) + fprintf( + stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name, + liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, + liblist[liblist_cnt].addr_start, + liblist[liblist_cnt].addr_end - 1); + liblist_cnt++; + + } + + } + + } + + if (debug) fprintf(stderr, "\n"); + +#elif defined(__FreeBSD__) + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; + char * buf, *start, *end; + size_t miblen = sizeof(mib) / sizeof(mib[0]); + size_t len; + + if (debug) fprintf(stderr, "Library list:\n"); + if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; } + + len = len * 4 / 3; + + buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); + if (buf == MAP_FAILED) { return; } + if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) { + + munmap(buf, len); + return; + + } + + start = buf; + end = buf + len; + + while (start < end) { + + struct kinfo_vmentry *region = (struct kinfo_vmentry *)start; + size_t size = region->kve_structsize; + + if (size == 0) { break; } + + if ((region->kve_protection & KVME_PROT_READ) && + !(region->kve_protection & KVME_PROT_EXEC)) { + + liblist[liblist_cnt].name = + region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0; + liblist[liblist_cnt].addr_start = region->kve_start; + liblist[liblist_cnt].addr_end = region->kve_end; + + if (debug) { + + fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name, + liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, + liblist[liblist_cnt].addr_start, + liblist[liblist_cnt].addr_end - 1); + + } + + liblist_cnt++; + + } + + start += size; + + } + +#endif + +} + +library_list_t *find_library(char *name) { + + char *filename = rindex(name, '/'); + + if (filename) + filename++; + else + filename = name; + +#if defined(__linux__) + u32 i; + for (i = 0; i < liblist_cnt; i++) + if (strcmp(liblist[i].name, filename) == 0) return &liblist[i]; +#elif defined(__APPLE__) && defined(__LP64__) + kern_return_t err; + static library_list_t lib; + + // get the list of all loaded modules from dyld + // the task_info mach API will get the address of the dyld all_image_info + // struct for the given task from which we can get the names and load + // addresses of all modules + task_dyld_info_data_t task_dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + err = task_info(mach_task_self(), TASK_DYLD_INFO, + (task_info_t)&task_dyld_info, &count); + + const struct dyld_all_image_infos *all_image_infos = + (const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr; + const struct dyld_image_info *image_infos = all_image_infos->infoArray; + + for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) { + + const char * image_name = image_infos[i].imageFilePath; + mach_vm_address_t image_load_address = + (mach_vm_address_t)image_infos[i].imageLoadAddress; + if (strstr(image_name, name)) { + + lib.name = name; + lib.addr_start = (u64)image_load_address; + lib.addr_end = 0; + return &lib; + + } + + } + +#endif + + return NULL; + +} + +static void gum_fake_event_sink_process(GumEventSink * sink, + const GumEvent *ev) { + +} + +/* Because this CAN be called more than once, it will return the LAST range */ +static int enumerate_ranges(const GumRangeDetails *details, + gpointer user_data) { + + GumMemoryRange *code_range = (GumMemoryRange *)user_data; + memcpy(code_range, details->range, sizeof(*code_range)); + return 0; + +} + +int main() { + +#ifndef __APPLE__ + (void)personality(ADDR_NO_RANDOMIZE); // disable ASLR +#endif + + // STEP 2: load the library you want to fuzz and lookup the functions, + // inclusive of the cleanup functions. + // If there is just one function, then there is nothing to change + // or add here. + + void *dl = dlopen(TARGET_LIBRARY, RTLD_LAZY); + if (!dl) { + + fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY); + exit(-1); + + } + + if (!(o_function = dlsym(dl, TARGET_FUNCTION))) { + + fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION); + exit(-1); + + } + + // END STEP 2 + + read_library_information(); + library_list_t *lib = find_library(TARGET_LIBRARY); + + if (lib == NULL) { + + fprintf(stderr, "Could not find target library\n"); + exit(-1); + + } + + gum_init_embedded(); + if (!gum_stalker_is_supported()) { + + gum_deinit_embedded(); + return 1; + + } + + GumStalker *stalker = gum_stalker_new(); + + /* + This does not work here as we load a shared library. pretty sure this + would also be easily solvable with frida gum, but I already have all the + code I need from afl-untracer + + GumAddress base_address = gum_module_find_base_address(TARGET_LIBRARY); + GumMemoryRange code_range; + gum_module_enumerate_ranges(TARGET_LIBRARY, GUM_PAGE_RX, enumerate_ranges, + &code_range); + guint64 code_start = code_range.base_address - base_address; + guint64 code_end = (code_range.base_address + code_range.size) - base_address; + range_t instr_range = {base_address, code_start, code_end}; + */ + range_t instr_range = {0, lib->addr_start, lib->addr_end}; + + GumStalkerTransformer *transformer = + gum_stalker_transformer_make_from_callback(instr_basic_block, + &instr_range, NULL); + + GumEventSink *event_sink = gum_fake_event_sink_new(); + + // to ensure that the signatures are not optimized out + memcpy(__afl_area_ptr, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT) + 1); + memcpy(__afl_area_ptr + 32, (void *)AFL_DEFER_FORKSVR, + sizeof(AFL_DEFER_FORKSVR) + 1); + __afl_manual_init(); + + // + // any expensive target library initialization that has to be done just once + // - put that here + // + + gum_stalker_follow_me(stalker, transformer, event_sink); + + while (__afl_persistent_loop(UINT32_MAX) != 0) { + + previous_pc = 0; // Required! + +#ifdef _DEBUG + fprintf(stderr, "CLIENT crc: %016llx len: %u\n", + hash64(__afl_fuzz_ptr, *__afl_fuzz_len), *__afl_fuzz_len); + fprintf(stderr, "RECV:"); + for (int i = 0; i < *__afl_fuzz_len; i++) + fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); + fprintf(stderr, "\n"); +#endif + + // STEP 3: ensure the minimum length is present and setup the target + // function to fuzz. + + if (*__afl_fuzz_len > 0) { + + __afl_fuzz_ptr[*__afl_fuzz_len] = 0; // if you need to null terminate + (*o_function)(__afl_fuzz_ptr, *__afl_fuzz_len); + + } + + // END STEP 3 + + } + + gum_stalker_unfollow_me(stalker); + + while (gum_stalker_garbage_collect(stalker)) + g_usleep(10000); + + g_object_unref(stalker); + g_object_unref(transformer); + g_object_unref(event_sink); + gum_deinit_embedded(); + + return 0; + +} + diff --git a/utils/afl_frida/afl-frida.h b/utils/afl_frida/afl-frida.h new file mode 100644 index 00000000..efa3440f --- /dev/null +++ b/utils/afl_frida/afl-frida.h @@ -0,0 +1,53 @@ +extern int is_persistent; + +G_BEGIN_DECLS + +#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type()) + +G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM, + FAKE_EVENT_SINK, GObject) + +struct _GumFakeEventSink { + + GObject parent; + GumEventType mask; + +}; + +GumEventSink *gum_fake_event_sink_new(void); +void gum_fake_event_sink_reset(GumFakeEventSink *self); + +G_END_DECLS + +typedef struct { + + GumAddress base_address; + guint64 code_start, code_end; + +} range_t; + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data); +#pragma once + +void afl_setup(void); +void afl_start_forkserver(void); +int __afl_persistent_loop(unsigned int max_cnt); + +inline static inline void afl_maybe_log(guint64 current_pc) { + + extern unsigned int afl_instr_rms; + extern uint8_t * afl_area_ptr; + + static __thread guint64 previous_pc; + + current_pc = (current_pc >> 4) ^ (current_pc << 8); + current_pc &= MAP_SIZE - 1; + + if (current_pc >= afl_instr_rms) return; + + afl_area_ptr[current_pc ^ previous_pc]++; + previous_pc = current_pc >> 1; + +} + diff --git a/utils/afl_frida/libtestinstr.c b/utils/afl_frida/libtestinstr.c new file mode 100644 index 00000000..96b1cf21 --- /dev/null +++ b/utils/afl_frida/libtestinstr.c @@ -0,0 +1,35 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + diff --git a/utils/afl_network_proxy/GNUmakefile b/utils/afl_network_proxy/GNUmakefile new file mode 100644 index 00000000..25a3df82 --- /dev/null +++ b/utils/afl_network_proxy/GNUmakefile @@ -0,0 +1,43 @@ +PREFIX ?= /usr/local +BIN_PATH = $(PREFIX)/bin +DOC_PATH = $(PREFIX)/share/doc/afl + +PROGRAMS = afl-network-client afl-network-server + +HASH=\# + +CFLAGS += -Wno-pointer-sign + +ifdef STATIC + CFLAGS += -static +endif + +ifeq "$(shell echo '$(HASH)include @int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" + CFLAGS += -DUSE_DEFLATE=1 + LDFLAGS += -ldeflate + $(info libdeflate-dev was detected, using compression) +else + $(warn did not find libdeflate-dev, cannot use compression) +endif + +all: $(PROGRAMS) + +help: + @echo make options: + @echo STATIC - build as static binaries + @echo COMPRESS_TESTCASES - compress test cases + +afl-network-client: afl-network-client.c + $(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c $(LDFLAGS) + +afl-network-server: afl-network-server.c + $(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" $(LDFLAGS) + +clean: + rm -f $(PROGRAMS) *~ core + +install: all + install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(DOC_PATH) + install -m 755 $(PROGRAMS) $${DESTDIR}$(BIN_PATH) + install -T -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md + diff --git a/utils/afl_network_proxy/Makefile b/utils/afl_network_proxy/Makefile new file mode 100644 index 00000000..0b306dde --- /dev/null +++ b/utils/afl_network_proxy/Makefile @@ -0,0 +1,2 @@ +all: + @echo please use GNU make, thanks! diff --git a/utils/afl_network_proxy/README.md b/utils/afl_network_proxy/README.md new file mode 100644 index 00000000..a5ac3578 --- /dev/null +++ b/utils/afl_network_proxy/README.md @@ -0,0 +1,61 @@ +# afl-network-proxy + +If you want to run afl-fuzz over the network than this is what you need :) +Note that the impact on fuzzing speed will be huge, expect a loss of 90%. + +## When to use this + +1. when you have to fuzz a target that has to run on a system that cannot + contain the fuzzing output (e.g. /tmp too small and file system is read-only) +2. when the target instantly reboots on crashes +3. ... any other reason you would need this + +## how to get it running + +### Compiling + +Just type `make` and let the autodetection do everything for you. + +Note that you will get a 40-50% performance increase if you have libdeflate-dev +installed. The GNUmakefile will autodetect it if present. + +If your target has large test cases (10+kb) that are ascii only or large chunks +of zero blocks then set `CFLAGS=-DCOMPRESS_TESTCASES=1` to compress them. +For most targets this hurts performance though so it is disabled by default. + +### on the target + +Run `afl-network-server` with your target with the -m and -t values you need. +Important is the -i parameter which is the TCP port to listen on. +e.g.: +``` +afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@ +``` + +### on the (afl-fuzz) master + +Just run afl-fuzz with your normal options, however the target should be +`afl-network-client` with the IP and PORT of the `afl-network-server` and +increase the -t value: +``` +afl-fuzz -i in -o out -t 2000+ -- afl-network-client TARGET-IP 1111 +``` +Note the '+' on the -t parameter value. The afl-network-server will take +care of proper timeouts hence afl-fuzz should not. The '+' increases the +timeout and the value itself should be 500-1000 higher than the one on +afl-network-server. + +### networking + +The TARGET can be an IPv4 or IPv6 address, or a host name that resolves to +either. Note that also the outgoing interface can be specified with a '%' for +`afl-network-client`, e.g. `fe80::1234%eth0`. + +Also make sure your default TCP window size is larger than your MAP_SIZE +(130kb is a good value). +On Linux that is the middle value of `/proc/sys/net/ipv4/tcp_rmem` + +## how to compile and install + +`make && sudo make install` + diff --git a/utils/afl_network_proxy/afl-network-client.c b/utils/afl_network_proxy/afl-network-client.c new file mode 100644 index 00000000..a2451fdc --- /dev/null +++ b/utils/afl_network_proxy/afl-network-client.c @@ -0,0 +1,415 @@ +/* + american fuzzy lop++ - afl-network-client + --------------------------------------- + + Written by Marc Heuse + + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + +*/ + +#ifdef __ANDROID__ + #include "android-ashmem.h" +#endif +#include "config.h" +#include "types.h" +#include "debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifndef USEMMAP + #include +#endif +#include +#include +#include +#include +#include + +#ifdef USE_DEFLATE + #include +#endif + +u8 *__afl_area_ptr; + +#ifdef __ANDROID__ +u32 __afl_map_size = MAP_SIZE; +#else +__thread u32 __afl_map_size = MAP_SIZE; +#endif + +/* Error reporting to forkserver controller */ + +void send_forkserver_error(int error) { + + u32 status; + if (!error || error > 0xffff) return; + status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); + if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; + +} + +/* SHM setup. */ + +static void __afl_map_shm(void) { + + char *id_str = getenv(SHM_ENV_VAR); + char *ptr; + + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { + + u32 val = atoi(ptr); + if (val > 0) __afl_map_size = val; + + } + + if (__afl_map_size > MAP_SIZE) { + + if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { + + fprintf(stderr, + "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + if (id_str) { + + send_forkserver_error(FS_ERROR_MAP_SIZE); + exit(-1); + + } + + } else { + + fprintf(stderr, + "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + + } + + } + + if (id_str) { + +#ifdef USEMMAP + const char * shm_file_path = id_str; + int shm_fd = -1; + unsigned char *shm_base = NULL; + + /* create the shared memory segment as if it was a file */ + shm_fd = shm_open(shm_file_path, O_RDWR, 0600); + if (shm_fd == -1) { + + fprintf(stderr, "shm_open() failed\n"); + send_forkserver_error(FS_ERROR_SHM_OPEN); + exit(1); + + } + + /* map the shared memory segment to the address space of the process */ + shm_base = + mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + + if (shm_base == MAP_FAILED) { + + close(shm_fd); + shm_fd = -1; + + fprintf(stderr, "mmap() failed\n"); + send_forkserver_error(FS_ERROR_MMAP); + exit(2); + + } + + __afl_area_ptr = shm_base; +#else + u32 shm_id = atoi(id_str); + + __afl_area_ptr = shmat(shm_id, 0, 0); + +#endif + + if (__afl_area_ptr == (void *)-1) { + + send_forkserver_error(FS_ERROR_SHMAT); + exit(1); + + } + + /* Write something into the bitmap so that the parent doesn't give up */ + + __afl_area_ptr[0] = 1; + + } + +} + +/* Fork server logic. */ + +static void __afl_start_forkserver(void) { + + u8 tmp[4] = {0, 0, 0, 0}; + u32 status = 0; + + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) + status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); + if (status) status |= (FS_OPT_ENABLED); + memcpy(tmp, &status, 4); + + /* Phone home and tell the parent that we're OK. */ + + if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + +} + +static u32 __afl_next_testcase(u8 *buf, u32 max_len) { + + s32 status, res = 0x0fffffff; // res is a dummy pid + + /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (read(FORKSRV_FD, &status, 4) != 4) return 0; + + /* we have a testcase - read it */ + status = read(0, buf, max_len); + + /* report that we are starting the target */ + if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; + + if (status < 1) + return 0; + else + return status; + +} + +static void __afl_end_testcase(int status) { + + if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); + +} + +/* you just need to modify the while() loop in this main() */ + +int main(int argc, char *argv[]) { + + u8 * interface, *buf, *ptr; + s32 s = -1; + struct addrinfo hints, *hres, *aip; + u32 * lenptr, max_len = 65536; +#ifdef USE_DEFLATE + u8 * buf2; + u32 * lenptr1, *lenptr2, buf2_len, compress_len; + size_t decompress_len; +#endif + + if (argc < 3 || argc > 4) { + + printf("Syntax: %s host port [max-input-size]\n\n", argv[0]); + printf("Requires host and port of the remote afl-proxy-server instance.\n"); + printf( + "IPv4 and IPv6 are supported, also binding to an interface with " + "\"%%\"\n"); + printf("The max-input-size default is %u.\n", max_len); + printf( + "The default map size is %u and can be changed with setting " + "AFL_MAP_SIZE.\n", + __afl_map_size); + exit(-1); + + } + + if ((interface = strchr(argv[1], '%')) != NULL) *interface++ = 0; + + if (argc > 3) + if ((max_len = atoi(argv[3])) < 0) + FATAL("max-input-size may not be negative or larger than 2GB: %s", + argv[3]); + + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) + if ((__afl_map_size = atoi(ptr)) < 8) + FATAL("illegal map size, may not be < 8 or >= 2^30: %s", ptr); + + if ((buf = malloc(max_len + 4)) == NULL) + PFATAL("can not allocate %u memory", max_len + 4); + lenptr = (u32 *)buf; + +#ifdef USE_DEFLATE + buf2_len = (max_len > __afl_map_size ? max_len : __afl_map_size); + if ((buf2 = malloc(buf2_len + 8)) == NULL) + PFATAL("can not allocate %u memory", buf2_len + 8); + lenptr1 = (u32 *)buf2; + lenptr2 = (u32 *)(buf2 + 4); +#endif + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + + if (getaddrinfo(argv[1], argv[2], &hints, &hres) != 0) + PFATAL("could not resolve target %s", argv[1]); + + for (aip = hres; aip != NULL && s == -1; aip = aip->ai_next) { + + if ((s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) >= 0) { + +#ifdef SO_BINDTODEVICE + if (interface != NULL) + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface, + strlen(interface) + 1) < 0) + fprintf(stderr, "Warning: could not bind to device %s\n", interface); +#else + fprintf(stderr, + "Warning: binding to interface is not supported for your OS\n"); +#endif + +#ifdef SO_PRIORITY + int priority = 7; + if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < + 0) { + + priority = 6; + if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, + sizeof(priority)) < 0) + WARNF("could not set priority on socket"); + + } + +#endif + + if (connect(s, aip->ai_addr, aip->ai_addrlen) == -1) s = -1; + + } + + } + +#ifdef USE_DEFLATE + struct libdeflate_compressor *compressor; + compressor = libdeflate_alloc_compressor(1); + struct libdeflate_decompressor *decompressor; + decompressor = libdeflate_alloc_decompressor(); + fprintf(stderr, "Compiled with compression support\n"); +#endif + + if (s == -1) + FATAL("could not connect to target tcp://%s:%s", argv[1], argv[2]); + else + fprintf(stderr, "Connected to target tcp://%s:%s\n", argv[1], argv[2]); + + /* we initialize the shared memory map and start the forkserver */ + __afl_map_shm(); + __afl_start_forkserver(); + + int i = 1, j, status, ret, received; + + // fprintf(stderr, "Waiting for first testcase\n"); + while ((*lenptr = __afl_next_testcase(buf + 4, max_len)) > 0) { + + // fprintf(stderr, "Sending testcase with len %u\n", *lenptr); +#ifdef USE_DEFLATE + #ifdef COMPRESS_TESTCASES + // we only compress the testcase if it does not fit in the TCP packet + if (*lenptr > 1500 - 20 - 32 - 4) { + + // set highest byte to signify compression + *lenptr1 = (*lenptr | 0xff000000); + *lenptr2 = (u32)libdeflate_deflate_compress(compressor, buf + 4, *lenptr, + buf2 + 8, buf2_len); + if (send(s, buf2, *lenptr2 + 8, 0) != *lenptr2 + 8) + PFATAL("sending test data failed"); + // fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2); + // for (u32 i = 0; i < *lenptr; i++) + // fprintf(stderr, "%02x", buf[i + 4]); + // fprintf(stderr, "\n"); + // for (u32 i = 0; i < *lenptr2; i++) + // fprintf(stderr, "%02x", buf2[i + 8]); + // fprintf(stderr, "\n"); + + } else { + + #endif +#endif + if (send(s, buf, *lenptr + 4, 0) != *lenptr + 4) + PFATAL("sending test data failed"); +#ifdef USE_DEFLATE + #ifdef COMPRESS_TESTCASES + // fprintf(stderr, "unCOMPRESS (%u)\n", *lenptr); + + } + + #endif +#endif + + received = 0; + while (received < 4 && + (ret = recv(s, &status + received, 4 - received, 0)) > 0) + received += ret; + if (received != 4) + FATAL("did not receive waitpid data (%d, %d)", received, ret); + // fprintf(stderr, "Received status\n"); + + received = 0; +#ifdef USE_DEFLATE + while (received < 4 && + (ret = recv(s, &compress_len + received, 4 - received, 0)) > 0) + received += ret; + if (received != 4) + FATAL("did not receive compress_len (%d, %d)", received, ret); + // fprintf(stderr, "Received status\n"); + + received = 0; + while (received < compress_len && + (ret = recv(s, buf2 + received, buf2_len - received, 0)) > 0) + received += ret; + if (received != compress_len) + FATAL("did not receive coverage data (%d, %d)", received, ret); + + if (libdeflate_deflate_decompress(decompressor, buf2, compress_len, + __afl_area_ptr, __afl_map_size, + &decompress_len) != LIBDEFLATE_SUCCESS || + decompress_len != __afl_map_size) + FATAL("decompression failed"); + // fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len); + // for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x", + // __afl_area_ptr[i]); fprintf(stderr, "\n"); +#else + while (received < __afl_map_size && + (ret = recv(s, __afl_area_ptr + received, __afl_map_size - received, + 0)) > 0) + received += ret; + if (received != __afl_map_size) + FATAL("did not receive coverage data (%d, %d)", received, ret); +#endif + // fprintf(stderr, "Received coverage\n"); + + /* report the test case is done and wait for the next */ + __afl_end_testcase(status); + // fprintf(stderr, "Waiting for next testcase %d\n", ++i); + + } + +#ifdef USE_DEFLATE + libdeflate_free_compressor(compressor); + libdeflate_free_decompressor(decompressor); +#endif + + return 0; + +} + diff --git a/utils/afl_network_proxy/afl-network-server.c b/utils/afl_network_proxy/afl-network-server.c new file mode 100644 index 00000000..513dc8f2 --- /dev/null +++ b/utils/afl_network_proxy/afl-network-server.c @@ -0,0 +1,720 @@ +/* + american fuzzy lop++ - network proxy server + ------------------------------------------- + + Originally written by Michal Zalewski + + Forkserver design by Jann Horn + + Now maintained by Marc Heuse , + Heiko Eißfeldt and + Andrea Fioraldi and + Dominik Maier + + Copyright 2016, 2017 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + */ + +#define AFL_MAIN + +#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 "common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_DEFLATE + #include +struct libdeflate_compressor * compressor; +struct libdeflate_decompressor *decompressor; +#endif + +static u8 *in_file, /* Minimizer input test case */ + *out_file; + +static u8 *in_data; /* Input data for trimming */ +static u8 *buf2; + +static s32 in_len; +static s32 buf2_len; +static u32 map_size = MAP_SIZE; + +static volatile u8 stop_soon; /* Ctrl-C pressed? */ + +/* See if any bytes are set in the bitmap. */ + +static inline u8 anything_set(afl_forkserver_t *fsrv) { + + u32 *ptr = (u32 *)fsrv->trace_bits; + u32 i = (map_size >> 2); + + while (i--) { + + if (*(ptr++)) { return 1; } + + } + + return 0; + +} + +static void at_exit_handler(void) { + + afl_fsrv_killall(); + +} + +/* Write output file. */ + +static s32 write_to_file(u8 *path, u8 *mem, u32 len) { + + s32 ret; + + unlink(path); /* Ignore errors */ + + ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600); + + if (ret < 0) { PFATAL("Unable to create '%s'", path); } + + ck_write(ret, mem, len, path); + + lseek(ret, 0, SEEK_SET); + + return ret; + +} + +/* Execute target application. Returns 0 if the changes are a dud, or + 1 if they should be kept. */ + +static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, + u8 first_run) { + + afl_fsrv_write_to_testcase(fsrv, mem, len); + + fsrv_run_result_t ret = + afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon); + + if (ret == FSRV_RUN_ERROR) { FATAL("Couldn't run child"); } + + if (stop_soon) { + + SAYF(cRST cLRD "\n+++ aborted by user +++\n" cRST); + exit(1); + + } + + return ret; + +} + +/* Handle Ctrl-C and the like. */ + +static void handle_stop_sig(int sig) { + + stop_soon = 1; + afl_fsrv_killall(); + +} + +/* Do basic preparations - persistent fds, filenames, etc. */ + +static void set_up_environment(afl_forkserver_t *fsrv) { + + u8 *x; + + fsrv->dev_null_fd = open("/dev/null", O_RDWR); + if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } + + if (!out_file) { + + u8 *use_dir = "."; + + if (access(use_dir, R_OK | W_OK | X_OK)) { + + use_dir = get_afl_env("TMPDIR"); + if (!use_dir) { use_dir = "/tmp"; } + + } + + out_file = alloc_printf("%s/.afl-input-temp-%u", use_dir, getpid()); + + } + + unlink(out_file); + + fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600); + + if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); } + + /* Set sane defaults... */ + + x = get_afl_env("ASAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "abort_on_error=1")) { + + FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); + + } + + if (!strstr(x, "symbolize=0")) { + + FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!"); + + } + + } + + x = get_afl_env("MSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) { + + FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY( + MSAN_ERROR) " - please fix!"); + + } + + if (!strstr(x, "symbolize=0")) { + + FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); + + } + + } + + setenv("ASAN_OPTIONS", + "abort_on_error=1:" + "detect_leaks=0:" + "symbolize=0:" + "allocator_may_return_null=1", + 0); + + setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" + "abort_on_error=1:" + "allocator_may_return_null=1:" + "msan_track_origins=0", 0); + + if (get_afl_env("AFL_PRELOAD")) { + + if (fsrv->qemu_mode) { + + u8 *qemu_preload = getenv("QEMU_SET_ENV"); + u8 *afl_preload = getenv("AFL_PRELOAD"); + u8 *buf; + + s32 i, afl_preload_size = strlen(afl_preload); + for (i = 0; i < afl_preload_size; ++i) { + + if (afl_preload[i] == ',') { + + PFATAL( + "Comma (',') is not allowed in AFL_PRELOAD when -Q is " + "specified!"); + + } + + } + + if (qemu_preload) { + + buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s", + qemu_preload, afl_preload, afl_preload); + + } else { + + buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s", + afl_preload, afl_preload); + + } + + setenv("QEMU_SET_ENV", buf, 1); + + afl_free(buf); + + } else { + + setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); + setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); + + } + + } + +} + +/* Setup signal handlers, duh. */ + +static void setup_signal_handlers(void) { + + struct sigaction sa; + + sa.sa_handler = NULL; + sa.sa_flags = SA_RESTART; + sa.sa_sigaction = NULL; + + sigemptyset(&sa.sa_mask); + + /* Various ways of saying "stop". */ + + sa.sa_handler = handle_stop_sig; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + +} + +/* Display usage hints. */ + +static void usage(u8 *argv0) { + + SAYF( + "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" + + "Required parameters:\n" + + " -i port - the port to listen for the client to connect to\n\n" + + "Execution control settings:\n" + + " -f file - input file read by the tested program (stdin)\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" + " -W - use qemu-based instrumentation with Wine (Wine " + "mode)\n\n" + + "Environment variables used:\n" + "TMPDIR: directory to use for temporary input files\n" + "ASAN_OPTIONS: custom settings for ASAN\n" + " (must contain abort_on_error=1 and symbolize=0)\n" + "MSAN_OPTIONS: custom settings for MSAN\n" + " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" + "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" + " the target was compiled for\n" + "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" + + , argv0, EXEC_TIMEOUT, MEM_LIMIT); + + exit(1); + +} + +int recv_testcase(int s, void **buf) { + + u32 size; + s32 ret; + size_t received; + + received = 0; + while (received < 4 && (ret = recv(s, &size + received, 4 - received, 0)) > 0) + received += ret; + if (received != 4) FATAL("did not receive size information"); + if (size == 0) FATAL("did not receive valid size information"); + // fprintf(stderr, "received size information of %d\n", size); + + if ((size & 0xff000000) != 0xff000000) { + + *buf = afl_realloc(buf, size); + if (unlikely(!*buf)) { PFATAL("Alloc"); } + received = 0; + // fprintf(stderr, "unCOMPRESS (%u)\n", size); + while (received < size && + (ret = recv(s, ((char *)*buf) + received, size - received, 0)) > 0) + received += ret; + + } else { + +#ifdef USE_DEFLATE + u32 clen; + size -= 0xff000000; + *buf = afl_realloc(buf, size); + if (unlikely(!*buf)) { PFATAL("Alloc"); } + received = 0; + while (received < 4 && + (ret = recv(s, &clen + received, 4 - received, 0)) > 0) + received += ret; + if (received != 4) FATAL("did not receive clen1 information"); + // fprintf(stderr, "received clen information of %d\n", clen); + if (clen < 1) + FATAL("did not receive valid compressed len information: %u", clen); + buf2 = afl_realloc((void **)&buf2, clen); + buf2_len = clen; + if (unlikely(!buf2)) { PFATAL("Alloc"); } + received = 0; + while (received < clen && + (ret = recv(s, buf2 + received, clen - received, 0)) > 0) + received += ret; + if (received != clen) FATAL("did not receive compressed information"); + if (libdeflate_deflate_decompress(decompressor, buf2, clen, (char *)*buf, + size, &received) != LIBDEFLATE_SUCCESS) + FATAL("decompression failed"); + // fprintf(stderr, "DECOMPRESS (%u->%u):\n", clen, received); + // for (u32 i = 0; i < clen; i++) fprintf(stderr, "%02x", buf2[i]); + // fprintf(stderr, "\n"); + // for (u32 i = 0; i < received; i++) fprintf(stderr, "%02x", + // ((u8*)(*buf))[i]); fprintf(stderr, "\n"); +#else + FATAL("Received compressed data but not compiled with compression support"); +#endif + + } + + // fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len); + if (received != size) + FATAL("did not receive testcase data %lu != %u, %d", received, size, ret); + // fprintf(stderr, "received testcase\n"); + return size; + +} + +/* Main entry point */ + +int main(int argc, char **argv_orig, char **envp) { + + s32 opt, s, sock, on = 1, port = -1; + u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; + char **use_argv; + struct sockaddr_in6 serveraddr, clientaddr; + int addrlen = sizeof(clientaddr); + char str[INET6_ADDRSTRLEN]; + char ** argv = argv_cpy_dup(argc, argv_orig); + u8 * send_buf; +#ifdef USE_DEFLATE + u32 *lenptr; +#endif + + afl_forkserver_t fsrv_var = {0}; + afl_forkserver_t *fsrv = &fsrv_var; + afl_fsrv_init(fsrv); + map_size = get_map_size(); + fsrv->map_size = map_size; + + if ((send_buf = malloc(map_size + 4)) == NULL) PFATAL("malloc"); + + while ((opt = getopt(argc, argv, "+i:f:m:t:QUWh")) > 0) { + + switch (opt) { + + case 'i': + + if (port > 0) { FATAL("Multiple -i options not supported"); } + port = atoi(optarg); + if (port < 1 || port > 65535) + FATAL("invalid port definition, must be between 1-65535: %s", optarg); + break; + + case 'f': + + if (out_file) { FATAL("Multiple -f options not supported"); } + fsrv->use_stdin = 0; + out_file = optarg; + break; + + case 'm': { + + u8 suffix = 'M'; + + if (mem_limit_given) { FATAL("Multiple -m options not supported"); } + mem_limit_given = 1; + + if (!optarg) { FATAL("Wrong usage of -m"); } + + if (!strcmp(optarg, "none")) { + + fsrv->mem_limit = 0; + break; + + } + + if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 || + optarg[0] == '-') { + + FATAL("Bad syntax used for -m"); + + } + + switch (suffix) { + + case 'T': + fsrv->mem_limit *= 1024 * 1024; + break; + case 'G': + fsrv->mem_limit *= 1024; + break; + case 'k': + fsrv->mem_limit /= 1024; + break; + case 'M': + break; + + default: + FATAL("Unsupported suffix or bad syntax for -m"); + + } + + if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); } + + if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) { + + FATAL("Value of -m out of range on 32-bit systems"); + + } + + } + + break; + + case 't': + + if (timeout_given) { FATAL("Multiple -t options not supported"); } + timeout_given = 1; + + if (!optarg) { FATAL("Wrong usage of -t"); } + + fsrv->exec_tmout = atoi(optarg); + + if (fsrv->exec_tmout < 10 || optarg[0] == '-') { + + FATAL("Dangerously low value of -t"); + + } + + break; + + case 'Q': + + if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } + if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; } + + fsrv->qemu_mode = 1; + break; + + case 'U': + + if (unicorn_mode) { FATAL("Multiple -Q options not supported"); } + if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; } + + unicorn_mode = 1; + break; + + case 'W': /* Wine+QEMU mode */ + + if (use_wine) { FATAL("Multiple -W options not supported"); } + fsrv->qemu_mode = 1; + use_wine = 1; + + if (!mem_limit_given) { fsrv->mem_limit = 0; } + + break; + + case 'h': + usage(argv[0]); + return -1; + break; + + default: + usage(argv[0]); + + } + + } + + if (optind == argc || port < 1) { usage(argv[0]); } + + check_environment_vars(envp); + + sharedmem_t shm = {0}; + fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); + + in_data = afl_realloc((void **)&in_data, 65536); + if (unlikely(!in_data)) { PFATAL("Alloc"); } + + atexit(at_exit_handler); + setup_signal_handlers(); + + set_up_environment(fsrv); + + fsrv->target_path = find_binary(argv[optind]); + detect_file_args(argv + optind, out_file, &fsrv->use_stdin); + + if (fsrv->qemu_mode) { + + if (use_wine) { + + use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind, + argv + optind); + + } else { + + use_argv = get_qemu_argv(argv[0], &fsrv->target_path, argc - optind, + argv + optind); + + } + + } else { + + use_argv = argv + optind; + + } + + if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) PFATAL("socket() failed"); + +#ifdef SO_REUSEADDR + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) { + + WARNF("setsockopt(SO_REUSEADDR) failed"); + + } + +#endif + +#ifdef SO_PRIORITY + int priority = 7; + if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < + 0) { + + priority = 6; + if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < + 0) + WARNF("could not set priority on socket"); + + } + +#endif + + memset(&serveraddr, 0, sizeof(serveraddr)); + serveraddr.sin6_family = AF_INET6; + serveraddr.sin6_port = htons(port); + serveraddr.sin6_addr = in6addr_any; + + if (bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) + PFATAL("bind() failed"); + + if (listen(sock, 1) < 0) { PFATAL("listen() failed"); } + + afl_fsrv_start( + fsrv, use_argv, &stop_soon, + (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) + ? 1 + : 0); + +#ifdef USE_DEFLATE + compressor = libdeflate_alloc_compressor(1); + decompressor = libdeflate_alloc_decompressor(); + buf2 = afl_realloc((void **)&buf2, map_size + 16); + buf2_len = map_size + 16; + if (unlikely(!buf2)) { PFATAL("alloc"); } + lenptr = (u32 *)(buf2 + 4); + fprintf(stderr, "Compiled with compression support\n"); +#endif + + fprintf(stderr, + "Waiting for incoming connection from afl-network-client on port %d " + "...\n", + port); + + if ((s = accept(sock, NULL, NULL)) < 0) { PFATAL("accept() failed"); } + fprintf(stderr, "Received connection, starting ...\n"); + +#ifdef SO_PRIORITY + priority = 7; + if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) { + + priority = 6; + if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) + WARNF("could not set priority on socket"); + + } + +#endif + + while ((in_len = recv_testcase(s, (void **)&in_data)) > 0) { + + // fprintf(stderr, "received %u\n", in_len); + (void)run_target(fsrv, use_argv, in_data, in_len, 1); + + memcpy(send_buf + 4, fsrv->trace_bits, fsrv->map_size); + +#ifdef USE_DEFLATE + memcpy(buf2, &fsrv->child_status, 4); + *lenptr = (u32)libdeflate_deflate_compress( + compressor, send_buf + 4, fsrv->map_size, buf2 + 8, buf2_len - 8); + // fprintf(stderr, "COMPRESS (%u->%u): ", fsrv->map_size, *lenptr); + // for (u32 i = 0; i < fsrv->map_size; i++) fprintf(stderr, "%02x", + // fsrv->trace_bits[i]); fprintf(stderr, "\n"); + if (send(s, buf2, *lenptr + 8, 0) != 8 + *lenptr) + FATAL("could not send data"); +#else + memcpy(send_buf, &fsrv->child_status, 4); + if (send(s, send_buf, fsrv->map_size + 4, 0) != 4 + fsrv->map_size) + FATAL("could not send data"); +#endif + + // fprintf(stderr, "sent result\n"); + + } + + unlink(out_file); + if (out_file) { ck_free(out_file); } + out_file = NULL; + + afl_shm_deinit(&shm); + afl_fsrv_deinit(fsrv); + if (fsrv->target_path) { ck_free(fsrv->target_path); } + afl_free(in_data); +#if USE_DEFLATE + afl_free(buf2); + libdeflate_free_compressor(compressor); + libdeflate_free_decompressor(decompressor); +#endif + + argv_cpy_free(argv); + + exit(0); + +} + diff --git a/utils/afl_proxy/Makefile b/utils/afl_proxy/Makefile new file mode 100644 index 00000000..4b368f8d --- /dev/null +++ b/utils/afl_proxy/Makefile @@ -0,0 +1,7 @@ +all: afl-proxy + +afl-proxy: afl-proxy.c + $(CC) -I../../include -o afl-proxy afl-proxy.c + +clean: + rm -f afl-proxy *~ core diff --git a/utils/afl_proxy/README.md b/utils/afl_proxy/README.md new file mode 100644 index 00000000..3c768a19 --- /dev/null +++ b/utils/afl_proxy/README.md @@ -0,0 +1,9 @@ +# afl-proxy + +afl-proxy is an example skeleton file which can easily be used to fuzz +and instrument non-standard things. + +You only need to change the while() loop of the main() to send the +data of buf[] with length len to the target and write the coverage +information to __afl_area_ptr[__afl_map_size] + diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c new file mode 100644 index 00000000..f2dfeac1 --- /dev/null +++ b/utils/afl_proxy/afl-proxy.c @@ -0,0 +1,238 @@ +/* + american fuzzy lop++ - afl-proxy skeleton example + --------------------------------------------------- + + Written by Marc Heuse + + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + + HOW-TO + ====== + + You only need to change the while() loop of the main() to send the + data of buf[] with length len to the target and write the coverage + information to __afl_area_ptr[__afl_map_size] + + +*/ + +#ifdef __ANDROID__ + #include "android-ashmem.h" +#endif +#include "config.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +u8 *__afl_area_ptr; + +#ifdef __ANDROID__ +u32 __afl_map_size = MAP_SIZE; +#else +__thread u32 __afl_map_size = MAP_SIZE; +#endif + +/* Error reporting to forkserver controller */ + +void send_forkserver_error(int error) { + + u32 status; + if (!error || error > 0xffff) return; + status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); + if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; + +} + +/* SHM setup. */ + +static void __afl_map_shm(void) { + + char *id_str = getenv(SHM_ENV_VAR); + char *ptr; + + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { + + u32 val = atoi(ptr); + if (val > 0) __afl_map_size = val; + + } + + if (__afl_map_size > MAP_SIZE) { + + if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { + + fprintf(stderr, + "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + if (id_str) { + + send_forkserver_error(FS_ERROR_MAP_SIZE); + exit(-1); + + } + + } else { + + fprintf(stderr, + "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + + } + + } + + if (id_str) { + +#ifdef USEMMAP + const char * shm_file_path = id_str; + int shm_fd = -1; + unsigned char *shm_base = NULL; + + /* create the shared memory segment as if it was a file */ + shm_fd = shm_open(shm_file_path, O_RDWR, 0600); + if (shm_fd == -1) { + + fprintf(stderr, "shm_open() failed\n"); + send_forkserver_error(FS_ERROR_SHM_OPEN); + exit(1); + + } + + /* map the shared memory segment to the address space of the process */ + shm_base = + mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + + if (shm_base == MAP_FAILED) { + + close(shm_fd); + shm_fd = -1; + + fprintf(stderr, "mmap() failed\n"); + send_forkserver_error(FS_ERROR_MMAP); + exit(2); + + } + + __afl_area_ptr = shm_base; +#else + u32 shm_id = atoi(id_str); + + __afl_area_ptr = shmat(shm_id, 0, 0); + +#endif + + if (__afl_area_ptr == (void *)-1) { + + send_forkserver_error(FS_ERROR_SHMAT); + exit(1); + + } + + /* Write something into the bitmap so that the parent doesn't give up */ + + __afl_area_ptr[0] = 1; + + } + +} + +/* Fork server logic. */ + +static void __afl_start_forkserver(void) { + + u8 tmp[4] = {0, 0, 0, 0}; + u32 status = 0; + + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) + status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); + if (status) status |= (FS_OPT_ENABLED); + memcpy(tmp, &status, 4); + + /* Phone home and tell the parent that we're OK. */ + + if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + +} + +static u32 __afl_next_testcase(u8 *buf, u32 max_len) { + + s32 status, res = 0xffffff; + + /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (read(FORKSRV_FD, &status, 4) != 4) return 0; + + /* we have a testcase - read it */ + status = read(0, buf, max_len); + + /* report that we are starting the target */ + if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; + + if (status < 1) + return 0; + else + return status; + +} + +static void __afl_end_testcase(void) { + + int status = 0xffffff; + + if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); + +} + +/* you just need to modify the while() loop in this main() */ + +int main(int argc, char *argv[]) { + + /* This is were the testcase data is written into */ + u8 buf[1024]; // this is the maximum size for a test case! set it! + u32 len; + + /* here you specify the map size you need that you are reporting to + afl-fuzz. */ + __afl_map_size = MAP_SIZE; // default is 65536 + + /* then we initialize the shared memory map and start the forkserver */ + __afl_map_shm(); + __afl_start_forkserver(); + + while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { + + /* here you have to create the magic that feeds the buf/len to the + target and write the coverage to __afl_area_ptr */ + + // ... the magic ... + + /* report the test case is done and wait for the next */ + __afl_end_testcase(); + + } + + return 0; + +} + diff --git a/utils/afl_untracer/Makefile b/utils/afl_untracer/Makefile new file mode 100644 index 00000000..14a09b41 --- /dev/null +++ b/utils/afl_untracer/Makefile @@ -0,0 +1,16 @@ +ifdef DEBUG + OPT=-O0 +else + OPT=-O3 +endif + +all: afl-untracer libtestinstr.so + +afl-untracer: afl-untracer.c + $(CC) $(OPT) -I../../include -g -o afl-untracer afl-untracer.c -ldl + +libtestinstr.so: libtestinstr.c + $(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c + +clean: + rm -f afl-untracer libtestinstr.so *~ core diff --git a/utils/afl_untracer/README.md b/utils/afl_untracer/README.md new file mode 100644 index 00000000..ada0c916 --- /dev/null +++ b/utils/afl_untracer/README.md @@ -0,0 +1,60 @@ +# afl-untracer - fast fuzzing of binary-only libraries + +## Introduction + +afl-untracer is an example skeleton file which can easily be used to fuzz +a closed source library. + +It requires less memory and is x3-5 faster than qemu_mode however it is way +more course grained and does not provide interesting features like compcov +or cmplog. + +Supported is so far Intel (i386/x86_64) and AARCH64. + +## How-to + +### Modify afl-untracer.c + +Read and modify afl-untracer.c then `make`. +To adapt afl-untracer.c to your needs, read the header of the file and then +search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations. + +### Generate patches.txt file + +To generate the `patches.txt` file for your target library use the +`ida_get_patchpoints.py` script for IDA Pro or +`ghidra_get_patchpoints.java` for Ghidra. + +The patches.txt file has to be pointed to by `AFL_UNTRACER_FILE`. + +To easily run the scripts without needing to run the GUI with Ghidra: +``` +/opt/ghidra/support/analyzeHeadless /tmp/ tmp$$ -import libtestinstr.so -postscript ./ghidra_get_patchpoints.java +rm -rf /tmp/tmp$$ +``` +The file is created at `~/Desktop/patches.txt` + +### Fuzzing + +Example (after modifying afl-untracer.c to your needs, compiling and creating +patches.txt): +``` +LD_LIBRARY_PATH=/path/to/target/library AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer +``` +(or even remote via afl-network-proxy). + +### Testing and debugging + +For testing/debugging you can try: +``` +make DEBUG=1 +AFL_UNTRACER_FILE=./patches.txt AFL_DEBUG=1 gdb ./afl-untracer +``` +and then you can easily set breakpoints to "breakpoint" and "fuzz". + +# Background + +This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL) +and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz). +This implementation is slower because the traps are not patched out with each +run, but on the other hand gives much better coverage information. diff --git a/utils/afl_untracer/TODO b/utils/afl_untracer/TODO new file mode 100644 index 00000000..fffffacf --- /dev/null +++ b/utils/afl_untracer/TODO @@ -0,0 +1,2 @@ + * add shmem fuzzing + * add snapshot feature? diff --git a/utils/afl_untracer/afl-untracer.c b/utils/afl_untracer/afl-untracer.c new file mode 100644 index 00000000..cb6f948c --- /dev/null +++ b/utils/afl_untracer/afl-untracer.c @@ -0,0 +1,768 @@ +/* + american fuzzy lop++ - afl-untracer skeleton example + --------------------------------------------------- + + Written by Marc Heuse + + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + + HOW-TO + ====== + + You only need to change the following: + + 1. decide if you want to receive data from stdin [DEFAULT] or file(name) + -> use_stdin = 0 if via file, and what the maximum input size is + 2. dl load the library you want to fuzz, lookup the functions you need + and setup the calls to these + 3. in the while loop you call the functions in the necessary order - + incl the cleanup. the cleanup is important! + + Just look these steps up in the code, look for "// STEP x:" + + +*/ + +#define __USE_GNU +#define _GNU_SOURCE + +#ifdef __ANDROID__ + #include "android-ashmem.h" +#endif +#include "config.h" +#include "types.h" +#include "debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(__linux__) + #include +#elif defined(__APPLE__) && defined(__LP64__) + #include +#elif defined(__FreeBSD__) + #include + #include +#else + #error "Unsupported platform" +#endif + +#define MEMORY_MAP_DECREMENT 0x200000000000 +#define MAX_LIB_COUNT 128 + +// STEP 1: + +/* here you need to specify the parameter for the target function */ +static void *(*o_function)(u8 *buf, int len); + +/* use stdin (1) or a file on the commandline (0) */ +static u32 use_stdin = 1; + +/* This is were the testcase data is written into */ +static u8 buf[10000]; // this is the maximum size for a test case! set it! + +/* If you want to have debug output set this to 1, can also be set with + AFL_DEBUG */ +static u32 debug = 0; + +// END STEP 1 + +typedef struct library_list { + + u8 *name; + u64 addr_start, addr_end; + +} library_list_t; + +#ifdef __ANDROID__ +u32 __afl_map_size = MAP_SIZE; +u32 do_exit; +#else +__thread u32 __afl_map_size = MAP_SIZE; +__thread u32 do_exit; +#endif + +static pid_t pid = 65537; +static pthread_t __afl_thread; +static u8 __afl_dummy[MAP_SIZE]; +static u8 * __afl_area_ptr = __afl_dummy; +static u8 * inputfile; // this will point to argv[1] +static u32 len; + +static library_list_t liblist[MAX_LIB_COUNT]; +static u32 liblist_cnt; + +static void sigtrap_handler(int signum, siginfo_t *si, void *context); +static void fuzz(void); + +/* read the library information */ +void read_library_information(void) { + +#if defined(__linux__) + FILE *f; + u8 buf[1024], *b, *m, *e, *n; + + if ((f = fopen("/proc/self/maps", "r")) == NULL) + FATAL("cannot open /proc/self/maps"); + + if (debug) fprintf(stderr, "Library list:\n"); + while (fgets(buf, sizeof(buf), f)) { + + if (strstr(buf, " r-x")) { + + if (liblist_cnt >= MAX_LIB_COUNT) { + + WARNF("too many libraries to old, maximum count of %d reached", + liblist_cnt); + return; + + } + + b = buf; + m = index(buf, '-'); + e = index(buf, ' '); + if ((n = rindex(buf, '/')) == NULL) n = rindex(buf, ' '); + if (n && + ((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '(')) + n = NULL; + else + n++; + if (b && m && e && n && *n) { + + *m++ = 0; + *e = 0; + if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0; + + liblist[liblist_cnt].name = strdup(n); + liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16); + liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16); + if (debug) + fprintf( + stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name, + liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, + liblist[liblist_cnt].addr_start, + liblist[liblist_cnt].addr_end - 1); + liblist_cnt++; + + } + + } + + } + + if (debug) fprintf(stderr, "\n"); + +#elif defined(__FreeBSD__) + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; + char * buf, *start, *end; + size_t miblen = sizeof(mib) / sizeof(mib[0]); + size_t len; + + if (debug) fprintf(stderr, "Library list:\n"); + if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; } + + len = len * 4 / 3; + + buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); + if (buf == MAP_FAILED) { return; } + + if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) { + + munmap(buf, len); + return; + + } + + start = buf; + end = buf + len; + + while (start < end) { + + struct kinfo_vmentry *region = (struct kinfo_vmentry *)start; + size_t size = region->kve_structsize; + + if (size == 0) { break; } + + if ((region->kve_protection & KVME_PROT_READ) && + !(region->kve_protection & KVME_PROT_EXEC)) { + + liblist[liblist_cnt].name = + region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0; + liblist[liblist_cnt].addr_start = region->kve_start; + liblist[liblist_cnt].addr_end = region->kve_end; + + if (debug) { + + fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name, + liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, + liblist[liblist_cnt].addr_start, + liblist[liblist_cnt].addr_end - 1); + + } + + liblist_cnt++; + + } + + start += size; + + } + +#endif + +} + +library_list_t *find_library(char *name) { + +#if defined(__linux__) + u32 i; + + for (i = 0; i < liblist_cnt; i++) + if (strncmp(liblist[i].name, name, strlen(name)) == 0) return &liblist[i]; +#elif defined(__APPLE__) && defined(__LP64__) + kern_return_t err; + static library_list_t lib; + + // get the list of all loaded modules from dyld + // the task_info mach API will get the address of the dyld all_image_info + // struct for the given task from which we can get the names and load + // addresses of all modules + task_dyld_info_data_t task_dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + err = task_info(mach_task_self(), TASK_DYLD_INFO, + (task_info_t)&task_dyld_info, &count); + + const struct dyld_all_image_infos *all_image_infos = + (const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr; + const struct dyld_image_info *image_infos = all_image_infos->infoArray; + + for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) { + + const char * image_name = image_infos[i].imageFilePath; + mach_vm_address_t image_load_address = + (mach_vm_address_t)image_infos[i].imageLoadAddress; + if (strstr(image_name, name)) { + + lib.name = name; + lib.addr_start = (u64)image_load_address; + lib.addr_end = 0; + return &lib; + + } + + } + +#endif + + return NULL; + +} + +/* for having an easy breakpoint location after loading the shared library */ +// this seems to work for clang too. nice :) requires gcc 4.4+ +#pragma GCC push_options +#pragma GCC optimize("O0") +void breakpoint(void) { + + if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n"); + +} + +#pragma GCC pop_options + +/* Error reporting to forkserver controller */ + +void send_forkserver_error(int error) { + + u32 status; + if (!error || error > 0xffff) return; + status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); + if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; + +} + +/* SHM setup. */ + +static void __afl_map_shm(void) { + + char *id_str = getenv(SHM_ENV_VAR); + char *ptr; + + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { + + u32 val = atoi(ptr); + if (val > 0) __afl_map_size = val; + + } + + if (__afl_map_size > MAP_SIZE) { + + if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { + + fprintf(stderr, + "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + if (id_str) { + + send_forkserver_error(FS_ERROR_MAP_SIZE); + exit(-1); + + } + + } else { + + fprintf(stderr, + "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + + } + + } + + if (id_str) { + +#ifdef USEMMAP + const char * shm_file_path = id_str; + int shm_fd = -1; + unsigned char *shm_base = NULL; + + /* create the shared memory segment as if it was a file */ + shm_fd = shm_open(shm_file_path, O_RDWR, 0600); + if (shm_fd == -1) { + + fprintf(stderr, "shm_open() failed\n"); + send_forkserver_error(FS_ERROR_SHM_OPEN); + exit(1); + + } + + /* map the shared memory segment to the address space of the process */ + shm_base = + mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + + if (shm_base == MAP_FAILED) { + + close(shm_fd); + shm_fd = -1; + + fprintf(stderr, "mmap() failed\n"); + send_forkserver_error(FS_ERROR_MMAP); + exit(2); + + } + + __afl_area_ptr = shm_base; +#else + u32 shm_id = atoi(id_str); + + __afl_area_ptr = shmat(shm_id, 0, 0); + +#endif + + if (__afl_area_ptr == (void *)-1) { + + send_forkserver_error(FS_ERROR_SHMAT); + exit(1); + + } + + /* Write something into the bitmap so that the parent doesn't give up */ + + __afl_area_ptr[0] = 1; + + } + +} + +/* Fork server logic. */ +inline static void __afl_start_forkserver(void) { + + u8 tmp[4] = {0, 0, 0, 0}; + u32 status = 0; + + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) + status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); + if (status) status |= (FS_OPT_ENABLED); + memcpy(tmp, &status, 4); + + /* Phone home and tell the parent that we're OK. */ + if (write(FORKSRV_FD + 1, tmp, 4) != 4) do_exit = 1; + // fprintf(stderr, "write0 %d\n", do_exit); + +} + +inline static u32 __afl_next_testcase(u8 *buf, u32 max_len) { + + s32 status; + + /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (read(FORKSRV_FD, &status, 4) != 4) do_exit = 1; + // fprintf(stderr, "read %d\n", do_exit); + + /* we have a testcase - read it if we read from stdin */ + if (use_stdin) { + + if ((status = read(0, buf, max_len)) <= 0) exit(-1); + + } else + + status = 1; + // fprintf(stderr, "stdin: %d %d\n", use_stdin, status); + + /* report that we are starting the target */ + if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1; + // fprintf(stderr, "write1 %d\n", do_exit); + + __afl_area_ptr[0] = 1; // put something in the map + + return status; + +} + +inline static void __afl_end_testcase(int status) { + + if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1; + // fprintf(stderr, "write2 %d\n", do_exit); + if (do_exit) exit(0); + +} + +#ifdef __aarch64__ + #define SHADOW(addr) \ + ((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \ + MEMORY_MAP_DECREMENT - \ + ((uintptr_t)addr & 0x7) * 0x10000000000)) +#else + #define SHADOW(addr) \ + ((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \ + MEMORY_MAP_DECREMENT - \ + ((uintptr_t)addr & 0x3) * 0x10000000000)) +#endif + +void setup_trap_instrumentation(void) { + + library_list_t *lib_base = NULL; + size_t lib_size = 0; + u8 * lib_addr; + char * line = NULL; + size_t nread, len = 0; + char * filename = getenv("AFL_UNTRACER_FILE"); + if (!filename) filename = getenv("TRAPFUZZ_FILE"); + if (!filename) FATAL("AFL_UNTRACER_FILE environment variable not set"); + + FILE *patches = fopen(filename, "r"); + if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename); + + // Index into the coverage bitmap for the current trap instruction. +#ifdef __aarch64__ + uint64_t bitmap_index = 0; +#else + uint32_t bitmap_index = 0; +#endif + + while ((nread = getline(&line, &len, patches)) != -1) { + + char *end = line + len; + + char *col = strchr(line, ':'); + if (col) { + + // It's a library:size pair + *col++ = 0; + + lib_base = find_library(line); + if (!lib_base) FATAL("Library %s does not appear to be loaded", line); + + // we ignore the defined lib_size + lib_size = strtoul(col, NULL, 16); +#if (__linux__) + if (lib_size < lib_base->addr_end - lib_base->addr_start) + lib_size = lib_base->addr_end - lib_base->addr_start; +#endif + if (lib_size % 0x1000 != 0) + WARNF("Invalid library size 0x%zx. Must be multiple of 0x1000", + lib_size); + + lib_addr = (u8 *)lib_base->addr_start; + + // Make library code writable. + if (mprotect((void *)lib_addr, lib_size, + PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + FATAL("Failed to mprotect library %s writable", line); + + // Create shadow memory. +#ifdef __aarch64__ + for (int i = 0; i < 8; i++) { + +#else + for (int i = 0; i < 4; i++) { + +#endif + + void *shadow_addr = SHADOW(lib_addr + i); + void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0); + if (debug) + fprintf(stderr, "Shadow: %s %d = %p-%p for %p\n", line, i, shadow, + shadow + lib_size - 1, lib_addr); + if (shadow == MAP_FAILED) FATAL("Failed to mmap shadow memory"); + + } + + // Done, continue with next line. + continue; + + } + + // It's an offset, parse it and do the patching. + unsigned long offset = strtoul(line, NULL, 16); + + if (offset > lib_size) + FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large", + offset, lib_size); + + if (bitmap_index >= __afl_map_size) + FATAL("Too many basic blocks to instrument"); + +#ifdef __arch64__ + uint64_t +#else + uint32_t +#endif + *shadow = SHADOW(lib_addr + offset); + if (*shadow != 0) continue; // skip duplicates + + // Make lookup entry in shadow memory. + +#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \ + defined(__i386__)) + + // this is for Intel x64 + + uint8_t orig_byte = lib_addr[offset]; + *shadow = (bitmap_index << 8) | orig_byte; + lib_addr[offset] = 0xcc; // replace instruction with debug trap + if (debug) + fprintf(stderr, + "Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %08x\n", + lib_addr, offset, lib_addr + offset, orig_byte, shadow, + bitmap_index, *shadow); + +#elif defined(__aarch64__) + + // this is for aarch64 + + uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset); + uint32_t orig_bytes = *patch_bytes; + *shadow = (bitmap_index << 32) | orig_bytes; + *patch_bytes = 0xd4200000; // replace instruction with debug trap + if (debug) + fprintf(stderr, + "Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %016x\n", + lib_addr, offset, lib_addr + offset, orig_bytes, shadow, + bitmap_index, *shadow); + +#else + // this will be ARM and AARCH64 + // for ARM we will need to identify if the code is in thumb or ARM + #error "non x86_64/aarch64 not supported yet" + //__arm__: + // linux thumb: 0xde01 + // linux arm: 0xe7f001f0 + //__aarch64__: + // linux aarch64: 0xd4200000 +#endif + + bitmap_index++; + + } + + free(line); + fclose(patches); + + // Install signal handler for SIGTRAP. + struct sigaction s; + s.sa_flags = SA_SIGINFO; + s.sa_sigaction = sigtrap_handler; + sigemptyset(&s.sa_mask); + sigaction(SIGTRAP, &s, 0); + + if (debug) fprintf(stderr, "Patched %u locations.\n", bitmap_index); + __afl_map_size = bitmap_index; + if (__afl_map_size % 8) __afl_map_size = (((__afl_map_size + 7) >> 3) << 3); + +} + +/* the signal handler for the traps / debugging interrupts + No debug output here because this would cost speed */ +static void sigtrap_handler(int signum, siginfo_t *si, void *context) { + + uint64_t addr; + // Must re-execute the instruction, so decrement PC by one instruction. + ucontext_t *ctx = (ucontext_t *)context; +#if defined(__APPLE__) && defined(__LP64__) + ctx->uc_mcontext->__ss.__rip -= 1; + addr = ctx->uc_mcontext->__ss.__rip; +#elif defined(__linux__) + #if defined(__x86_64__) || defined(__i386__) + ctx->uc_mcontext.gregs[REG_RIP] -= 1; + addr = ctx->uc_mcontext.gregs[REG_RIP]; + #elif defined(__aarch64__) + ctx->uc_mcontext.pc -= 4; + addr = ctx->uc_mcontext.pc; + #else + #error "Unsupported processor" + #endif +#elif defined(__FreeBSD__) && defined(__LP64__) + ctx->uc_mcontext.mc_rip -= 1; + addr = ctx->uc_mcontext.mc_rip; +#else + #error "Unsupported platform" +#endif + + // fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr, + // si->si_addr); + + // If the trap didn't come from our instrumentation, then we probably will + // just segfault here + uint8_t *faultaddr; + if (unlikely(si->si_addr)) + faultaddr = (u8 *)si->si_addr - 1; + else + faultaddr = (u8 *)addr; + // if (debug) fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr)); + uint32_t shadow = *SHADOW(faultaddr); + uint8_t orig_byte = shadow & 0xff; + uint32_t index = shadow >> 8; + + // if (debug) fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n", + // shadow, orig_byte, index); + + // Index zero is invalid so that it is still possible to catch actual trap + // instructions in instrumented libraries. + if (unlikely(index == 0)) abort(); + + // Restore original instruction + *faultaddr = orig_byte; + + __afl_area_ptr[index] = 128; + +} + +/* the MAIN function */ +int main(int argc, char *argv[]) { + + (void)personality(ADDR_NO_RANDOMIZE); // disable ASLR + + pid = getpid(); + if (getenv("AFL_DEBUG")) debug = 1; + + /* by default we use stdin, but also a filename can be passed, in this + case the input is argv[1] and we have to disable stdin */ + if (argc > 1) { + + use_stdin = 0; + inputfile = argv[1]; + + } + + // STEP 2: load the library you want to fuzz and lookup the functions, + // inclusive of the cleanup functions + // NOTE: above the main() you have to define the functions! + + void *dl = dlopen("./libtestinstr.so", RTLD_LAZY); + if (!dl) FATAL("could not find target library"); + o_function = dlsym(dl, "testinstr"); + if (!o_function) FATAL("could not resolve target function from library"); + if (debug) fprintf(stderr, "Function address: %p\n", o_function); + + // END STEP 2 + + /* setup instrumentation, shared memory and forkserver */ + breakpoint(); + read_library_information(); + setup_trap_instrumentation(); + __afl_map_shm(); + __afl_start_forkserver(); + + while (1) { + + // instead of fork() we could also use the snapshot lkm or do our own mini + // snapshot feature like in https://github.com/marcinguy/fuzzer + // -> snapshot.c + if ((pid = fork()) == -1) PFATAL("fork failed"); + + if (pid) { + + u32 status; + if (waitpid(pid, &status, 0) < 0) exit(1); + /* report the test case is done and wait for the next */ + __afl_end_testcase(status); + + } else { + + pid = getpid(); + while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { + + // in this function the fuzz magic happens, this is STEP 3 + fuzz(); + + // we can use _exit which is faster because our target library + // was loaded via dlopen and therefore cannot have deconstructors + // registered. + _exit(0); + + } + + } + + } + + return 0; + +} + +#ifndef _DEBUG +inline +#endif + static void + fuzz(void) { + + // STEP 3: call the function to fuzz, also the functions you might + // need to call to prepare the function and - important! - + // to clean everything up + + // in this example we use the input file, not stdin! + (*o_function)(buf, len); + + // normally you also need to cleanup + //(*o_LibFree)(foo); + + // END STEP 3 + +} + diff --git a/utils/afl_untracer/ghidra_get_patchpoints.java b/utils/afl_untracer/ghidra_get_patchpoints.java new file mode 100644 index 00000000..2a93642b --- /dev/null +++ b/utils/afl_untracer/ghidra_get_patchpoints.java @@ -0,0 +1,84 @@ +/* ### + * IP: GHIDRA + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Find patch points for untracer tools (e.g. afl++ utils/afl_untracer) +// +// Copy to ..../Ghidra/Features/Search/ghidra_scripts/ +// Writes the results to ~/Desktop/patches.txt +// +// This is my very first Ghidra script. I am sure this could be done better. +// +//@category Search + +import ghidra.app.script.GhidraScript; +import ghidra.program.model.address.*; +import ghidra.program.model.block.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.symbol.*; +import ghidra.program.model.mem.*; + +import java.io.*; + +public class ghidra_get_patchpoints extends GhidraScript { + + @Override + public void run() throws Exception { + + long segment_start = 0; + Memory memory = currentProgram.getMemory(); + MultEntSubModel model = new MultEntSubModel(currentProgram); + CodeBlockIterator subIter = model.getCodeBlocks(monitor); + BufferedWriter out = new BufferedWriter(new FileWriter(System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "patches.txt")); + + while (subIter.hasNext()) { + + CodeBlock multiEntryBlock = subIter.next(); + SimpleBlockModel basicBlockModel = new SimpleBlockModel(currentProgram); + CodeBlockIterator bbIter = basicBlockModel.getCodeBlocksContaining(multiEntryBlock, monitor); + + while (bbIter.hasNext()) { + + CodeBlock basicBlock = bbIter.next(); + + if (segment_start == 0) { + + Address firstAddr = basicBlock.getFirstStartAddress(); + long firstBlockAddr = firstAddr.getAddressableWordOffset(); + MemoryBlock mb = memory.getBlock(firstAddr); + Address startAddr = mb.getStart(); + Address endAddr = mb.getEnd(); + segment_start = startAddr.getAddressableWordOffset(); + if ((firstBlockAddr - segment_start) >= 0x1000) + segment_start += 0x1000; + long segment_end = endAddr.getAddressableWordOffset(); + long segment_size = segment_end - segment_start; + if ((segment_size % 0x1000) > 0) + segment_size = (((segment_size / 0x1000) + 1) * 0x1000); + out.write(currentProgram.getName() + ":0x" + Long.toHexString(segment_size) + "\n"); + //println("Start: " + Long.toHexString(segment_start)); + //println("End: " + Long.toHexString(segment_end)); + + } + + if (basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start > 0) + out.write("0x" + Long.toHexString(basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start) + "\n"); + + } + } + + out.close(); + + } +} diff --git a/utils/afl_untracer/ida_get_patchpoints.py b/utils/afl_untracer/ida_get_patchpoints.py new file mode 100644 index 00000000..43cf6d89 --- /dev/null +++ b/utils/afl_untracer/ida_get_patchpoints.py @@ -0,0 +1,62 @@ +# +# IDAPython script for IDA Pro +# Slightly modified from https://github.com/googleprojectzero/p0tools/blob/master/TrapFuzz/findPatchPoints.py +# + +import idautils +import idaapi +import ida_nalt +import idc + +# See https://www.hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml + +from os.path import expanduser +home = expanduser("~") + +patchpoints = set() + +max_offset = 0 +for seg_ea in idautils.Segments(): + name = idc.get_segm_name(seg_ea) + #print("Segment: " + name) + if name != "__text" and name != ".text": + continue + + start = idc.get_segm_start(seg_ea) + end = idc.get_segm_end(seg_ea) + first = 0 + subtract_addr = 0 + #print("Start: " + hex(start) + " End: " + hex(end)) + for func_ea in idautils.Functions(start, end): + f = idaapi.get_func(func_ea) + if not f: + continue + for block in idaapi.FlowChart(f): + if start <= block.start_ea < end: + if first == 0: + if block.start_ea >= 0x1000: + subtract_addr = 0x1000 + first = 1 + + max_offset = max(max_offset, block.start_ea) + patchpoints.add(block.start_ea - subtract_addr) + #else: + # print("Warning: broken CFG?") + +# Round up max_offset to page size +size = max_offset +rem = size % 0x1000 +if rem != 0: + size += 0x1000 - rem + +print("Writing to " + home + "/Desktop/patches.txt") + +with open(home + "/Desktop/patches.txt", "w") as f: + f.write(ida_nalt.get_root_filename() + ':' + hex(size) + '\n') + f.write('\n'.join(map(hex, sorted(patchpoints)))) + f.write('\n') + +print("Done, found {} patchpoints".format(len(patchpoints))) + +# For headless script running remove the comment from the next line +#ida_pro.qexit() diff --git a/utils/afl_untracer/libtestinstr.c b/utils/afl_untracer/libtestinstr.c new file mode 100644 index 00000000..96b1cf21 --- /dev/null +++ b/utils/afl_untracer/libtestinstr.c @@ -0,0 +1,35 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + diff --git a/utils/afl_untracer/patches.txt b/utils/afl_untracer/patches.txt new file mode 100644 index 00000000..7e964249 --- /dev/null +++ b/utils/afl_untracer/patches.txt @@ -0,0 +1,34 @@ +libtestinstr.so:0x1000 +0x10 +0x12 +0x20 +0x36 +0x30 +0x40 +0x50 +0x63 +0x6f +0x78 +0x80 +0xa4 +0xb0 +0xb8 +0x100 +0xc0 +0xc9 +0xd7 +0xe3 +0xe8 +0xf8 +0x105 +0x11a +0x135 +0x141 +0x143 +0x14e +0x15a +0x15c +0x168 +0x16a +0x16b +0x170 diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile new file mode 100644 index 00000000..c1a087d7 --- /dev/null +++ b/utils/aflpp_driver/GNUmakefile @@ -0,0 +1,46 @@ +ifeq "" "$(LLVM_CONFIG)" + LLVM_CONFIG=llvm-config +endif + +LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null) +ifneq "" "$(LLVM_BINDIR)" + LLVM_BINDIR := $(LLVM_BINDIR)/ +endif + +CFLAGS := -O3 -funroll-loops -g + +all: libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so + +aflpp_driver.o: aflpp_driver.c + -$(LLVM_BINDIR)clang -I. -I../../include $(CFLAGS) -c aflpp_driver.c + +libAFLDriver.a: aflpp_driver.o + ar ru libAFLDriver.a aflpp_driver.o + cp -vf libAFLDriver.a ../../ + +debug: + $(LLVM_BINDIR)clang -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c + $(LLVM_BINDIR)clang -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c + #$(LLVM_BINDIR)clang -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c + #$(LLVM_BINDIR)clang -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c + ar ru libAFLDriver.a afl-performance.o aflpp_driver.o + +aflpp_qemu_driver.o: aflpp_qemu_driver.c + $(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c + +libAFLQemuDriver.a: aflpp_qemu_driver.o + ar ru libAFLQemuDriver.a aflpp_qemu_driver.o + cp -vf libAFLQemuDriver.a ../../ + +aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o + $(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so + +aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c + $(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c + +test: debug + #clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c + afl-clang-fast -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test aflpp_driver_test.c libAFLDriver.a afl-performance.o + +clean: + rm -f *.o libAFLDriver*.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so *~ core aflpp_driver_test diff --git a/utils/aflpp_driver/Makefile b/utils/aflpp_driver/Makefile new file mode 100644 index 00000000..3666a74d --- /dev/null +++ b/utils/aflpp_driver/Makefile @@ -0,0 +1,2 @@ +all: + @gmake all || echo please install GNUmake diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c new file mode 100644 index 00000000..017aa72b --- /dev/null +++ b/utils/aflpp_driver/aflpp_driver.c @@ -0,0 +1,326 @@ +//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//===----------------------------------------------------------------------===// + +/* This file allows to fuzz libFuzzer-style target functions + (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode. + +Usage: +################################################################################ +cat << EOF > test_fuzzer.cc +#include +#include +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + if (size > 0 && data[0] == 'H') + if (size > 1 && data[1] == 'I') + if (size > 2 && data[2] == '!') + __builtin_trap(); + return 0; + +} + +EOF +# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang. +clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c +# Build afl-llvm-rt.o.c from the AFL distribution. +clang -c -w $AFL_HOME/instrumentation/afl-llvm-rt.o.c +# Build this file, link it with afl-llvm-rt.o.o and the target code. +clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o +# Run AFL: +rm -rf IN OUT; mkdir IN OUT; echo z > IN/z; +$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out +################################################################################ +AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file +specified. If the file does not exist, it is created. This is useful for getting +stack traces (when using ASAN for example) or original error messages on hard +to reproduce bugs. Note that any content written to stderr will be written to +this file instead of stderr's usual location. + +AFL_DRIVER_CLOSE_FD_MASK: Similar to libFuzzer's -close_fd_mask behavior option. +If 1, close stdout at startup. If 2 close stderr; if 3 close both. + +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "cmplog.h" + +#ifdef _DEBUG + #include "hash.h" +#endif + +#ifndef MAP_FIXED_NOREPLACE + #define MAP_FIXED_NOREPLACE 0x100000 +#endif + +#define MAX_DUMMY_SIZE 256000 + +// Platform detection. Copied from FuzzerInternal.h +#ifdef __linux__ + #define LIBFUZZER_LINUX 1 + #define LIBFUZZER_APPLE 0 + #define LIBFUZZER_NETBSD 0 + #define LIBFUZZER_FREEBSD 0 + #define LIBFUZZER_OPENBSD 0 +#elif __APPLE__ + #define LIBFUZZER_LINUX 0 + #define LIBFUZZER_APPLE 1 + #define LIBFUZZER_NETBSD 0 + #define LIBFUZZER_FREEBSD 0 + #define LIBFUZZER_OPENBSD 0 +#elif __NetBSD__ + #define LIBFUZZER_LINUX 0 + #define LIBFUZZER_APPLE 0 + #define LIBFUZZER_NETBSD 1 + #define LIBFUZZER_FREEBSD 0 + #define LIBFUZZER_OPENBSD 0 +#elif __FreeBSD__ + #define LIBFUZZER_LINUX 0 + #define LIBFUZZER_APPLE 0 + #define LIBFUZZER_NETBSD 0 + #define LIBFUZZER_FREEBSD 1 + #define LIBFUZZER_OPENBSD 0 +#elif __OpenBSD__ + #define LIBFUZZER_LINUX 0 + #define LIBFUZZER_APPLE 0 + #define LIBFUZZER_NETBSD 0 + #define LIBFUZZER_FREEBSD 0 + #define LIBFUZZER_OPENBSD 1 +#else + #error "Support for your platform has not been implemented" +#endif + +int __afl_sharedmem_fuzzing = 1; +extern unsigned int * __afl_fuzz_len; +extern unsigned char *__afl_fuzz_ptr; + +// libFuzzer interface is thin, so we don't include any libFuzzer headers. +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); +__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); + +// Notify AFL about persistent mode. +static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; +int __afl_persistent_loop(unsigned int); + +// Notify AFL about deferred forkserver. +static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; +void __afl_manual_init(); + +// Use this optionally defined function to output sanitizer messages even if +// user asks to close stderr. +__attribute__((weak)) void __sanitizer_set_report_fd(void *); + +// Keep track of where stderr content is being written to, so that +// dup_and_close_stderr can use the correct one. +static FILE *output_file; + +// Experimental feature to use afl_driver without AFL's deferred mode. +// Needs to run before __afl_auto_init. +__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) { + + if (getenv("AFL_DRIVER_DONT_DEFER")) { + + if (unsetenv("__AFL_DEFER_FORKSRV")) { + + perror("Failed to unset __AFL_DEFER_FORKSRV"); + abort(); + + } + + } + +} + +// If the user asks us to duplicate stderr, then do it. +static void maybe_duplicate_stderr() { + + char *stderr_duplicate_filename = + getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); + + if (!stderr_duplicate_filename) return; + + FILE *stderr_duplicate_stream = + freopen(stderr_duplicate_filename, "a+", stderr); + + if (!stderr_duplicate_stream) { + + fprintf( + stderr, + "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); + abort(); + + } + + output_file = stderr_duplicate_stream; + +} + +// Most of these I/O functions were inspired by/copied from libFuzzer's code. +static void discard_output(int fd) { + + FILE *temp = fopen("/dev/null", "w"); + if (!temp) abort(); + dup2(fileno(temp), fd); + fclose(temp); + +} + +static void close_stdout() { + + discard_output(STDOUT_FILENO); + +} + +// Prevent the targeted code from writing to "stderr" but allow sanitizers and +// this driver to do so. +static void dup_and_close_stderr() { + + int output_fileno = fileno(output_file); + int output_fd = dup(output_fileno); + if (output_fd <= 0) abort(); + FILE *new_output_file = fdopen(output_fd, "w"); + if (!new_output_file) abort(); + if (!__sanitizer_set_report_fd) return; + __sanitizer_set_report_fd((void *)(long int)output_fd); + discard_output(output_fileno); + +} + +// Close stdout and/or stderr if user asks for it. +static void maybe_close_fd_mask() { + + char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK"); + if (!fd_mask_str) return; + int fd_mask = atoi(fd_mask_str); + if (fd_mask & 2) dup_and_close_stderr(); + if (fd_mask & 1) close_stdout(); + +} + +// Define LLVMFuzzerMutate to avoid link failures for targets that use it +// with libFuzzer's LLVMFuzzerCustomMutator. +size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { + + // assert(false && "LLVMFuzzerMutate should not be called from afl_driver"); + return 0; + +} + +// Execute any files provided as parameters. +static int ExecuteFilesOnyByOne(int argc, char **argv) { + + unsigned char *buf = malloc(MAX_FILE); + for (int i = 1; i < argc; i++) { + + int fd = open(argv[i], O_RDONLY); + if (fd == -1) continue; + ssize_t length = read(fd, buf, MAX_FILE); + if (length > 0) { + + printf("Reading %zu bytes from %s\n", length, argv[i]); + LLVMFuzzerTestOneInput(buf, length); + printf("Execution successful.\n"); + + } + + } + + free(buf); + return 0; + +} + +int main(int argc, char **argv) { + + printf( + "======================= INFO =========================\n" + "This binary is built for afl++.\n" + "To run the target function on individual input(s) execute this:\n" + " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" + "To fuzz with afl-fuzz execute this:\n" + " afl-fuzz [afl-flags] -- %s [-N]\n" + "afl-fuzz will run N iterations before re-spawning the process (default: " + "1000)\n" + "======================================================\n", + argv[0], argv[0]); + + output_file = stderr; + maybe_duplicate_stderr(); + maybe_close_fd_mask(); + if (LLVMFuzzerInitialize) { + + fprintf(stderr, "Running LLVMFuzzerInitialize ...\n"); + LLVMFuzzerInitialize(&argc, &argv); + fprintf(stderr, "continue...\n"); + + } + + // Do any other expensive one-time initialization here. + + uint8_t dummy_input[64] = {0}; + memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT)); + memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR, + sizeof(AFL_DEFER_FORKSVR)); + int N = INT_MAX; + if (argc == 2 && argv[1][0] == '-') + N = atoi(argv[1] + 1); + else if (argc == 2 && (N = atoi(argv[1])) > 0) + printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N); + else if (argc > 1) { + + __afl_sharedmem_fuzzing = 0; + __afl_manual_init(); + return ExecuteFilesOnyByOne(argc, argv); + + } + + assert(N > 0); + + // if (!getenv("AFL_DRIVER_DONT_DEFER")) + __afl_manual_init(); + + // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization + // on the first execution of LLVMFuzzerTestOneInput is ignored. + LLVMFuzzerTestOneInput(dummy_input, 1); + + int num_runs = 0; + while (__afl_persistent_loop(N)) { + +#ifdef _DEBUG + fprintf(stderr, "CLIENT crc: %016llx len: %u\n", + hash64(__afl_fuzz_ptr, *__afl_fuzz_len, 0xa5b35705), + *__afl_fuzz_len); + fprintf(stderr, "RECV:"); + for (int i = 0; i < *__afl_fuzz_len; i++) + fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); + fprintf(stderr, "\n"); +#endif + if (*__afl_fuzz_len) { + + num_runs++; + LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len); + + } + + } + + printf("%s: successfully executed %d input(s)\n", argv[0], num_runs); + +} + diff --git a/utils/aflpp_driver/aflpp_driver_test.c b/utils/aflpp_driver/aflpp_driver_test.c new file mode 100644 index 00000000..b4ff6bc6 --- /dev/null +++ b/utils/aflpp_driver/aflpp_driver_test.c @@ -0,0 +1,32 @@ +#include +#include +#include + +#include "hash.h" + +void __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) { + + if (Size < 5) return; + + if (Data[0] == 'F') + if (Data[1] == 'A') + if (Data[2] == '$') + if (Data[3] == '$') + if (Data[4] == '$') abort(); + +} + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + + if (Size) + fprintf(stderr, "FUNC crc: %016llx len: %lu\n", + hash64((u8 *)Data, (unsigned int)Size, + (unsigned long long int)0xa5b35705), + Size); + + crashme(Data, Size); + + return 0; + +} + diff --git a/utils/aflpp_driver/aflpp_qemu_driver.c b/utils/aflpp_driver/aflpp_qemu_driver.c new file mode 100644 index 00000000..4f3e5f71 --- /dev/null +++ b/utils/aflpp_driver/aflpp_qemu_driver.c @@ -0,0 +1,38 @@ +#include +#include +#include + +// libFuzzer interface is thin, so we don't include any libFuzzer headers. +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); +__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); + +static const size_t kMaxAflInputSize = 1 * 1024 * 1024; +static uint8_t AflInputBuf[kMaxAflInputSize]; + +void __attribute__((noinline)) afl_qemu_driver_stdin_input(void) { + + size_t l = read(0, AflInputBuf, kMaxAflInputSize); + LLVMFuzzerTestOneInput(AflInputBuf, l); + +} + +int main(int argc, char **argv) { + + if (LLVMFuzzerInitialize) LLVMFuzzerInitialize(&argc, &argv); + // Do any other expensive one-time initialization here. + + if (getenv("AFL_QEMU_DRIVER_NO_HOOK")) { + + afl_qemu_driver_stdin_input(); + + } else { + + uint8_t dummy_input[1024000] = {0}; + LLVMFuzzerTestOneInput(dummy_input, 1); + + } + + return 0; + +} + diff --git a/utils/aflpp_driver/aflpp_qemu_driver_hook.c b/utils/aflpp_driver/aflpp_qemu_driver_hook.c new file mode 100644 index 00000000..823cc42d --- /dev/null +++ b/utils/aflpp_driver/aflpp_qemu_driver_hook.c @@ -0,0 +1,22 @@ +#include +#include + +#define g2h(x) ((void *)((unsigned long)(x) + guest_base)) + +#define REGS_RDI 7 +#define REGS_RSI 6 + +void afl_persistent_hook(uint64_t *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_len) { + + memcpy(g2h(regs[REGS_RDI]), input_buf, input_len); + regs[REGS_RSI] = input_len; + +} + +int afl_persistent_hook_init(void) { + + return 1; + +} + diff --git a/utils/analysis_scripts/queue2csv.sh b/utils/analysis_scripts/queue2csv.sh new file mode 100755 index 00000000..2528b438 --- /dev/null +++ b/utils/analysis_scripts/queue2csv.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +test -z "$1" -o -z "$2" -o "$1" = "-h" -o "$1" = "-hh" -o "$1" = "--help" -o '!' -d "$1" && { + echo "Syntax: [-n] $0 out-directory file.csv [\"tools/target --opt @@\"]" + echo Option -n will suppress the CSV header. + echo If the target execution command is supplied then also edge coverage is gathered. + exit 1 +} + +function getval() { + VAL="" + if [ "$file" != "${file/$1/}" ]; then + TMP="${file/*$1:/}" + VAL="${TMP/,*/}" + fi +} + +SKIP= +if [ "$1" = "-n" ]; then + SKIP=1 + shift +fi + +test -n "$4" && { echo "Error: too many commandline options. Target command and options including @@ have to be passed within \"\"!"; exit 1; } + +test -d "$1"/queue && OUT="$1/queue" || OUT="$1" + +OK=`ls $OUT/id:000000,time:0,orig:* 2> /dev/null` +if [ -n "$OK" ]; then + LISTCMD="ls $OUT/id:"* +else + LISTCMD="ls -tr $OUT/" +fi + +ID=;SRC=;TIME=;OP=;POS=;REP=;EDGES=;EDGES_TOTAL=; +DIR="$OUT/../stats" +rm -rf "$DIR" +> "$2" || exit 1 +mkdir "$DIR" || exit 1 +> "$DIR/../edges.txt" || exit 1 + +{ + + if [ -z "$SKIP" ]; then + echo "time;\"filename\";id;src;new_cov;edges;total_edges;\"op\";pos;rep;unique_edges" + fi + + $LISTCMD | grep -v ,sync: | sed 's/.*id:/id:/g' | while read file; do + + if [ -n "$3" ]; then + + TMP=${3/@@/$OUT/$file} + + if [ "$TMP" = "$3" ]; then + + cat "$OUT/$file" | afl-showmap -o "$DIR/$file" -q -- $3 >/dev/null 2>&1 + + else + + afl-showmap -o "$DIR/$file" -q -- $TMP >/dev/null 2>&1 + + fi + + { cat "$DIR/$file" | sed 's/:.*//' ; cat "$DIR/../edges.txt" ; } | sort -nu > $DIR/../edges.txt.tmp + mv $DIR/../edges.txt.tmp $DIR/../edges.txt + EDGES=$(cat "$DIR/$file" | wc -l) + EDGES_TOTAL=$(cat "$DIR/../edges.txt" | wc -l) + + fi + + getval id; ID="$VAL" + getval src; SRC="$VAL" + getval time; TIME="$VAL" + getval op; OP="$VAL" + getval pos; POS="$VAL" + getval rep; REP="$VAL" + if [ "$file" != "${file/+cov/}" ]; then + COV=1 + else + COV="" + fi + + if [ -n "$3" -a -s "$DIR/../edges.txt" ]; then + echo "$TIME;\"$file\";$ID;$SRC;$COV;$EDGES;$EDGES_TOTAL;\"$OP\";$POS;$REP;UNIQUE$file" + else + echo "$TIME;\"$file\";$ID;$SRC;$COV;;;\"$OP\";$POS;$REP;" + fi + + done + +} | tee "$DIR/../queue.csv" > "$2" || exit 1 + +if [ -n "$3" -a -s "$DIR/../edges.txt" ]; then + + cat "$DIR/"* | sed 's/:.*//' | sort -n | uniq -c | egrep '^[ \t]*1 ' | awk '{print$2}' > $DIR/../unique.txt + + if [ -s "$DIR/../unique.txt" ]; then + + ls "$DIR/id:"* | grep -v ",sync:" |sed 's/.*\/id:/id:/g' | while read file; do + + CNT=$(sed 's/:.*//' "$DIR/$file" | tee "$DIR/../tmp.txt" | wc -l) + DIFF=$(diff -u "$DIR/../tmp.txt" "$DIR/../unique.txt" | egrep '^-[0-9]' | wc -l) + UNIQUE=$(($CNT - $DIFF)) + sed -i "s/;UNIQUE$file/;$UNIQUE/" "$DIR/../queue.csv" "$2" + + done + + rm -f "$DIR/../tmp.txt" + + else + + sed -i 's/;UNIQUE.*/;/' "$DIR/../queue.csv" "$2" + + fi + +fi + +mv "$DIR/../queue.csv" "$DIR/queue.csv" +if [ -e "$DIR/../edges.txt" ]; then mv "$DIR/../edges.txt" "$DIR/edges.txt"; fi +if [ -e "$DIR/../unique.txt" ]; then mv "$DIR/../unique.txt" "$DIR/unique.txt"; fi + +echo "Created $2" diff --git a/utils/argv_fuzzing/Makefile b/utils/argv_fuzzing/Makefile new file mode 100644 index 00000000..5a0ac6e6 --- /dev/null +++ b/utils/argv_fuzzing/Makefile @@ -0,0 +1,58 @@ +# +# american fuzzy lop++ - argvfuzz +# -------------------------------- +# +# Copyright 2019-2020 Kjell Braden +# +# 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 +# + +.PHONY: all install clean + +PREFIX ?= /usr/local +BIN_PATH = $(PREFIX)/bin +HELPER_PATH = $(PREFIX)/lib/afl + +CFLAGS = -fPIC -Wall -Wextra +LDFLAGS = -shared + +UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?) +UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$? + +_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=) +LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl) +LDFLAGS += $(LDFLAGS_ADD) + +# on gcc for arm there is no -m32, but -mbe32 +M32FLAG = -m32 +M64FLAG = -m64 + +CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?) +CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$? +CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?) +CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$? + +_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER) +__M32FLAG=$(_M32FLAG:00=-mbe32) +___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32) +M32FLAG=$(___M32FLAG) + +all: argvfuzz32.so argvfuzz64.so + +argvfuzz32.so: argvfuzz.c + -@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz32 build failure (that's fine)" + +argvfuzz64.so: argvfuzz.c + -@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz64 build failure (that's fine)" + +install: argvfuzz32.so argvfuzz64.so + install -d -m 755 $(DESTDIR)$(HELPER_PATH)/ + if [ -f argvfuzz32.so ]; then set -e; install -m 755 argvfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi + if [ -f argvfuzz64.so ]; then set -e; install -m 755 argvfuzz64.so $(DESTDIR)$(HELPER_PATH)/; fi + +clean: + rm -f argvfuzz32.so argvfuzz64.so diff --git a/utils/argv_fuzzing/README.md b/utils/argv_fuzzing/README.md new file mode 100644 index 00000000..fa8cad80 --- /dev/null +++ b/utils/argv_fuzzing/README.md @@ -0,0 +1,16 @@ +# argvfuzz + +afl supports fuzzing file inputs or stdin. When source is available, +`argv-fuzz-inl.h` can be used to change `main()` to build argv from stdin. + +`argvfuzz` tries to provide the same functionality for binaries. When loaded +using `LD_PRELOAD`, it will hook the call to `__libc_start_main` and replace +argv using the same logic of `argv-fuzz-inl.h`. + +A few conditions need to be fulfilled for this mechanism to work correctly: + +1. As it relies on hooking the loader, it cannot work on static binaries. +2. If the target binary does not use the default libc's `_start` implementation + (crt1.o), the hook may not run. +3. The hook will replace argv with pointers to `.data` of `argvfuzz.so`. If the + target binary expects argv to be living on the stack, things may go wrong. diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h new file mode 100644 index 00000000..c15c0271 --- /dev/null +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -0,0 +1,90 @@ +/* + american fuzzy lop++ - sample argv fuzzing wrapper + ------------------------------------------------ + + Originally written by Michal Zalewski + + Copyright 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 + + This file shows a simple way to fuzz command-line parameters with stock + afl-fuzz. To use, add: + + #include "/path/to/argv-fuzz-inl.h" + + ...to the file containing main(), ideally placing it after all the + standard includes. Next, put AFL_INIT_ARGV(); near the very beginning of + main(). + + This will cause the program to read NUL-delimited input from stdin and + put it in argv[]. Two subsequent NULs terminate the array. Empty + params are encoded as a lone 0x02. Lone 0x02 can't be generated, but + that shouldn't matter in real life. + + If you would like to always preserve argv[0], use this instead: + AFL_INIT_SET0("prog_name"); + +*/ + +#ifndef _HAVE_ARGV_FUZZ_INL +#define _HAVE_ARGV_FUZZ_INL + +#include + +#define AFL_INIT_ARGV() \ + do { \ + \ + argv = afl_init_argv(&argc); \ + \ + } while (0) + +#define AFL_INIT_SET0(_p) \ + do { \ + \ + argv = afl_init_argv(&argc); \ + argv[0] = (_p); \ + if (!argc) argc = 1; \ + \ + } while (0) + +#define MAX_CMDLINE_LEN 100000 +#define MAX_CMDLINE_PAR 50000 + +static char **afl_init_argv(int *argc) { + + static char in_buf[MAX_CMDLINE_LEN]; + static char *ret[MAX_CMDLINE_PAR]; + + char *ptr = in_buf; + int rc = 0; + + if (read(0, in_buf, MAX_CMDLINE_LEN - 2) < 0) {} + + while (*ptr && rc < MAX_CMDLINE_PAR) { + + ret[rc] = ptr; + if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++; + rc++; + + while (*ptr) + ptr++; + ptr++; + + } + + *argc = rc; + + return ret; + +} + +#undef MAX_CMDLINE_LEN +#undef MAX_CMDLINE_PAR + +#endif /* !_HAVE_ARGV_FUZZ_INL */ + diff --git a/utils/argv_fuzzing/argvfuzz.c b/utils/argv_fuzzing/argvfuzz.c new file mode 100644 index 00000000..4251ca4c --- /dev/null +++ b/utils/argv_fuzzing/argvfuzz.c @@ -0,0 +1,49 @@ +/* + american fuzzy lop++ - LD_PRELOAD for fuzzing argv in binaries + ------------------------------------------------------------ + + Copyright 2019-2020 Kjell Braden + + 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 + + */ + +#define _GNU_SOURCE /* for RTLD_NEXT */ +#include +#include +#include +#include +#include "argv-fuzz-inl.h" + +int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv, + void (*init)(void), void (*fini)(void), + void (*rtld_fini)(void), void *stack_end) { + + int (*orig)(int (*main)(int, char **, char **), int argc, char **argv, + void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), + void *stack_end); + int sub_argc; + char **sub_argv; + + (void)argc; + (void)argv; + + orig = dlsym(RTLD_NEXT, __func__); + + if (!orig) { + + fprintf(stderr, "hook did not find original %s: %s\n", __func__, dlerror()); + exit(EXIT_FAILURE); + + } + + sub_argv = afl_init_argv(&sub_argc); + + return orig(main, sub_argc, sub_argv, init, fini, rtld_fini, stack_end); + +} + diff --git a/utils/asan_cgroups/limit_memory.sh b/utils/asan_cgroups/limit_memory.sh new file mode 100755 index 00000000..1f0f04ad --- /dev/null +++ b/utils/asan_cgroups/limit_memory.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env bash +# +# american fuzzy lop++ - limit memory using cgroups +# ----------------------------------------------- +# +# Written by Samir Khakimov and +# David A. Wheeler +# +# Edits to bring the script in line with afl-cmin and other companion scripts +# by Michal Zalewski. All bugs are my fault. +# +# Copyright 2015 Institute for Defense Analyses. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# This tool allows the amount of actual memory allocated to a program +# to be limited on Linux systems using cgroups, instead of the traditional +# setrlimit() API. This helps avoid the address space problems discussed in +# docs/notes_for_asan.md. +# +# Important: the limit covers *both* afl-fuzz and the fuzzed binary. In some +# hopefully rare circumstances, afl-fuzz could be killed before the fuzzed +# task. +# + +echo "cgroup tool for afl-fuzz by and " +echo + +unset NEW_USER +MEM_LIMIT="50" + +while getopts "+u:m:" opt; do + + case "$opt" in + + "u") + NEW_USER="$OPTARG" + ;; + + "m") + MEM_LIMIT="$[OPTARG]" + ;; + + "?") + exit 1 + ;; + + esac + +done + +if [ "$MEM_LIMIT" -lt "5" ]; then + echo "[-] Error: malformed or dangerously low value of -m." 1>&2 + exit 1 +fi + +shift $((OPTIND-1)) + +TARGET_BIN="$1" + +if [ "$TARGET_BIN" = "" -o "$NEW_USER" = "" ]; then + + cat 1>&2 <<_EOF_ +Usage: $0 [ options ] -- /path/to/afl-fuzz [ ...afl options... ] + +Required parameters: + + -u user - run the fuzzer as a specific user after setting up limits + +Optional parameters: + + -m megs - set memory limit to a specified value ($MEM_LIMIT MB) + +This tool configures cgroups-based memory limits for a fuzzing job to simplify +the task of fuzzing ASAN or MSAN binaries. You would normally want to use it in +conjunction with '-m none' passed to the afl-fuzz binary itself, say: + + $0 -u joe ./afl-fuzz -i input -o output -m none /path/to/target + +_EOF_ + + exit 1 + +fi + +# Basic sanity checks + +if [ ! "`uname -s`" = "Linux" ]; then + echo "[-] Error: this tool does not support non-Linux systems." 1>&2 + exit 1 +fi + +if [ ! "`id -u`" = "0" ]; then + echo "[-] Error: you need to run this script as root (sorry!)." 1>&2 + exit 1 +fi + +if ! type cgcreate 2>/dev/null 1>&2; then + + echo "[-] Error: you need to install cgroup tools first." 1>&2 + + if type apt-get 2>/dev/null 1>&2; then + echo " (Perhaps 'apt-get install cgroup-bin' will work.)" 1>&2 + elif type yum 2>/dev/null 1>&2; then + echo " (Perhaps 'yum install libcgroup-tools' will work.)" 1>&2 + fi + + exit 1 + +fi + +if ! id -u "$NEW_USER" 2>/dev/null 1>&2; then + echo "[-] Error: user '$NEW_USER' does not seem to exist." 1>&2 + exit 1 +fi + +# Create a new cgroup path if necessary... We used PID-keyed groups to keep +# parallel afl-fuzz tasks separate from each other. + +CID="afl-$NEW_USER-$$" + +CPATH="/sys/fs/cgroup/memory/$CID" + +if [ ! -d "$CPATH" ]; then + + cgcreate -a "$NEW_USER" -g memory:"$CID" || exit 1 + +fi + +# Set the appropriate limit... + +if [ -f "$CPATH/memory.memsw.limit_in_bytes" ]; then + + echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" 2>/dev/null + echo "${MEM_LIMIT}M" > "$CPATH/memory.memsw.limit_in_bytes" || exit 1 + echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1 + +elif grep -qE 'partition|file' /proc/swaps; then + + echo "[-] Error: your system requires swap to be disabled first (swapoff -a)." 1>&2 + exit 1 + +else + + echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1 + +fi + +# All right. At this point, we can just run the command. + +cgexec -g "memory:$CID" su -c "$*" "$NEW_USER" + +cgdelete -g "memory:$CID" diff --git a/utils/bash_shellshock/shellshock-fuzz.diff b/utils/bash_shellshock/shellshock-fuzz.diff new file mode 100644 index 00000000..3fa05bf8 --- /dev/null +++ b/utils/bash_shellshock/shellshock-fuzz.diff @@ -0,0 +1,59 @@ +This patch shows a very simple way to find post-Shellshock bugs in bash, as +discussed here: + + http://lcamtuf.blogspot.com/2014/10/bash-bug-how-we-finally-cracked.html + +In essence, it shows a way to fuzz environmental variables. Instructions: + +1) Download bash 4.3, apply this patch, compile with: + + CC=/path/to/afl-gcc ./configure + make clean all + + Note that the harness puts the fuzzed output in $TEST_VARIABLE. With + Florian's Shellshock patch (bash43-028), this is no longer passed down + to the parser. + +2) Create and cd to an empty directory, put the compiled bash binary in + there, and run these commands: + + mkdir in_dir + echo -n '() { a() { a; }; : >b; }' >in_dir/script.txt + +3) Run the fuzzer with: + + /path/to/afl-fuzz -d -i in_dir -o out_dir ./bash -c : + + The -d parameter is advisable only if the tested shell is fairly slow + or if you are in a hurry; will cover more ground faster, but + less systematically. + +4) Watch for crashes in out_dir/crashes/. Also watch for any new files + created in cwd if you're interested in non-crash RCEs (files will be + created whenever the shell executes "foo>bar" or something like + that). You can correlate their creation date with new entries in + out_dir/queue/. + + You can also modify the bash binary to directly check for more subtle + fault conditions, or use the synthesized entries in out_dir/queue/ + as a seed for other, possibly slower or more involved testing regimes. + + Expect several hours to get decent coverage. + +--- bash-4.3/shell.c.orig 2014-01-14 14:04:32.000000000 +0100 ++++ bash-4.3/shell.c 2015-04-30 05:56:46.000000000 +0200 +@@ -371,6 +371,14 @@ + env = environ; + #endif /* __OPENNT */ + ++ { ++ ++ static char val[1024 * 16]; ++ read(0, val, sizeof(val) - 1); ++ setenv("TEST_VARIABLE", val, 1); ++ ++ } ++ + USE_VAR(argc); + USE_VAR(argv); + USE_VAR(env); diff --git a/utils/canvas_harness/canvas_harness.html b/utils/canvas_harness/canvas_harness.html new file mode 100644 index 00000000..a37b6937 --- /dev/null +++ b/utils/canvas_harness/canvas_harness.html @@ -0,0 +1,170 @@ + + + + + +
    + +
    + + + +

    Results

    + +
      + + + + diff --git a/utils/clang_asm_normalize/as b/utils/clang_asm_normalize/as new file mode 100755 index 00000000..45537cae --- /dev/null +++ b/utils/clang_asm_normalize/as @@ -0,0 +1,75 @@ +#!/bin/sh +# +# american fuzzy lop++ - clang assembly normalizer +# ---------------------------------------------- +# +# Originally written by Michal Zalewski +# The idea for this wrapper comes from Ryan Govostes. +# +# Copyright 2013, 2014 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 +# +# This 'as' wrapper should allow you to instrument unruly, hand-written +# assembly with afl-as. +# +# Usage: +# +# export AFL_REAL_PATH=/path/to/directory/with/afl-as/ +# AFL_PATH=/path/to/this/directory/ make clean all + +if [ "$#" -lt "2" ]; then + echo "[-] Error: this utility can't be called directly." 1>&2 + exit 1 +fi + +if [ "$AFL_REAL_PATH" = "" ]; then + echo "[-] Error: AFL_REAL_PATH not set!" 1>&2 + exit 1 +fi + +if [ ! -x "$AFL_REAL_PATH/afl-as" ]; then + echo "[-] Error: AFL_REAL_PATH does not contain the 'afl-as' binary." 1>&2 + exit 1 +fi + +unset __AFL_AS_CMDLINE __AFL_FNAME + +while [ ! "$#" = "0" ]; do + + if [ "$#" = "1" ]; then + __AFL_FNAME="$1" + else + __AFL_AS_CMDLINE="${__AFL_AS_CMDLINE} $1" + fi + + shift + +done + +test "$TMPDIR" = "" && TMPDIR=/tmp + +TMPFILE=`mktemp $TMPDIR/.afl-XXXXXXXXXX.s` + +test "$TMPFILE" = "" && exit 1 + +clang -cc1as -filetype asm -output-asm-variant 0 "${__AFL_FNAME}" >"$TMPFILE" + +ERR="$?" + +if [ ! "$ERR" = "0" ]; then + rm -f "$TMPFILE" + exit $ERR +fi + +"$AFL_REAL_PATH/afl-as" ${__AFL_AS_CMDLINE} "$TMPFILE" + +ERR="$?" + +rm -f "$TMPFILE" + +exit "$ERR" diff --git a/utils/crash_triage/triage_crashes.sh b/utils/crash_triage/triage_crashes.sh new file mode 100755 index 00000000..bf763cba --- /dev/null +++ b/utils/crash_triage/triage_crashes.sh @@ -0,0 +1,115 @@ +#!/bin/sh +# +# american fuzzy lop++ - crash triage utility +# ----------------------------------------- +# +# Originally written by Michal Zalewski +# +# Copyright 2013, 2014, 2017 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 +# +# Note that this assumes that the targeted application reads from stdin +# and requires no other cmdline parameters. Modify as needed if this is +# not the case. +# +# Note that on OpenBSD, you may need to install a newer version of gdb +# (e.g., from ports). You can set GDB=/some/path to point to it if +# necessary. +# + +echo "crash triage utility for afl-fuzz by Michal Zalewski" +echo + +ulimit -v 100000 2>/dev/null +ulimit -d 100000 2>/dev/null + +if [ "$#" -lt "2" ]; then + echo "Usage: $0 /path/to/afl_output_dir /path/to/tested_binary [...target params...]" 1>&2 + echo 1>&2 + exit 1 +fi + +DIR="$1" +BIN="$2" +shift +shift + +if [ "$AFL_ALLOW_TMP" = "" ]; then + + echo "$DIR" | grep -qE '^(/var)?/tmp/' + T1="$?" + + echo "$BIN" | grep -qE '^(/var)?/tmp/' + T2="$?" + + if [ "$T1" = "0" -o "$T2" = "0" ]; then + echo "[-] Error: do not use shared /tmp or /var/tmp directories with this script." 1>&2 + exit 1 + fi + +fi + +if + [ "$GDB" = "" ]; then + GDB=gdb +fi + +if [ ! -f "$BIN" -o ! -x "$BIN" ]; then + echo "[-] Error: binary '$2' not found or is not executable." 1>&2 + exit 1 +fi + +if [ ! -d "$DIR/queue" ]; then + echo "[-] Error: directory '$1' not found or not created by afl-fuzz." 1>&2 + exit 1 +fi + +CCOUNT=$((`ls -- "$DIR/crashes" 2>/dev/null | wc -l`)) + +if [ "$CCOUNT" = "0" ]; then + echo "No crashes recorded in the target directory - nothing to be done." + exit 0 +fi + +echo + +for crash in $DIR/crashes/id:*; do + + id=`basename -- "$crash" | cut -d, -f1 | cut -d: -f2` + sig=`basename -- "$crash" | cut -d, -f2 | cut -d: -f2` + + # Grab the args, converting @@ to $crash + + use_args="" + use_stdio=1 + + for a in $@; do + + if [ "$a" = "@@" ] ; then + use_args="$use_args $crash" + unset use_stdio + else + use_args="$use_args $a" + fi + + done + + # Strip the trailing space + use_args="${use_args# }" + + echo "+++ ID $id, SIGNAL $sig +++" + echo + + if [ "$use_stdio" = "1" ]; then + $GDB --batch -q --ex "r $use_args <$crash" --ex 'back' --ex 'disass $pc, $pc+16' --ex 'info reg' --ex 'quit' "$BIN" 0 + +#define INITIAL_GROWTH_SIZE (64) + +#define RAND_BELOW(limit) (rand() % (limit)) + +/* Use in a struct: creates a name_buf and a name_size variable. */ +#define BUF_VAR(type, name) \ + type * name##_buf; \ + size_t name##_size; +/* this fills in `&structptr->something_buf, &structptr->something_size`. */ +#define BUF_PARAMS(struct, name) \ + (void **)&struct->name##_buf, &struct->name##_size + +typedef struct { + +} afl_t; + +static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) { + + static s8 interesting_8[] = {INTERESTING_8}; + static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16}; + static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32}; + + switch (RAND_BELOW(12)) { + + case 0: { + + /* Flip a single bit somewhere. Spooky! */ + + s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8); + + out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7); + + break; + + } + + case 1: { + + /* Set byte to interesting value. */ + + u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))]; + out_buf[(RAND_BELOW(end - begin) + begin)] = val; + + break; + + } + + case 2: { + + /* Set word to interesting value, randomly choosing endian. */ + + if (end - begin < 2) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 1) break; + + switch (RAND_BELOW(2)) { + + case 0: + *(u16 *)(out_buf + byte_idx) = + interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]; + break; + case 1: + *(u16 *)(out_buf + byte_idx) = + SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]); + break; + + } + + break; + + } + + case 3: { + + /* Set dword to interesting value, randomly choosing endian. */ + + if (end - begin < 4) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 3) break; + + switch (RAND_BELOW(2)) { + + case 0: + *(u32 *)(out_buf + byte_idx) = + interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; + break; + case 1: + *(u32 *)(out_buf + byte_idx) = + SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); + break; + + } + + break; + + } + + case 4: { + + /* Set qword to interesting value, randomly choosing endian. */ + + if (end - begin < 8) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 7) break; + + switch (RAND_BELOW(2)) { + + case 0: + *(u64 *)(out_buf + byte_idx) = + (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; + break; + case 1: + *(u64 *)(out_buf + byte_idx) = SWAP64( + (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); + break; + + } + + break; + + } + + case 5: { + + /* Randomly subtract from byte. */ + + out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX); + + break; + + } + + case 6: { + + /* Randomly add to byte. */ + + out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX); + + break; + + } + + case 7: { + + /* Randomly subtract from word, random endian. */ + + if (end - begin < 2) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 1) break; + + if (RAND_BELOW(2)) { + + *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u16 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u16 *)(out_buf + byte_idx) = + SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num); + + } + + break; + + } + + case 8: { + + /* Randomly add to word, random endian. */ + + if (end - begin < 2) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 1) break; + + if (RAND_BELOW(2)) { + + *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u16 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u16 *)(out_buf + byte_idx) = + SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num); + + } + + break; + + } + + case 9: { + + /* Randomly subtract from dword, random endian. */ + + if (end - begin < 4) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 3) break; + + if (RAND_BELOW(2)) { + + *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u32 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u32 *)(out_buf + byte_idx) = + SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num); + + } + + break; + + } + + case 10: { + + /* Randomly add to dword, random endian. */ + + if (end - begin < 4) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 3) break; + + if (RAND_BELOW(2)) { + + *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u32 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u32 *)(out_buf + byte_idx) = + SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num); + + } + + break; + + } + + case 11: { + + /* Just set a random byte to a random value. Because, + why not. We use XOR with 1-255 to eliminate the + possibility of a no-op. */ + + out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255); + + break; + + } + + } + +} + +/* This function calculates the next power of 2 greater or equal its argument. + @return The rounded up power of 2 (if no overflow) or 0 on overflow. +*/ +static inline size_t next_pow2(size_t in) { + + if (in == 0 || in > (size_t)-1) + return 0; /* avoid undefined behaviour under-/overflow */ + size_t out = in - 1; + out |= out >> 1; + out |= out >> 2; + out |= out >> 4; + out |= out >> 8; + out |= out >> 16; + return out + 1; + +} + +/* This function makes sure *size is > size_needed after call. + It will realloc *buf otherwise. + *size will grow exponentially as per: + https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ + Will return NULL and free *buf if size_needed is <1 or realloc failed. + @return For convenience, this function returns *buf. + */ +static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { + + /* No need to realloc */ + if (likely(size_needed && *size >= size_needed)) return *buf; + + /* No initial size was set */ + if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE; + + /* grow exponentially */ + size_t next_size = next_pow2(size_needed); + + /* handle overflow */ + if (!next_size) { next_size = size_needed; } + + /* alloc */ + *buf = realloc(*buf, next_size); + *size = *buf ? next_size : 0; + + return *buf; + +} + +/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ +static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2, + size_t *size2) { + + void * scratch_buf = *buf1; + size_t scratch_size = *size1; + *buf1 = *buf2; + *size1 = *size2; + *buf2 = scratch_buf; + *size2 = scratch_size; + +} + +#undef INITIAL_GROWTH_SIZE + +#endif + diff --git a/utils/custom_mutators/example.c b/utils/custom_mutators/example.c new file mode 100644 index 00000000..23add128 --- /dev/null +++ b/utils/custom_mutators/example.c @@ -0,0 +1,376 @@ +/* + New Custom Mutator for AFL++ + Written by Khaled Yakdan + Andrea Fioraldi + Shengtuo Hu + Dominik Maier +*/ + +// You need to use -I /path/to/AFLplusplus/include +#include "custom_mutator_helpers.h" + +#include +#include +#include +#include + +#define DATA_SIZE (100) + +static const char *commands[] = { + + "GET", + "PUT", + "DEL", + +}; + +typedef struct my_mutator { + + afl_t *afl; + + // any additional data here! + size_t trim_size_current; + int trimmming_steps; + int cur_step; + + // Reused buffers: + BUF_VAR(u8, fuzz); + BUF_VAR(u8, data); + BUF_VAR(u8, havoc); + BUF_VAR(u8, trim); + BUF_VAR(u8, post_process); + +} my_mutator_t; + +/** + * Initialize this custom mutator + * + * @param[in] afl a pointer to the internal state object. Can be ignored for + * now. + * @param[in] seed A seed for this mutator - the same seed should always mutate + * in the same way. + * @return Pointer to the data object this custom mutator instance should use. + * There may be multiple instances of this mutator in one afl-fuzz run! + * Return NULL on error. + */ +my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { + + srand(seed); // needed also by surgical_havoc_mutate() + + my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); + if (!data) { + + perror("afl_custom_init alloc"); + return NULL; + + } + + data->afl = afl; + + return data; + +} + +/** + * Perform custom mutations on a given input + * + * (Optional for now. Required in the future) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Pointer to input data to be mutated + * @param[in] buf_size Size of input data + * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on + * error. + * @param[in] add_buf Buffer containing the additional test case + * @param[in] add_buf_size Size of the additional test case + * @param[in] max_size Maximum size of the mutated output. The mutation must not + * produce data larger than max_size. + * @return Size of the mutated output. + */ +size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, + u8 **out_buf, uint8_t *add_buf, + size_t add_buf_size, // add_buf can be NULL + size_t max_size) { + + // Make sure that the packet size does not exceed the maximum size expected by + // the fuzzer + size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size; + + // maybe_grow is optimized to be quick for reused buffers. + u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size); + if (!mutated_out) { + + *out_buf = NULL; + perror("custom mutator allocation (maybe_grow)"); + return 0; /* afl-fuzz will very likely error out after this. */ + + } + + // Randomly select a command string to add as a header to the packet + memcpy(mutated_out, commands[rand() % 3], 3); + + // Mutate the payload of the packet + int i; + for (i = 0; i < 8; ++i) { + + // Randomly perform one of the (no len modification) havoc mutations + surgical_havoc_mutate(mutated_out, 3, mutated_size); + + } + + *out_buf = mutated_out; + return mutated_size; + +} + +/** + * A post-processing function to use right before AFL writes the test case to + * disk in order to execute the target. + * + * (Optional) If this functionality is not needed, simply don't define this + * function. + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Buffer containing the test case to be executed + * @param[in] buf_size Size of the test case + * @param[out] out_buf Pointer to the buffer containing the test case after + * processing. External library should allocate memory for out_buf. + * The buf pointer may be reused (up to the given buf_size); + * @return Size of the output buffer after processing or the needed amount. + * A return of 0 indicates an error. + */ +size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf, + size_t buf_size, uint8_t **out_buf) { + + uint8_t *post_process_buf = + maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5); + if (!post_process_buf) { + + perror("custom mutator realloc failed."); + *out_buf = NULL; + return 0; + + } + + memcpy(post_process_buf + 5, buf, buf_size); + post_process_buf[0] = 'A'; + post_process_buf[1] = 'F'; + post_process_buf[2] = 'L'; + post_process_buf[3] = '+'; + post_process_buf[4] = '+'; + + *out_buf = post_process_buf; + + return buf_size + 5; + +} + +/** + * This method is called at the start of each trimming operation and receives + * the initial buffer. It should return the amount of iteration steps possible + * on this input (e.g. if your input has n elements and you want to remove + * them one by one, return n, if you do a binary search, return log(n), + * and so on...). + * + * If your trimming algorithm doesn't allow you to determine the amount of + * (remaining) steps easily (esp. while running), then you can alternatively + * return 1 here and always return 0 in post_trim until you are finished and + * no steps remain. In that case, returning 1 in post_trim will end the + * trimming routine. The whole current index/max iterations stuff is only used + * to show progress. + * + * (Optional) + * + * @param data pointer returned in afl_custom_init for this fuzz case + * @param buf Buffer containing the test case + * @param buf_size Size of the test case + * @return The amount of possible iteration steps to trim the input. + * negative on error. + */ +int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, + size_t buf_size) { + + // We simply trim once + data->trimmming_steps = 1; + + data->cur_step = 0; + + if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) { + + perror("init_trim grow"); + return -1; + + } + + memcpy(data->trim_buf, buf, buf_size); + + data->trim_size_current = buf_size; + + return data->trimmming_steps; + +} + +/** + * This method is called for each trimming operation. It doesn't have any + * arguments because we already have the initial buffer from init_trim and we + * can memorize the current state in *data. This can also save + * reparsing steps for each iteration. It should return the trimmed input + * buffer, where the returned data must not exceed the initial input data in + * length. Returning anything that is larger than the original data (passed + * to init_trim) will result in a fatal abort of AFLFuzz. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[out] out_buf Pointer to the buffer containing the trimmed test case. + * External library should allocate memory for out_buf. + * AFL++ will not release the memory after saving the test case. + * Keep a ref in *data. + * *out_buf = NULL is treated as error. + * @return Pointer to the size of the trimmed test case + */ +size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) { + + *out_buf = data->trim_buf; + + // Remove the last byte of the trimming input + return data->trim_size_current - 1; + +} + +/** + * This method is called after each trim operation to inform you if your + * trimming step was successful or not (in terms of coverage). If you receive + * a failure here, you should reset your input to the last known good state. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param success Indicates if the last trim operation was successful. + * @return The next trim iteration index (from 0 to the maximum amount of + * steps returned in init_trim). negative ret on failure. + */ +int32_t afl_custom_post_trim(my_mutator_t *data, int success) { + + if (success) { + + ++data->cur_step; + return data->cur_step; + + } + + return data->trimmming_steps; + +} + +/** + * Perform a single custom mutation on a given input. + * This mutation is stacked with the other muatations in havoc. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Pointer to the input data to be mutated and the mutated + * output + * @param[in] buf_size Size of input data + * @param[out] out_buf The output buffer. buf can be reused, if the content + * fits. *out_buf = NULL is treated as error. + * @param[in] max_size Maximum size of the mutated output. The mutation must + * not produce data larger than max_size. + * @return Size of the mutated output. + */ +size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size, + u8 **out_buf, size_t max_size) { + + if (buf_size == 0) { + + *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1); + if (!*out_buf) { + + perror("custom havoc: maybe_grow"); + return 0; + + } + + **out_buf = rand() % 256; + buf_size = 1; + + } else { + + // We reuse buf here. It's legal and faster. + *out_buf = buf; + + } + + size_t victim = rand() % buf_size; + (*out_buf)[victim] += rand() % 10; + + return buf_size; + +} + +/** + * Return the probability (in percentage) that afl_custom_havoc_mutation + * is called in havoc. By default it is 6 %. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @return The probability (0-100). + */ +uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) { + + return 5; // 5 % + +} + +/** + * Determine whether the fuzzer should fuzz the queue entry or not. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param filename File name of the test case in the queue entry + * @return Return True(1) if the fuzzer will fuzz the queue entry, and + * False(0) otherwise. + */ +uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) { + + return 1; + +} + +/** + * Allow for additional analysis (e.g. calling a different tool that does a + * different kind of coverage and saves this for the custom mutator). + * + * (Optional) + * + * @param data pointer returned in afl_custom_init for this fuzz case + * @param filename_new_queue File name of the new queue entry + * @param filename_orig_queue File name of the original queue entry + */ +void afl_custom_queue_new_entry(my_mutator_t * data, + const uint8_t *filename_new_queue, + const uint8_t *filename_orig_queue) { + + /* Additional analysis on the original or new test case */ + +} + +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +void afl_custom_deinit(my_mutator_t *data) { + + free(data->post_process_buf); + free(data->havoc_buf); + free(data->data_buf); + free(data->fuzz_buf); + free(data->trim_buf); + free(data); + +} + diff --git a/utils/custom_mutators/example.py b/utils/custom_mutators/example.py new file mode 100644 index 00000000..cf659e5a --- /dev/null +++ b/utils/custom_mutators/example.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +# encoding: utf-8 +''' +Example Python Module for AFLFuzz + +@author: Christian Holler (:decoder) + +@license: + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@contact: choller@mozilla.com +''' + +import random + + +COMMANDS = [ + b"GET", + b"PUT", + b"DEL", + b"AAAAAAAAAAAAAAAAA", +] + + +def init(seed): + ''' + Called once when AFLFuzz starts up. Used to seed our RNG. + + @type seed: int + @param seed: A 32-bit random value + ''' + random.seed(seed) + + +def deinit(): + pass + + +def fuzz(buf, add_buf, max_size): + ''' + Called per fuzzing iteration. + + @type buf: bytearray + @param buf: The buffer that should be mutated. + + @type add_buf: bytearray + @param add_buf: A second buffer that can be used as mutation source. + + @type max_size: int + @param max_size: Maximum size of the mutated output. The mutation must not + produce data larger than max_size. + + @rtype: bytearray + @return: A new bytearray containing the mutated data + ''' + ret = bytearray(100) + + ret[:3] = random.choice(COMMANDS) + + return ret + +# Uncomment and implement the following methods if you want to use a custom +# trimming algorithm. See also the documentation for a better API description. + +# def init_trim(buf): +# ''' +# Called per trimming iteration. +# +# @type buf: bytearray +# @param buf: The buffer that should be trimmed. +# +# @rtype: int +# @return: The maximum number of trimming steps. +# ''' +# global ... +# +# # Initialize global variables +# +# # Figure out how many trimming steps are possible. +# # If this is not possible for your trimming, you can +# # return 1 instead and always return 0 in post_trim +# # until you are done (then you return 1). +# +# return steps +# +# def trim(): +# ''' +# Called per trimming iteration. +# +# @rtype: bytearray +# @return: A new bytearray containing the trimmed data. +# ''' +# global ... +# +# # Implement the actual trimming here +# +# return bytearray(...) +# +# def post_trim(success): +# ''' +# Called after each trimming operation. +# +# @type success: bool +# @param success: Indicates if the last trim operation was successful. +# +# @rtype: int +# @return: The next trim index (0 to max number of steps) where max +# number of steps indicates the trimming is done. +# ''' +# global ... +# +# if not success: +# # Restore last known successful input, determine next index +# else: +# # Just determine the next index, based on what was successfully +# # removed in the last step +# +# return next_index +# +# def post_process(buf): +# ''' +# Called just before the execution to write the test case in the format +# expected by the target +# +# @type buf: bytearray +# @param buf: The buffer containing the test case to be executed +# +# @rtype: bytearray +# @return: The buffer containing the test case after +# ''' +# return buf +# +# def havoc_mutation(buf, max_size): +# ''' +# Perform a single custom mutation on a given input. +# +# @type buf: bytearray +# @param buf: The buffer that should be mutated. +# +# @type max_size: int +# @param max_size: Maximum size of the mutated output. The mutation must not +# produce data larger than max_size. +# +# @rtype: bytearray +# @return: A new bytearray containing the mutated data +# ''' +# return mutated_buf +# +# def havoc_mutation_probability(): +# ''' +# Called for each `havoc_mutation`. Return the probability (in percentage) +# that `havoc_mutation` is called in havoc. Be default it is 6%. +# +# @rtype: int +# @return: The probability (0-100) +# ''' +# return prob +# +# def queue_get(filename): +# ''' +# Called at the beginning of each fuzz iteration to determine whether the +# test case should be fuzzed +# +# @type filename: str +# @param filename: File name of the test case in the current queue entry +# +# @rtype: bool +# @return: Return True if the custom mutator decides to fuzz the test case, +# and False otherwise +# ''' +# return True +# +# def queue_new_entry(filename_new_queue, filename_orig_queue): +# ''' +# Called after adding a new test case to the queue +# +# @type filename_new_queue: str +# @param filename_new_queue: File name of the new queue entry +# +# @type filename_orig_queue: str +# @param filename_orig_queue: File name of the original queue entry +# ''' +# pass diff --git a/utils/custom_mutators/post_library_gif.so.c b/utils/custom_mutators/post_library_gif.so.c new file mode 100644 index 00000000..ac10f409 --- /dev/null +++ b/utils/custom_mutators/post_library_gif.so.c @@ -0,0 +1,165 @@ +/* + american fuzzy lop++ - postprocessor library example + -------------------------------------------------- + + Originally written by Michal Zalewski + Edited by Dominik Maier, 2020 + + Copyright 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 + + Postprocessor libraries can be passed to afl-fuzz to perform final cleanup + of any mutated test cases - for example, to fix up checksums in PNG files. + + Please heed the following warnings: + + 1) In almost all cases, it is more productive to comment out checksum logic + in the targeted binary (as shown in ../libpng_no_checksum/). One possible + exception is the process of fuzzing binary-only software in QEMU mode. + + 2) The use of postprocessors for anything other than checksums is + questionable and may cause more harm than good. AFL is normally pretty good + about dealing with length fields, magic values, etc. + + 3) Postprocessors that do anything non-trivial must be extremely robust to + gracefully handle malformed data and other error conditions - otherwise, + they will crash and take afl-fuzz down with them. Be wary of reading past + *len and of integer overflows when calculating file offsets. + + In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really, + honestly know what you're doing =) + + With that out of the way: the postprocessor library is passed to afl-fuzz + via AFL_POST_LIBRARY. The library must be compiled with: + + gcc -shared -Wall -O3 post_library.so.c -o post_library.so + + AFL will call the afl_custom_post_process() function for every mutated output + buffer. From there, you have three choices: + + 1) If you don't want to modify the test case, simply set `*out_buf = in_buf` + and return the original `len`. + + 2) If you want to skip this test case altogether and have AFL generate a + new one, return 0 or set `*out_buf = NULL`. + Use this sparingly - it's faster than running the target program + with patently useless inputs, but still wastes CPU time. + + 3) If you want to modify the test case, allocate an appropriately-sized + buffer, move the data into that buffer, make the necessary changes, and + then return the new pointer as out_buf. Return an appropriate len + afterwards. + + Note that the buffer will *not* be freed for you. To avoid memory leaks, + you need to free it or reuse it on subsequent calls (as shown below). + + *** Feel free to reuse the original 'in_buf' BUFFER and return it. *** + + Aight. The example below shows a simple postprocessor that tries to make + sure that all input files start with "GIF89a". + + PS. If you don't like C, you can try out the unix-based wrapper from + Ben Nagy instead: https://github.com/bnagy/aflfix + + */ + +#include +#include +#include + +/* Header that must be present at the beginning of every test case: */ + +#define HEADER "GIF89a" + +typedef struct post_state { + + unsigned char *buf; + size_t size; + +} post_state_t; + +void *afl_custom_init(void *afl) { + + post_state_t *state = malloc(sizeof(post_state_t)); + if (!state) { + + perror("malloc"); + return NULL; + + } + + state->buf = calloc(sizeof(unsigned char), 4096); + if (!state->buf) { + + free(state); + perror("calloc"); + return NULL; + + } + + return state; + +} + +/* The actual postprocessor routine called by afl-fuzz: */ + +size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf, + unsigned int len, unsigned char **out_buf) { + + /* Skip execution altogether for buffers shorter than 6 bytes (just to + show how it's done). We can trust len to be sane. */ + + if (len < strlen(HEADER)) return 0; + + /* Do nothing for buffers that already start with the expected header. */ + + if (!memcmp(in_buf, HEADER, strlen(HEADER))) { + + *out_buf = in_buf; + return len; + + } + + /* Allocate memory for new buffer, reusing previous allocation if + possible. */ + + *out_buf = realloc(data->buf, len); + + /* If we're out of memory, the most graceful thing to do is to return the + original buffer and give up on modifying it. Let AFL handle OOM on its + own later on. */ + + if (!*out_buf) { + + *out_buf = in_buf; + return len; + + } + + /* Copy the original data to the new location. */ + + memcpy(*out_buf, in_buf, len); + + /* Insert the new header. */ + + memcpy(*out_buf, HEADER, strlen(HEADER)); + + /* Return the new len. It hasn't changed, so it's just len. */ + + return len; + +} + +/* Gets called afterwards */ +void afl_custom_deinit(post_state_t *data) { + + free(data->buf); + free(data); + +} + diff --git a/utils/custom_mutators/post_library_png.so.c b/utils/custom_mutators/post_library_png.so.c new file mode 100644 index 00000000..941f7e55 --- /dev/null +++ b/utils/custom_mutators/post_library_png.so.c @@ -0,0 +1,163 @@ +/* + american fuzzy lop++ - postprocessor for PNG + ------------------------------------------ + + Originally written by Michal Zalewski + + Copyright 2015 Google Inc. All rights reserved. + Adapted to the new API, 2020 by Dominik Maier + + 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 + + See post_library.so.c for a general discussion of how to implement + postprocessors. This specific postprocessor attempts to fix up PNG + checksums, providing a slightly more complicated example than found + in post_library.so.c. + + Compile with: + + gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz + + */ + +#include +#include +#include +#include +#include + +#include + +/* A macro to round an integer up to 4 kB. */ + +#define UP4K(_i) ((((_i) >> 12) + 1) << 12) + +typedef struct post_state { + + unsigned char *buf; + size_t size; + +} post_state_t; + +void *afl_custom_init(void *afl) { + + post_state_t *state = malloc(sizeof(post_state_t)); + if (!state) { + + perror("malloc"); + return NULL; + + } + + state->buf = calloc(sizeof(unsigned char), 4096); + if (!state->buf) { + + free(state); + perror("calloc"); + return NULL; + + } + + return state; + +} + +size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf, + unsigned int len, + const unsigned char **out_buf) { + + unsigned char *new_buf = (unsigned char *)in_buf; + unsigned int pos = 8; + + /* Don't do anything if there's not enough room for the PNG header + (8 bytes). */ + + if (len < 8) { + + *out_buf = in_buf; + return len; + + } + + /* Minimum size of a zero-length PNG chunk is 12 bytes; if we + don't have that, we can bail out. */ + + while (pos + 12 <= len) { + + unsigned int chunk_len, real_cksum, file_cksum; + + /* Chunk length is the first big-endian dword in the chunk. */ + + chunk_len = ntohl(*(uint32_t *)(in_buf + pos)); + + /* Bail out if chunk size is too big or goes past EOF. */ + + if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break; + + /* Chunk checksum is calculated for chunk ID (dword) and the actual + payload. */ + + real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4)); + + /* The in-file checksum is the last dword past the chunk data. */ + + file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len); + + /* If the checksums do not match, we need to fix the file. */ + + if (real_cksum != file_cksum) { + + /* First modification? Make a copy of the input buffer. Round size + up to 4 kB to minimize the number of reallocs needed. */ + + if (new_buf == in_buf) { + + if (len <= data->size) { + + new_buf = data->buf; + + } else { + + new_buf = realloc(data->buf, UP4K(len)); + if (!new_buf) { + + *out_buf = in_buf; + return len; + + } + + data->buf = new_buf; + data->size = UP4K(len); + memcpy(new_buf, in_buf, len); + + } + + } + + *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum; + + } + + /* Skip the entire chunk and move to the next one. */ + + pos += 12 + chunk_len; + + } + + *out_buf = new_buf; + return len; + +} + +/* Gets called afterwards */ +void afl_custom_deinit(post_state_t *data) { + + free(data->buf); + free(data); + +} + diff --git a/utils/custom_mutators/simple-chunk-replace.py b/utils/custom_mutators/simple-chunk-replace.py new file mode 100644 index 00000000..df2f4ca7 --- /dev/null +++ b/utils/custom_mutators/simple-chunk-replace.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# encoding: utf-8 +''' +Simple Chunk Cross-Over Replacement Module for AFLFuzz + +@author: Christian Holler (:decoder) + +@license: + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@contact: choller@mozilla.com +''' + +import random + + +def init(seed): + ''' + Called once when AFLFuzz starts up. Used to seed our RNG. + + @type seed: int + @param seed: A 32-bit random value + ''' + # Seed our RNG + random.seed(seed) + + +def fuzz(buf, add_buf, max_size): + ''' + Called per fuzzing iteration. + + @type buf: bytearray + @param buf: The buffer that should be mutated. + + @type add_buf: bytearray + @param add_buf: A second buffer that can be used as mutation source. + + @type max_size: int + @param max_size: Maximum size of the mutated output. The mutation must not + produce data larger than max_size. + + @rtype: bytearray + @return: A new bytearray containing the mutated data + ''' + # Make a copy of our input buffer for returning + ret = bytearray(buf) + + # Take a random fragment length between 2 and 32 (or less if add_buf is shorter) + fragment_len = random.randint(1, min(len(add_buf), 32)) + + # Determine a random source index where to take the data chunk from + rand_src_idx = random.randint(0, len(add_buf) - fragment_len) + + # Determine a random destination index where to put the data chunk + rand_dst_idx = random.randint(0, len(buf)) + + # Make the chunk replacement + ret[rand_dst_idx:rand_dst_idx + fragment_len] = add_buf[rand_src_idx:rand_src_idx + fragment_len] + + # Return data + return ret diff --git a/utils/custom_mutators/simple_example.c b/utils/custom_mutators/simple_example.c new file mode 100644 index 00000000..d888ec1f --- /dev/null +++ b/utils/custom_mutators/simple_example.c @@ -0,0 +1,74 @@ +// This simple example just creates random buffer <= 100 filled with 'A' +// needs -I /path/to/AFLplusplus/include +#include "custom_mutator_helpers.h" + +#include +#include +#include +#include + +#ifndef _FIXED_CHAR + #define _FIXED_CHAR 0x41 +#endif + +typedef struct my_mutator { + + afl_t *afl; + + // Reused buffers: + BUF_VAR(u8, fuzz); + +} my_mutator_t; + +my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { + + srand(seed); + my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); + if (!data) { + + perror("afl_custom_init alloc"); + return NULL; + + } + + data->afl = afl; + + return data; + +} + +size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, + u8 **out_buf, uint8_t *add_buf, + size_t add_buf_size, // add_buf can be NULL + size_t max_size) { + + int size = (rand() % 100) + 1; + if (size > max_size) size = max_size; + u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size); + if (!mutated_out) { + + *out_buf = NULL; + perror("custom mutator allocation (maybe_grow)"); + return 0; /* afl-fuzz will very likely error out after this. */ + + } + + memset(mutated_out, _FIXED_CHAR, size); + + *out_buf = mutated_out; + return size; + +} + +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +void afl_custom_deinit(my_mutator_t *data) { + + free(data->fuzz_buf); + free(data); + +} + diff --git a/utils/custom_mutators/wrapper_afl_min.py b/utils/custom_mutators/wrapper_afl_min.py new file mode 100644 index 00000000..ecb03b55 --- /dev/null +++ b/utils/custom_mutators/wrapper_afl_min.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +from XmlMutatorMin import XmlMutatorMin + +# Default settings (production mode) + +__mutator__ = None +__seed__ = "RANDOM" +__log__ = False +__log_file__ = "wrapper.log" + + +# AFL functions +def log(text): + """ + Logger + """ + + global __seed__ + global __log__ + global __log_file__ + + if __log__: + with open(__log_file__, "a") as logf: + logf.write("[%s] %s\n" % (__seed__, text)) + + +def init(seed): + """ + Called once when AFL starts up. Seed is used to identify the AFL instance in log files + """ + + global __mutator__ + global __seed__ + + # Get the seed + __seed__ = seed + + # Create a global mutation class + try: + __mutator__ = XmlMutatorMin(__seed__, verbose=__log__) + log("init(): Mutator created") + except RuntimeError as e: + log("init(): Can't create mutator: %s" % e.message) + + +def fuzz(buf, add_buf, max_size): + """ + Called for each fuzzing iteration. + """ + + global __mutator__ + + # Do we have a working mutator object? + if __mutator__ is None: + log("fuzz(): Can't fuzz, no mutator available") + return buf + + # Try to use the AFL buffer + via_buffer = True + + # Interpret the AFL buffer (an array of bytes) as a string + if via_buffer: + try: + buf_str = str(buf) + log("fuzz(): AFL buffer converted to a string") + except Exception: + via_buffer = False + log("fuzz(): Can't convert AFL buffer to a string") + + # Load XML from the AFL string + if via_buffer: + try: + __mutator__.init_from_string(buf_str) + log("fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" % len(buf_str)) + except Exception: + via_buffer = False + log("fuzz(): Can't initialize mutator with AFL buffer") + + # If init from AFL buffer wasn't succesful + if not via_buffer: + log("fuzz(): Returning unmodified AFL buffer") + return buf + + # Sucessful initialization -> mutate + try: + __mutator__.mutate(max=5) + log("fuzz(): Input mutated") + except Exception: + log("fuzz(): Can't mutate input => returning buf") + return buf + + # Convert mutated data to a array of bytes + try: + data = bytearray(__mutator__.save_to_string()) + log("fuzz(): Mutated data converted as bytes") + except Exception: + log("fuzz(): Can't convert mutated data to bytes => returning buf") + return buf + + # Everything went fine, returning mutated content + log("fuzz(): Returning %d bytes" % len(data)) + return data + + +# Main (for debug) +if __name__ == '__main__': + + __log__ = True + __log_file__ = "/dev/stdout" + __seed__ = "RANDOM" + + init(__seed__) + + in_1 = bytearray("ffffzzzzzzzzzzzz") + in_2 = bytearray("") + out = fuzz(in_1, in_2) + print(out) diff --git a/utils/defork/Makefile b/utils/defork/Makefile new file mode 100644 index 00000000..e8240dba --- /dev/null +++ b/utils/defork/Makefile @@ -0,0 +1,64 @@ +# +# american fuzzy lop++ - defork +# ---------------------------------- +# +# 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 +# + +.PHONY: all install clean + +PREFIX ?= /usr/local +BIN_PATH = $(PREFIX)/bin +HELPER_PATH = $(PREFIX)/lib/afl + +CFLAGS = -fPIC -Wall -Wextra +LDFLAGS = -shared + +UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?) +UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$? + +_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=) +LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl) +LDFLAGS += $(LDFLAGS_ADD) + +# on gcc for arm there is no -m32, but -mbe32 +M32FLAG = -m32 +M64FLAG = -m64 + +CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?) +CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$? +CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?) +CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$? + +_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER) +__M32FLAG=$(_M32FLAG:00=-mbe32) +___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32) +M32FLAG=$(___M32FLAG) +#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" "" +# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)")) +# M32FLAG = -mbe32 +# endif +#endif + +all: defork32.so defork64.so + +defork32.so: defork.c + -@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork32 build failure (that's fine)" + +defork64.so: defork.c + -@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork64 build failure (that's fine)" + +install: defork32.so defork64.so + install -d -m 755 $(DESTDIR)$(HELPER_PATH)/ + if [ -f defork32.so ]; then set -e; install -m 755 defork32.so $(DESTDIR)$(HELPER_PATH)/; fi + if [ -f defork64.so ]; then set -e; install -m 755 defork64.so $(DESTDIR)$(HELPER_PATH)/; fi + +target: + ../../afl-clang forking_target.c -o forking_target -Wall -Wextra -Werror + +clean: + rm -f defork32.so defork64.so forking_target diff --git a/utils/defork/README.md b/utils/defork/README.md new file mode 100644 index 00000000..7e950323 --- /dev/null +++ b/utils/defork/README.md @@ -0,0 +1,11 @@ +# defork + +when the target forks, this breaks all normal fuzzing runs. +Sometimes, though, it is enough to just run the child process. +If this is the case, then this LD_PRELOAD library will always return 0 on fork, +the target will belive it is running as the child, post-fork. + +This is defork.c from the amazing preeny project +https://github.com/zardus/preeny + +It is altered for afl++ to work with its fork-server: the initial fork will go through, the second fork will be blocked. diff --git a/utils/defork/defork.c b/utils/defork/defork.c new file mode 100644 index 00000000..f71d1124 --- /dev/null +++ b/utils/defork/defork.c @@ -0,0 +1,50 @@ +#define __GNU_SOURCE +#include +#include +#include +#include + +#include "../../include/config.h" + +/* we want to fork once (for the afl++ forkserver), + then immediately return as child on subsequent forks. */ +static bool forked = 0; + +pid_t (*original_fork)(void); + +/* In case we are not running in afl, we use a dummy original_fork */ +static pid_t nop(void) { + + return 0; + +} + +__attribute__((constructor)) void preeny_fork_orig() { + + if (getenv(SHM_ENV_VAR)) { + + printf("defork: running in AFL++. Allowing forkserver.\n"); + original_fork = dlsym(RTLD_NEXT, "socket"); + + } else { + + printf("defork: no AFL++ detected. Disabling fork from the start.\n"); + original_fork = &nop; + + } + +} + +pid_t fork(void) { + + /* If we forked before, or if we're in the child (pid==0), + we don't want to fork anymore, else, we are still in the forkserver. + The forkserver parent needs to fork infinite times, each child should never + fork again. This can be written without branches and I hate myself for it. + */ + pid_t ret = !forked && original_fork(); + forked = !ret; + return ret; + +} + diff --git a/utils/defork/forking_target.c b/utils/defork/forking_target.c new file mode 100644 index 00000000..628d23c9 --- /dev/null +++ b/utils/defork/forking_target.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +/* This is an example target for defork.c - fuzz using +``` +mkdir in; echo a > ./in/a +AFL_PRELOAD=./defork64.so ../../afl-fuzz -i in -o out -- ./forking_target @@ +``` +*/ + +int main(int argc, char **argv) { + + if (argc < 2) { + + printf("Example tool to test defork.\nUsage ./forking_target \n"); + return -1; + + } + + pid_t pid = fork(); + if (pid == 0) { + + printf("We're in the child.\n"); + FILE *f = fopen(argv[1], "r"); + char buf[4096]; + fread(buf, 1, 4096, f); + fclose(f); + uint32_t offset = buf[100] + (buf[101] << 8); + char test_val = buf[offset]; + return test_val < 100; + + } else if (pid < 0) { + + perror("fork"); + return -1; + + } else { + + printf("We are in the parent - defork didn't work! :( (pid=%d)\n", + (int)pid); + + } + + return 0; + +} + diff --git a/utils/distributed_fuzzing/sync_script.sh b/utils/distributed_fuzzing/sync_script.sh new file mode 100755 index 00000000..b28ff6cd --- /dev/null +++ b/utils/distributed_fuzzing/sync_script.sh @@ -0,0 +1,97 @@ +#!/bin/sh +# +# american fuzzy lop++ - fuzzer synchronization tool +# -------------------------------------------------- +# +# Originally written by Michal Zalewski +# +# Copyright 2014 Google Inc. All rights reserved. +# Copyright 2019-2020 AFLplusplus Project. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# To make this script work: +# +# - Edit FUZZ_HOSTS, FUZZ_DOMAIN, FUZZ_USER, and SYNC_DIR to reflect your +# environment. +# +# - Make sure that the system you are running this on can log into FUZZ_HOSTS +# without a password (authorized_keys or otherwise). +# +# - Make sure that every fuzzer is running with -o pointing to SYNC_DIR and -S +# that consists of its local host name, followed by an underscore, and then +# by some host-local fuzzer ID. +# + +# Hosts to synchronize the data across. +FUZZ_HOSTS='host1 host2 host3 host4' + +# Domain for all hosts +FUZZ_DOMAIN='example.com' + +# Remote user for SSH +FUZZ_USER=bob + +# Directory to synchronize +SYNC_DIR='/home/bob/sync_dir' + +# We only capture -M main nodes, set the name to your chosen naming scheme +MAIN_NAME='main' + +# Interval (seconds) between sync attempts (eg one hour) +SYNC_INTERVAL=$((60 * 60)) + +if [ "$AFL_ALLOW_TMP" = "" ]; then + + if [ "$PWD" = "/tmp" -o "$PWD" = "/var/tmp" ]; then + echo "[-] Error: do not use shared /tmp or /var/tmp directories with this script." 1>&2 + exit 1 + fi + +fi + +rm -rf .sync_tmp 2>/dev/null +mkdir .sync_tmp || exit 1 + +while :; do + + # Pull data in... + + for host in $FUZZ_HOSTS; do + + echo "[*] Retrieving data from ${host}.${FUZZ_DOMAIN}..." + + ssh -o 'passwordauthentication no' ${FUZZ_USER}@${host}.$FUZZ_DOMAIN \ + "cd '$SYNC_DIR' && tar -czf - ${host}_${MAIN_NAME}*/" > ".sync_tmp/${host}.tgz" + + done + + # Distribute data. For large fleets, see tips in the docs/ directory. + + for dst_host in $FUZZ_HOSTS; do + + echo "[*] Distributing data to ${dst_host}.${FUZZ_DOMAIN}..." + + for src_host in $FUZZ_HOSTS; do + + test "$src_host" = "$dst_host" && continue + + echo " Sending fuzzer data from ${src_host}.${FUZZ_DOMAIN}..." + + ssh -o 'passwordauthentication no' ${FUZZ_USER}@$dst_host \ + "cd '$SYNC_DIR' && tar -xkzf - " < ".sync_tmp/${src_host}.tgz" + + done + + done + + echo "[+] Done. Sleeping for $SYNC_INTERVAL seconds (Ctrl-C to quit)." + + sleep $SYNC_INTERVAL + +done + diff --git a/utils/libpng_no_checksum/libpng-nocrc.patch b/utils/libpng_no_checksum/libpng-nocrc.patch new file mode 100644 index 00000000..0a3793a0 --- /dev/null +++ b/utils/libpng_no_checksum/libpng-nocrc.patch @@ -0,0 +1,15 @@ +--- pngrutil.c.orig 2014-06-12 03:35:16.000000000 +0200 ++++ pngrutil.c 2014-07-01 05:08:31.000000000 +0200 +@@ -268,7 +268,11 @@ + if (need_crc != 0) + { + crc = png_get_uint_32(crc_bytes); +- return ((int)(crc != png_ptr->crc)); ++ ++ if (crc != png_ptr->crc) ++ fprintf(stderr, "NOTE: CRC in the file is 0x%08x, change to 0x%08x\n", crc, png_ptr->crc); ++ ++ return ((int)(1 != 1)); + } + + else diff --git a/utils/persistent_mode/Makefile b/utils/persistent_mode/Makefile new file mode 100644 index 00000000..6fa1c30e --- /dev/null +++ b/utils/persistent_mode/Makefile @@ -0,0 +1,10 @@ +all: + afl-clang-fast -o persistent_demo persistent_demo.c + afl-clang-fast -o persistent_demo_new persistent_demo_new.c + AFL_DONT_OPTIMIZE=1 afl-clang-fast -o test-instr test-instr.c + +document: + AFL_DONT_OPTIMIZE=1 afl-clang-fast -D_AFL_DOCUMENT_MUTATIONS -o test-instr test-instr.c + +clean: + rm -f persistent_demo persistent_demo_new test-instr diff --git a/utils/persistent_mode/persistent_demo.c b/utils/persistent_mode/persistent_demo.c new file mode 100644 index 00000000..4cedc32c --- /dev/null +++ b/utils/persistent_mode/persistent_demo.c @@ -0,0 +1,112 @@ +/* + american fuzzy lop++ - persistent mode example + -------------------------------------------- + + Originally written by Michal Zalewski + + Copyright 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 + + This file demonstrates the high-performance "persistent mode" that may be + suitable for fuzzing certain fast and well-behaved libraries, provided that + they are stateless or that their internal state can be easily reset + across runs. + + To make this work, the library and this shim need to be compiled in LLVM + mode using afl-clang-fast (other compiler wrappers will *not* work). + + */ + +#include +#include +#include +#include +#include + +/* Main entry point. */ + +int main(int argc, char **argv) { + + ssize_t len; /* how much input did we read? */ + char buf[100]; /* Example-only buffer, you'd replace it with other global or + local variables appropriate for your use case. */ + + /* The number passed to __AFL_LOOP() controls the maximum number of + iterations before the loop exits and the program is allowed to + terminate normally. This limits the impact of accidental memory leaks + and similar hiccups. */ + + __AFL_INIT(); + while (__AFL_LOOP(1000)) { + + /*** PLACEHOLDER CODE ***/ + + /* STEP 1: Fully re-initialize all critical variables. In our example, this + involves zeroing buf[], our input buffer. */ + + memset(buf, 0, 100); + + /* STEP 2: Read input data. When reading from stdin, no special preparation + is required. When reading from a named file, you need to close + the old descriptor and reopen the file first! + + Beware of reading from buffered FILE* objects such as stdin. Use + raw file descriptors or call fopen() / fdopen() in every pass. */ + + len = read(0, buf, 100); + + /* STEP 3: This is where we'd call the tested library on the read data. + We just have some trivial inline code that faults on 'foo!'. */ + + /* do we have enough data? */ + if (len < 8) continue; + + if (buf[0] == 'f') { + + printf("one\n"); + if (buf[1] == 'o') { + + printf("two\n"); + if (buf[2] == 'o') { + + printf("three\n"); + if (buf[3] == '!') { + + printf("four\n"); + if (buf[4] == '!') { + + printf("five\n"); + if (buf[5] == '!') { + + printf("six\n"); + abort(); + + } + + } + + } + + } + + } + + } + + /*** END PLACEHOLDER CODE ***/ + + } + + /* Once the loop is exited, terminate normally - AFL will restart the process + when this happens, with a clean slate when it comes to allocated memory, + leftover file descriptors, etc. */ + + return 0; + +} + diff --git a/utils/persistent_mode/persistent_demo_new.c b/utils/persistent_mode/persistent_demo_new.c new file mode 100644 index 00000000..a29792ff --- /dev/null +++ b/utils/persistent_mode/persistent_demo_new.c @@ -0,0 +1,117 @@ +/* + american fuzzy lop++ - persistent mode example + -------------------------------------------- + + Originally written by Michal Zalewski + + Copyright 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 + + This file demonstrates the high-performance "persistent mode" that may be + suitable for fuzzing certain fast and well-behaved libraries, provided that + they are stateless or that their internal state can be easily reset + across runs. + + To make this work, the library and this shim need to be compiled in LLVM + mode using afl-clang-fast (other compiler wrappers will *not* work). + + */ + +#include +#include +#include +#include +#include + +/* this lets the source compile without afl-clang-fast/lto */ +#ifndef __AFL_FUZZ_TESTCASE_LEN + +ssize_t fuzz_len; +unsigned char fuzz_buf[1024000]; + + #define __AFL_FUZZ_TESTCASE_LEN fuzz_len + #define __AFL_FUZZ_TESTCASE_BUF fuzz_buf + #define __AFL_FUZZ_INIT() void sync(void); + #define __AFL_LOOP(x) \ + ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0) + #define __AFL_INIT() sync() + +#endif + +__AFL_FUZZ_INIT(); + +/* Main entry point. */ + +int main(int argc, char **argv) { + + ssize_t len; /* how much input did we read? */ + unsigned char *buf; /* test case buffer pointer */ + + /* The number passed to __AFL_LOOP() controls the maximum number of + iterations before the loop exits and the program is allowed to + terminate normally. This limits the impact of accidental memory leaks + and similar hiccups. */ + + __AFL_INIT(); + buf = __AFL_FUZZ_TESTCASE_BUF; // this must be assigned before __AFL_LOOP! + + while (__AFL_LOOP(1000)) { // increase if you have good stability + + len = __AFL_FUZZ_TESTCASE_LEN; // do not use the macro directly in a call! + + fprintf(stderr, "input: %zd \"%s\"\n", len, buf); + + /* do we have enough data? */ + if (len < 8) continue; + + if (strcmp((char *)buf, "thisisateststring") == 0) printf("teststring\n"); + + if (buf[0] == 'f') { + + printf("one\n"); + if (buf[1] == 'o') { + + printf("two\n"); + if (buf[2] == 'o') { + + printf("three\n"); + if (buf[3] == '!') { + + printf("four\n"); + if (buf[4] == '!') { + + printf("five\n"); + if (buf[6] == '!') { + + printf("six\n"); + abort(); + + } + + } + + } + + } + + } + + } + + /*** END PLACEHOLDER CODE ***/ + + } + + /* Once the loop is exited, terminate normally - AFL will restart the process + when this happens, with a clean slate when it comes to allocated memory, + leftover file descriptors, etc. */ + + return 0; + +} + diff --git a/utils/persistent_mode/test-instr.c b/utils/persistent_mode/test-instr.c new file mode 100644 index 00000000..a6188b22 --- /dev/null +++ b/utils/persistent_mode/test-instr.c @@ -0,0 +1,69 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +__AFL_FUZZ_INIT(); + +int main(int argc, char **argv) { + + __AFL_INIT(); + unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; + + while (__AFL_LOOP(2147483647)) { // MAX_INT if you have 100% stability + + unsigned int len = __AFL_FUZZ_TESTCASE_LEN; + +#ifdef _AFL_DOCUMENT_MUTATIONS + static unsigned int counter = 0; + char fn[32]; + sprintf(fn, "%09u:test-instr", counter); + int fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd_doc >= 0) { + + if (write(fd_doc, buf, len) != __afl_fuzz_len) { + + fprintf(stderr, "write of mutation file failed: %s\n", fn); + unlink(fn); + + } + + close(fd_doc); + + } + + counter++; +#endif + + // fprintf(stderr, "len: %u\n", len); + + if (!len) continue; + + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + + } + + return 0; + +} + diff --git a/utils/qemu_persistent_hook/Makefile b/utils/qemu_persistent_hook/Makefile new file mode 100644 index 00000000..85db1b46 --- /dev/null +++ b/utils/qemu_persistent_hook/Makefile @@ -0,0 +1,6 @@ +all: + $(CC) -no-pie test.c -o test + $(CC) -fPIC -shared read_into_rdi.c -o read_into_rdi.so + +clean: + rm -rf in out test read_into_rdi.so diff --git a/utils/qemu_persistent_hook/README.md b/utils/qemu_persistent_hook/README.md new file mode 100644 index 00000000..3f908c22 --- /dev/null +++ b/utils/qemu_persistent_hook/README.md @@ -0,0 +1,19 @@ +# QEMU persistent hook example + +Compile the test binary and the library: + +``` +make +``` + +Fuzz with: + +``` +export AFL_QEMU_PERSISTENT_ADDR=0x$(nm test | grep "T target_func" | awk '{print $1}') +export AFL_QEMU_PERSISTENT_HOOK=./read_into_rdi.so + +mkdir in +echo 0000 > in/in + +../../afl-fuzz -Q -i in -o out -- ./test +``` diff --git a/utils/qemu_persistent_hook/read_into_rdi.c b/utils/qemu_persistent_hook/read_into_rdi.c new file mode 100644 index 00000000..f4a8ae59 --- /dev/null +++ b/utils/qemu_persistent_hook/read_into_rdi.c @@ -0,0 +1,34 @@ +#include "../../qemu_mode/qemuafl/qemuafl/api.h" + +#include +#include + +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { +\ +#define g2h(x) ((void *)((unsigned long)(x) + guest_base)) +#define h2g(x) ((uint64_t)(x)-guest_base) + + // In this example the register RDI is pointing to the memory location + // of the target buffer, and the length of the input is in RSI. + // This can be seen with a debugger, e.g. gdb (and "disass main") + + printf("Placing input into 0x%lx\n", regs->rdi); + + if (input_buf_len > 1024) input_buf_len = 1024; + memcpy(g2h(regs->rdi), input_buf, input_buf_len); + regs->rsi = input_buf_len; + +#undef g2h +#undef h2g + +} + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + diff --git a/utils/qemu_persistent_hook/test.c b/utils/qemu_persistent_hook/test.c new file mode 100644 index 00000000..afeff202 --- /dev/null +++ b/utils/qemu_persistent_hook/test.c @@ -0,0 +1,35 @@ +#include + +int target_func(unsigned char *buf, int size) { + + printf("buffer:%p, size:%p\n", buf, size); + switch (buf[0]) { + + case 1: + if (buf[1] == '\x44') { puts("a"); } + break; + case 0xff: + if (buf[2] == '\xff') { + + if (buf[1] == '\x44') { puts("b"); } + + } + + break; + default: + break; + + } + + return 1; + +} + +char data[1024]; + +int main() { + + target_func(data, 1024); + +} + diff --git a/utils/socket_fuzzing/Makefile b/utils/socket_fuzzing/Makefile new file mode 100644 index 00000000..9476e2d5 --- /dev/null +++ b/utils/socket_fuzzing/Makefile @@ -0,0 +1,61 @@ +# +# american fuzzy lop++ - socket_fuzz +# ---------------------------------- +# +# 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 +# + +.PHONY: all install clean + +PREFIX ?= /usr/local +BIN_PATH = $(PREFIX)/bin +HELPER_PATH = $(PREFIX)/lib/afl + +CFLAGS = -fPIC -Wall -Wextra +LDFLAGS = -shared + +UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?) +UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$? + +_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=) +LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl) +LDFLAGS += $(LDFLAGS_ADD) + +# on gcc for arm there is no -m32, but -mbe32 +M32FLAG = -m32 +M64FLAG = -m64 + +CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?) +CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$? +CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?) +CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$? + +_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER) +__M32FLAG=$(_M32FLAG:00=-mbe32) +___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32) +M32FLAG=$(___M32FLAG) +#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" "" +# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)")) +# M32FLAG = -mbe32 +# endif +#endif + +all: socketfuzz32.so socketfuzz64.so + +socketfuzz32.so: socketfuzz.c + -@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz32 build failure (that's fine)" + +socketfuzz64.so: socketfuzz.c + -@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz64 build failure (that's fine)" + +install: socketfuzz32.so socketfuzz64.so + install -d -m 755 $(DESTDIR)$(HELPER_PATH)/ + if [ -f socketfuzz32.so ]; then set -e; install -m 755 socketfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi + if [ -f socketfuzz64.so ]; then set -e; install -m 755 socketfuzz64.so $(DESTDIR)$(HELPER_PATH)/; fi + +clean: + rm -f socketfuzz32.so socketfuzz64.so diff --git a/utils/socket_fuzzing/README.md b/utils/socket_fuzzing/README.md new file mode 100644 index 00000000..79f28bea --- /dev/null +++ b/utils/socket_fuzzing/README.md @@ -0,0 +1,11 @@ +# socketfuzz + +when you want to fuzz a network service and you can not/do not want to modify +the source (or just have a binary), then this LD_PRELOAD library will allow +for sending input to stdin which the target binary will think is coming from +a network socket. + +This is desock_dup.c from the amazing preeny project +https://github.com/zardus/preeny + +It is packaged in afl++ to have it at hand if needed diff --git a/utils/socket_fuzzing/socketfuzz.c b/utils/socket_fuzzing/socketfuzz.c new file mode 100644 index 00000000..3ec8383b --- /dev/null +++ b/utils/socket_fuzzing/socketfuzz.c @@ -0,0 +1,110 @@ +/* + * This is desock_dup.c from the amazing preeny project + * https://github.com/zardus/preeny + * + * It is packaged in afl++ to have it at hand if needed + * + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include // +#include // +#include // +#include // +#include +#include +#include +#include +#include +#include +#include +//#include "logging.h" // switche from preeny_info() to fprintf(stderr, "Info: " + +// +// originals +// +int (*original_close)(int); +int (*original_dup2)(int, int); +__attribute__((constructor)) void preeny_desock_dup_orig() { + + original_close = dlsym(RTLD_NEXT, "close"); + original_dup2 = dlsym(RTLD_NEXT, "dup2"); + +} + +int close(int sockfd) { + + if (sockfd <= 2) { + + fprintf(stderr, "Info: Disabling close on %d\n", sockfd); + return 0; + + } else { + + return original_close(sockfd); + + } + +} + +int dup2(int old, int new) { + + if (new <= 2) { + + fprintf(stderr, "Info: Disabling dup from %d to %d\n", old, new); + return 0; + + } else { + + return original_dup2(old, new); + + } + +} + +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + + (void)sockfd; + (void)addr; + (void)addrlen; + fprintf(stderr, "Info: Emulating accept on %d\n", sockfd); + return 0; + +} + +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + + (void)sockfd; + (void)addr; + (void)addrlen; + fprintf(stderr, "Info: Emulating bind on port %d\n", + ntohs(((struct sockaddr_in *)addr)->sin_port)); + return 0; + +} + +int listen(int sockfd, int backlog) { + + (void)sockfd; + (void)backlog; + return 0; + +} + +int setsockopt(int sockfd, int level, int optid, const void *optdata, + socklen_t optdatalen) { + + (void)sockfd; + (void)level; + (void)optid; + (void)optdata; + (void)optdatalen; + return 0; + +} + -- cgit 1.4.1 From a2e2fae840e9946c7994ac6807bed8496d71af56 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 3 Dec 2020 14:43:06 +0100 Subject: AFL_CRASH_EXITCODE env var added, u8->bool --- .gitignore | 1 + afl-cmin | 5 +++-- docs/Changelog.md | 4 +++- docs/env_variables.md | 7 +++++++ include/afl-fuzz.h | 7 ++++--- include/common.h | 2 +- include/envs.h | 1 + include/forkserver.h | 21 +++++++++++++-------- src/afl-analyze.c | 4 ++-- src/afl-common.c | 4 ++-- src/afl-forkserver.c | 22 +++++++++++++++------- src/afl-fuzz-init.c | 27 +++++++++++++++++++++++++-- src/afl-fuzz-state.c | 7 +++++++ src/afl-fuzz.c | 26 ++++++++++++++++++++++++-- src/afl-showmap.c | 19 +++++++++++++++++++ src/afl-tmin.c | 32 +++++++++++++++++++++++++------- 16 files changed, 152 insertions(+), 37 deletions(-) (limited to 'docs/env_variables.md') diff --git a/.gitignore b/.gitignore index 97f99bf6..82a81605 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.pyc *.dSYM as +a.out ld in out diff --git a/afl-cmin b/afl-cmin index 91ed8d6d..b3b1ead8 100755 --- a/afl-cmin +++ b/afl-cmin @@ -116,11 +116,12 @@ function usage() { "For additional tips, please consult README.md\n" \ "\n" \ "Environment variables used:\n" \ +"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \ +"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \ +"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" \ "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ "AFL_PATH: path for the afl-showmap binary\n" \ "AFL_SKIP_BIN_CHECK: skip check for target binary\n" \ -"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" -"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" exit 1 } diff --git a/docs/Changelog.md b/docs/Changelog.md index fd30c7b0..02728f10 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -60,8 +60,10 @@ sending a mail to . - Our afl++ Grammar-Mutator is now better integrated into custom_mutators/ - added INTROSPECTION support for custom modules - python fuzz function was not optional, fixed - - unicornafl synced with upstream (arm64 fix, better rust bindings) + - some python mutator speed improvements + - unicornafl synced with upstream version 1.02 (fixes, better rust bindings) - renamed AFL_DEBUG_CHILD_OUTPUT to AFL_DEBUG_CHILD + - added AFL_CRASH_EXITCODE env variable to treat a child exitcode as crash ### Version ++2.68c (release) diff --git a/docs/env_variables.md b/docs/env_variables.md index ada89257..e203055f 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -428,6 +428,13 @@ checks or alter some of the more exotic semantics of the tool: matches your StatsD server. Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`. + - Setting `AFL_CRASH_EXITCODE` sets the exit code afl treats as crash. + For example, if `AFL_CRASH_EXITCODE='-1'` is set, each input resulting + in an `-1` return code (i.e. `exit(-1)` got called), will be treated + as if a crash had ocurred. + This may be beneficial if you look for higher-level faulty conditions in which your + target still exits gracefully. + - Outdated environment variables that are not supported anymore: `AFL_DEFER_FORKSRV` `AFL_PERSISTENT` diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 933af65d..62d76323 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -144,8 +144,8 @@ struct queue_entry { u8 *fname; /* File name for the test case */ u32 len; /* Input length */ - u8 cal_failed, /* Calibration failed? */ - trim_done, /* Trimmed? */ + u8 cal_failed; /* Calibration failed? */ + bool trim_done, /* Trimmed? */ was_fuzzed, /* historical, but needed for MOpt */ passed_det, /* Deterministic stages passed? */ has_new_cov, /* Triggers new coverage? */ @@ -368,7 +368,8 @@ typedef struct afl_env_vars { u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, - *afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries; + *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, + *afl_testcache_entries; } afl_env_vars_t; diff --git a/include/common.h b/include/common.h index c364ade0..6e5039d8 100644 --- a/include/common.h +++ b/include/common.h @@ -38,7 +38,7 @@ #define STRINGIFY_VAL_SIZE_MAX (16) -void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin); +void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin); void check_environment_vars(char **env); char **argv_cpy_dup(int argc, char **argv); diff --git a/include/envs.h b/include/envs.h index 3aa05cb5..43c87148 100644 --- a/include/envs.h +++ b/include/envs.h @@ -32,6 +32,7 @@ static char *afl_environment_variables[] = { "AFL_CODE_START", "AFL_COMPCOV_BINNAME", "AFL_COMPCOV_LEVEL", + "AFL_CRASH_EXITCODE", "AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_ONLY", "AFL_CXX", diff --git a/include/forkserver.h b/include/forkserver.h index 300ecffc..5d5c728f 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -37,9 +37,7 @@ typedef struct afl_forkserver { /* a program that includes afl-forkserver needs to define these */ - u8 uses_asan; /* Target uses ASAN? */ u8 *trace_bits; /* SHM with instrumentation bitmap */ - u8 use_stdin; /* use stdin for sending data */ s32 fsrv_pid, /* PID of the fork server */ child_pid, /* PID of the fuzzed program */ @@ -53,8 +51,6 @@ typedef struct afl_forkserver { fsrv_ctl_fd, /* Fork server control pipe (write) */ fsrv_st_fd; /* Fork server status pipe (read) */ - u8 no_unlink; /* do not unlink cur_input */ - u32 exec_tmout; /* Configurable exec timeout (ms) */ u32 init_tmout; /* Configurable init timeout (ms) */ u32 map_size; /* map size used by the target */ @@ -73,13 +69,22 @@ typedef struct afl_forkserver { u8 last_kill_signal; /* Signal that killed the child */ - u8 use_shmem_fuzz; /* use shared mem for test cases */ + bool use_shmem_fuzz; /* use shared mem for test cases */ + + bool support_shmem_fuzz; /* set by afl-fuzz */ + + bool use_fauxsrv; /* Fauxsrv for non-forking targets? */ + + bool qemu_mode; /* if running in qemu mode or not */ + + bool use_stdin; /* use stdin for sending data */ - u8 support_shmem_fuzz; /* set by afl-fuzz */ + bool no_unlink; /* do not unlink cur_input */ - u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */ + bool uses_asan; /* Target uses ASAN? */ - u8 qemu_mode; /* if running in qemu mode or not */ + bool uses_crash_exitcode; /* Custom crash exitcode specified? */ + u8 crash_exitcode; /* The crash exitcode specified */ u32 *shmem_fuzz_len; /* length of the fuzzing test case */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index c8acebb3..2780deff 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -78,9 +78,9 @@ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ static s32 dev_null_fd = -1; /* FD to /dev/null */ -static u8 edges_only, /* Ignore hit counts? */ +static bool edges_only, /* Ignore hit counts? */ use_hex_offsets, /* Show hex offsets? */ - use_stdin = 1; /* Use stdin for program input? */ + use_stdin = true; /* Use stdin for program input? */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_timed_out; /* Child timed out? */ diff --git a/src/afl-common.c b/src/afl-common.c index 8cf1a444..ed0b0e53 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -46,7 +46,7 @@ u8 be_quiet = 0; u8 *doc_path = ""; u8 last_intr = 0; -void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) { +void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin) { u32 i = 0; u8 cwd[PATH_MAX]; @@ -63,7 +63,7 @@ void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) { if (!prog_in) { FATAL("@@ syntax is not supported by this tool."); } - *use_stdin = 0; + *use_stdin = false; if (prog_in[0] != 0) { // not afl-showmap special case diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 01ef1d9e..20117c1d 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -76,8 +76,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->dev_urandom_fd = -1; /* Settings */ - fsrv->use_stdin = 1; - fsrv->no_unlink = 0; + fsrv->use_stdin = true; + fsrv->no_unlink = false; fsrv->exec_tmout = EXEC_TIMEOUT; fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT; fsrv->mem_limit = MEM_LIMIT; @@ -86,8 +86,11 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { /* exec related stuff */ fsrv->child_pid = -1; fsrv->map_size = get_map_size(); - fsrv->use_fauxsrv = 0; - fsrv->last_run_timed_out = 0; + fsrv->use_fauxsrv = false; + fsrv->last_run_timed_out = false; + + fsrv->uses_crash_exitcode = false; + fsrv->uses_asan = false; fsrv->init_child_func = fsrv_exec_child; @@ -109,6 +112,8 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->dev_urandom_fd = from->dev_urandom_fd; fsrv_to->out_fd = from->out_fd; // not sure this is a good idea fsrv_to->no_unlink = from->no_unlink; + fsrv_to->uses_crash_exitcode = from->uses_crash_exitcode; + fsrv_to->crash_exitcode = from->crash_exitcode; // These are forkserver specific. fsrv_to->out_dir_fd = -1; @@ -1136,10 +1141,13 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, } - /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and - must use a special exit code. */ + /* MSAN in uses_asan mode uses a special exit code as it doesn't support + abort_on_error. + On top, a user may specify a custom AFL_CRASH_EXITCODE. Handle both here. */ - if (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) { + if ((fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) || + (fsrv->uses_crash_exitcode && + WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode)) { fsrv->last_kill_signal = 0; return FSRV_RUN_CRASH; diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 0360cdb0..6707340b 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -868,7 +868,19 @@ void perform_dry_run(afl_state_t *afl) { if (skip_crashes) { - WARNF("Test case results in a crash (skipping)"); + if (afl->fsrv.uses_crash_exitcode) { + + WARNF( + "Test case results in a crash or AFL_CRASH_EXITCODE %d " + "(skipping)", + (int)(s8)afl->fsrv.crash_exitcode); + + } else { + + WARNF("Test case results in a crash (skipping)"); + + } + q->cal_failed = CAL_CHANCES; ++cal_failures; break; @@ -954,7 +966,18 @@ void perform_dry_run(afl_state_t *afl) { #undef MSG_ULIMIT_USAGE #undef MSG_FORK_ON_APPLE - WARNF("Test case '%s' results in a crash, skipping", fn); + if (afl->fsrv.uses_crash_exitcode) { + + WARNF( + "Test case '%s' results in a crash or AFL_CRASH_EXITCODE %d, " + "skipping", + fn, (int)(s8)afl->fsrv.crash_exitcode); + + } else { + + WARNF("Test case '%s' results in a crash, skipping", fn); + + } /* Remove from fuzzing queue but keep for splicing */ diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 489d4e53..73b94466 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -394,6 +394,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_statsd_tags_flavor = (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_CRASH_EXITCODE", + + afl_environment_variable_len)) { + + afl->afl_env.afl_crash_exitcode = + (u8 *)get_afl_env(afl_environment_variables[i]); + } } else { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index b91d862d..eb5e9307 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -26,6 +26,7 @@ #include "afl-fuzz.h" #include "cmplog.h" #include +#include #ifndef USEMMAP #include #include @@ -165,6 +166,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n" "AFL_BENCH_JUST_ONE: run the target just once\n" "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n" + "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n" "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n" "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n" @@ -702,7 +704,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'N': /* Unicorn mode */ if (afl->no_unlink) { FATAL("Multiple -N options not supported"); } - afl->fsrv.no_unlink = afl->no_unlink = 1; + afl->fsrv.no_unlink = (afl->no_unlink = true); break; @@ -1135,6 +1137,23 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->afl_env.afl_crash_exitcode) { + + long exitcode = strtol(afl->afl_env.afl_crash_exitcode, NULL, 10); + if ((!exitcode && (errno == EINVAL || errno == ERANGE)) || + exitcode < -127 || exitcode > 128) { + + FATAL("Invalid crash exitcode, expected -127 to 128, but got %s", + afl->afl_env.afl_crash_exitcode); + + } + + afl->fsrv.uses_crash_exitcode = true; + // WEXITSTATUS is 8 bit unsigned + afl->fsrv.crash_exitcode = (u8)exitcode; + + } + if (afl->non_instrumented_mode == 2 && afl->no_forkserver) { FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); @@ -1486,9 +1505,12 @@ int main(int argc, char **argv_orig, char **envp) { cull_queue(afl); - if (!afl->pending_not_fuzzed) + if (!afl->pending_not_fuzzed) { + FATAL("We need at least on valid input seed that does not crash!"); + } + show_init_stats(afl); if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index a8e7d3f9..e07e76c8 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -667,6 +667,8 @@ static void usage(u8 *argv0) { "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing " "inputs\n" "AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n" + "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as " + "crash\n" "AFL_DEBUG: enable extra developer output\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the " "size\n" @@ -1090,6 +1092,23 @@ int main(int argc, char **argv_orig, char **envp) { } + if (getenv("AFL_CRASH_EXITCODE")) { + + long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); + if ((!exitcode && (errno == EINVAL || errno == ERANGE)) || + exitcode < -127 || exitcode > 128) { + + FATAL("Invalid crash exitcode, expected -127 to 128, but got %s", + getenv("AFL_CRASH_EXITCODE")); + + } + + fsrv->uses_crash_exitcode = true; + // WEXITSTATUS is 8 bit unsigned + fsrv->crash_exitcode = (u8)exitcode; + + } + afl_fsrv_start(fsrv, use_argv, &stop_soon, (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) diff --git a/src/afl-tmin.c b/src/afl-tmin.c index e4fb068d..b9045551 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -841,17 +842,17 @@ static void usage(u8 *argv0) { "For additional tips, please consult %s/README.md.\n\n" "Environment variables used:\n" - "TMPDIR: directory to use for temporary input files\n" - "ASAN_OPTIONS: custom settings for ASAN\n" - " (must contain abort_on_error=1 and symbolize=0)\n" - "MSAN_OPTIONS: custom settings for MSAN\n" - " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" + "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" + "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" " the target was compiled for\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n" - "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n" - + "ASAN_OPTIONS: custom settings for ASAN\n" + " (must contain abort_on_error=1 and symbolize=0)\n" + "MSAN_OPTIONS: custom settings for MSAN\n" + " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" + "TMPDIR: directory to use for temporary input files\n" , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path); exit(1); @@ -1122,6 +1123,23 @@ int main(int argc, char **argv_orig, char **envp) { } + if (getenv("AFL_CRASH_EXITCODE")) { + + long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); + if ((!exitcode && (errno == EINVAL || errno == ERANGE)) || + exitcode < -127 || exitcode > 128) { + + FATAL("Invalid crash exitcode, expected -127 to 128, but got %s", + getenv("AFL_CRASH_EXITCODE")); + + } + + fsrv->uses_crash_exitcode = true; + // WEXITSTATUS is 8 bit unsigned + fsrv->crash_exitcode = (u8)exitcode; + + } + shm_fuzz = ck_alloc(sizeof(sharedmem_t)); /* initialize cmplog_mode */ -- cgit 1.4.1 From 12ebb351dc2b5655b4174539e2b9ee59e4acf893 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 18 Dec 2020 21:10:39 +0100 Subject: apply nocolor changes --- docs/Changelog.md | 2 ++ docs/env_variables.md | 3 +++ include/config.h | 16 ++++++++++++ include/debug.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++----- include/envs.h | 4 +++ src/afl-fuzz-state.c | 16 ++++++++++++ src/afl-fuzz.c | 15 +++++++++++ 7 files changed, 122 insertions(+), 6 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index ac75c68d..ebc514f3 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -52,6 +52,8 @@ sending a mail to . - somewhere we broke -n dumb fuzzing, fixed - added afl_custom_describe to the custom mutator API to allow for easy mutation reproduction on crashing inputs + - new env. var. AFL_NO_COLOR (or AFL_NO_COLOUR) to suppress colored + console output (when configured with USE_COLOR and not ALWAYS_COLORED) - instrumentation - We received an enhanced gcc_plugin module from AdaCore, thank you very much!! diff --git a/docs/env_variables.md b/docs/env_variables.md index e203055f..74863d8d 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -381,6 +381,9 @@ checks or alter some of the more exotic semantics of the tool: some basic stats. This behavior is also automatically triggered when the output from afl-fuzz is redirected to a file or to a pipe. + - Setting `AFL_NO_COLOR` or `AFL_NO_COLOUR` will omit control sequences for + coloring console output when configured with USE_COLOR and not ALWAYS_COLORED. + - Setting `AFL_FORCE_UI` will force painting the UI on the screen even if no valid terminal was detected (for virtual consoles) diff --git a/include/config.h b/include/config.h index 1eb6bc5e..d57ef223 100644 --- a/include/config.h +++ b/include/config.h @@ -36,11 +36,27 @@ * * ******************************************************/ +/* console output colors: There are three ways to configure its behavior + * 1. default: colored outputs fixed on: defined USE_COLOR && defined ALWAYS_COLORED + * The env var. AFL_NO_COLOR will have no effect + * 2. defined USE_COLOR && !defined ALWAYS_COLORED + * -> depending on env var AFL_NO_COLOR=1 colors can be switched off + * at run-time. Default is to use colors. + * 3. colored outputs fixed off: !defined USE_COLOR + * The env var. AFL_NO_COLOR will have no effect +*/ + /* Comment out to disable terminal colors (note that this makes afl-analyze a lot less nice): */ #define USE_COLOR +#ifdef USE_COLOR +/* Comment in to always enable terminal colors */ +/* Comment out to enable runtime controlled terminal colors via AFL_NO_COLOR */ +#define ALWAYS_COLORED 1 +#endif + /* StatsD config Config can be adjusted via AFL_STATSD_HOST and AFL_STATSD_PORT environment variable. diff --git a/include/debug.h b/include/debug.h index 5512023c..7a1725b5 100644 --- a/include/debug.h +++ b/include/debug.h @@ -168,12 +168,72 @@ * Debug & error macros * ************************/ -/* Just print stuff to the appropriate stream. */ +#if defined USE_COLOR && !defined ALWAYS_COLORED +#include +#pragma GCC diagnostic ignored "-Wformat-security" +static inline const char * colorfilter(const char * x) { + static int once = 1; + static int disabled = 0; + + if (once) { + /* when there is no tty -> we always want filtering + * when AFL_NO_UI is set filtering depends on AFL_NO_COLOR + * otherwise we want always colors + */ + disabled = isatty(2) && (!getenv("AFL_NO_UI") || (!getenv("AFL_NO_COLOR") && !getenv("AFL_NO_COLOUR"))); + once = 0; + } + if (likely(disabled)) return x; + + static char monochromestring[4096]; + char *d = monochromestring; + int in_seq = 0; + + while(*x) { + if (in_seq && *x == 'm') { + in_seq = 0; + } else { + if (!in_seq && *x == '\x1b') { in_seq = 1; } + if (!in_seq) { + *d++ = *x; + } + } + ++x; + } + + *d = '\0'; + return monochromestring; +} +#else +#define colorfilter(x) x /* no filtering necessary */ +#endif +/* macro magic to transform the first parameter to SAYF + * through colorfilter which strips coloring */ +#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,\ +_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,\ +_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,\ +_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,\ +NAME,...) NAME + +#define SAYF(...) GET_MACRO(__VA_ARGS__, \ +SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \ +SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \ +SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \ +SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \ +SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \ +SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \ +SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_N, \ +SAYF_N, SAYF_N, SAYF_N, SAYF_N, SAYF_1)(__VA_ARGS__) + +#define SAYF_1(x) MY_SAYF(colorfilter(x)) +#define SAYF_N(x,...) MY_SAYF(colorfilter(x), __VA_ARGS__) + +/* Just print stuff to the appropriate stream. */ #ifdef MESSAGES_TO_STDOUT - #define SAYF(x...) printf(x) + #define MY_SAYF(x...) printf(x) #else - #define SAYF(x...) fprintf(stderr, x) + #define MY_SAYF(x...) fprintf(stderr, x) #endif /* ^MESSAGES_TO_STDOUT */ /* Show a prefixed warning. */ @@ -222,7 +282,7 @@ do { \ \ 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", __func__, \ __FILE__, __LINE__); \ exit(1); \ @@ -235,7 +295,7 @@ do { \ \ 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", __func__, \ __FILE__, __LINE__); \ abort(); \ @@ -249,7 +309,7 @@ \ fflush(stdout); \ 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", __func__, \ __FILE__, __LINE__); \ SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \ diff --git a/include/envs.h b/include/envs.h index c0f41ca5..f16e61f0 100644 --- a/include/envs.h +++ b/include/envs.h @@ -103,6 +103,10 @@ static char *afl_environment_variables[] = { "AFL_NO_ARITH", "AFL_NO_AUTODICT", "AFL_NO_BUILTIN", +#if defined USE_COLOR && ! defined ALWAYS_COLORED + "AFL_NO_COLOR", + "AFL_NO_COLOUR", +#endif "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI", diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 9c51a3ef..e863c4c7 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -401,6 +401,22 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_crash_exitcode = (u8 *)get_afl_env(afl_environment_variables[i]); +#if defined USE_COLOR && ! defined ALWAYS_COLORED + } else if (!strncmp(env, "AFL_NO_COLOR", + + afl_environment_variable_len)) { + + afl->afl_env.afl_statsd_tags_flavor = + (u8 *)get_afl_env(afl_environment_variables[i]); + + } else if (!strncmp(env, "AFL_NO_COLOUR", + + afl_environment_variable_len)) { + + afl->afl_env.afl_statsd_tags_flavor = + (u8 *)get_afl_env(afl_environment_variables[i]); +#endif + } } else { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 391d4c4f..e0d46f7e 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -156,6 +156,12 @@ static void usage(u8 *argv0, int more_help) { if (more_help > 1) { +#if defined USE_COLOR && !defined ALWAYS_COLORED + #define DYN_COLOR "AFL_NO_COLOR or AFL_NO_COLOUR: switch colored console output off\n" +#else + #define DYN_COLOR +#endif + SAYF( "Environment variables used:\n" "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n" @@ -194,6 +200,9 @@ static void usage(u8 *argv0, int more_help) { "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n" "AFL_NO_UI: switch status screen off\n" + + DYN_COLOR + "AFL_PATH: path to AFL support binaries\n" "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n" "AFL_QUIET: suppress forkserver status messages\n" @@ -298,6 +307,12 @@ int main(int argc, char **argv_orig, char **envp) { struct timeval tv; struct timezone tz; +#if defined USE_COLOR && defined ALWAYS_COLORED + if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) { + WARNF("Setting AFL_NO_COLOR has no effect (colors are configured on at compile time)"); + } +#endif + char **argv = argv_cpy_dup(argc, argv_orig); afl_state_t *afl = calloc(1, sizeof(afl_state_t)); -- cgit 1.4.1 From 2e3cf10070681375a6c0e63ad39e7ce04ff22684 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 20 Dec 2020 22:53:41 +0100 Subject: document AFL_LLVM_INSTRUMENT option NATIVE --- docs/Changelog.md | 2 ++ docs/env_variables.md | 2 ++ instrumentation/README.llvm.md | 21 +-------------------- src/afl-cc.c | 3 +++ 4 files changed, 8 insertions(+), 20 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 28b7e723..a26a4e0e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,6 +17,8 @@ sending a mail to . - allow instrumenting LLVMFuzzerTestOneInput - fixed endless loop for allow/blocklist lines starting with a comment (thanks to Zherya for reporting) + - added AFL_LLVM_INSTRUMENT option NATIVE for native clang pc-guard support + (less performant than our own) ### Version ++3.00c (release) diff --git a/docs/env_variables.md b/docs/env_variables.md index 74863d8d..c1693748 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -113,6 +113,8 @@ Then there are a few specific features that are only available in instrumentatio - `AFL_LLVM_INSTRUMENT` - this configures the instrumentation mode. Available options: + PCGUARD - our own pcgard based instrumentation (default) + NATIVE - clang's original pcguard based instrumentation CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default) CFG - InsTrim instrumentation (see below) LTO - LTO instrumentation (see below) diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index 07636970..2705ce0d 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -168,26 +168,7 @@ This is the most powerful and effective fuzzing you can do. Please see [README.persistent_mode.md](README.persistent_mode.md) for a full explanation. -## 7) Bonus feature: 'trace-pc-guard' mode - -LLVM is shipping with a built-in execution tracing feature -that provides AFL with the necessary tracing data without the need to -post-process the assembly or install any compiler plugins. See: - - http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards - -If you have not an outdated compiler and want to give it a try, build -targets this way: - -``` -AFL_LLVM_INSTRUMENT=PCGUARD make -``` - -Note that this is currently the default if you use LLVM >= 7, as it is the best -mode. Recommended is LLVM >= 9. -If you have llvm 11+ and compiled afl-clang-lto - this is the only better mode. - -## 8) Bonus feature: 'dict2file' pass +## 7) Bonus feature: 'dict2file' pass Just specify `AFL_LLVM_DICT2FILE=/absolute/path/file.txt` and during compilation all constant string compare parameters will be written to this file to be diff --git a/src/afl-cc.c b/src/afl-cc.c index 8593f9b8..6f4801de 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1346,6 +1346,9 @@ int main(int argc, char **argv, char **envp) { "Sub-Modes: (set via env AFL_LLVM_INSTRUMENT, afl-cc selects the best " "available)\n" " PCGUARD: Dominator tree instrumentation (best!) (README.llvm.md)\n" +#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0) + " NATIVE: use llvm's native PCGUARD instrumentation (less performant)\n" +#endif " CLASSIC: decision target instrumentation (README.llvm.md)\n" " CTX: CLASSIC + callee context (instrumentation/README.ctx.md)\n" " NGRAM-x: CLASSIC + previous path " -- cgit 1.4.1 From 27b9ba45026397ee0605dd88aab359c4c1dea4cc Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 22 Dec 2020 10:51:40 +0100 Subject: better gcc and clang support for afl-cc --- docs/Changelog.md | 3 +- docs/env_variables.md | 2 + src/afl-cc.c | 134 ++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 123 insertions(+), 16 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index e36e4e9f..cf9bfbe1 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,7 +20,8 @@ sending a mail to . - fixed endless loop for allow/blocklist lines starting with a comment (thanks to Zherya for reporting) - added AFL_LLVM_INSTRUMENT option NATIVE for native clang pc-guard - support (less performant than our own) + support (less performant than our own), GCC for old afl-gcc and + CLANG for old afl-clang - added dummy Makefile to instrumentation/ diff --git a/docs/env_variables.md b/docs/env_variables.md index c1693748..e6b9381b 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -120,6 +120,8 @@ Then there are a few specific features that are only available in instrumentatio LTO - LTO instrumentation (see below) CTX - context sensitive instrumentation (see below) NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16) + GCC - outdated gcc instrumentation + CLANG - outdated clang instrumentation In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or NGRAM, seperate the options with a comma "," then, e.g.: `AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4` diff --git a/src/afl-cc.c b/src/afl-cc.c index 3b8092a9..a18f87db 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -62,7 +62,7 @@ u8 use_stdin; /* dummy */ enum { - INSTURMENT_DEFAULT = 0, + INSTRUMENT_DEFAULT = 0, INSTRUMENT_CLASSIC = 1, INSTRUMENT_AFL = 1, INSTRUMENT_PCGUARD = 2, @@ -70,6 +70,8 @@ enum { INSTRUMENT_CFG = 3, INSTRUMENT_LTO = 4, INSTRUMENT_LLVMNATIVE = 5, + INSTRUMENT_GCC = 6, + INSTRUMENT_CLANG = 7, INSTRUMENT_OPT_CTX = 8, INSTRUMENT_OPT_NGRAM = 16 @@ -77,9 +79,24 @@ enum { char instrument_mode_string[18][18] = { - "DEFAULT", "CLASSIC", "PCGUARD", "CFG", "LTO", "", "PCGUARD-NATIVE", - "", "CTX", "", "", "", "", "", - "", "", "NGRAM", "" + "DEFAULT", + "CLASSIC", + "PCGUARD", + "CFG", + "LTO", + "PCGUARD-NATIVE", + "GCC", + "CLANG", + "CTX", + "", + "", + "", + "", + "", + "", + "", + "NGRAM", + "" }; @@ -89,14 +106,15 @@ enum { LTO = 1, LLVM = 2, GCC_PLUGIN = 3, - GCC = 4 + GCC = 4, + CLANG = 5 }; -char compiler_mode_string[6][12] = { +char compiler_mode_string[7][12] = { "AUTOSELECT", "LLVM-LTO", "LLVM", "GCC_PLUGIN", - "GCC", "" + "GCC", "CLANG", "" }; @@ -324,6 +342,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { alt_cxx = clang_mode ? "clang++" : "g++"; + } else if (compiler_mode == CLANG) { + + alt_cxx = "clang++"; + } else { alt_cxx = "g++"; @@ -357,6 +379,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { alt_cc = clang_mode ? "clang" : "gcc"; + } else if (compiler_mode == CLANG) { + + alt_cc = "clang"; + } else { alt_cc = "gcc"; @@ -380,12 +406,16 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - if (compiler_mode == GCC) { + if (compiler_mode == GCC || compiler_mode == CLANG) { cc_params[cc_par_cnt++] = "-B"; cc_params[cc_par_cnt++] = obj_path; - if (clang_mode) { cc_params[cc_par_cnt++] = "-no-integrated-as"; } + if (clang_mode || compiler_mode == CLANG) { + + cc_params[cc_par_cnt++] = "-no-integrated-as"; + + } } @@ -996,12 +1026,14 @@ int main(int argc, char **argv, char **envp) { } else if (strncmp(callname, "afl-gcc", 7) == 0 || - strncmp(callname, "afl-g++", 7) == 0 || - - strncmp(callname, "afl-clang", 9) == 0) { + strncmp(callname, "afl-g++", 7) == 0) { compiler_mode = GCC; + } else if (strncmp(callname, "afl-clang", 9) == 0) { + + compiler_mode = CLANG; + } if ((ptr = getenv("AFL_CC_COMPILER"))) { @@ -1045,6 +1077,7 @@ int main(int argc, char **argv, char **envp) { if (strncmp(callname, "afl-clang", 9) == 0) { clang_mode = 1; + compiler_mode = CLANG; if (strncmp(callname, "afl-clang++", 11) == 0) { plusplus_mode = 1; } @@ -1072,6 +1105,34 @@ int main(int argc, char **argv, char **envp) { compiler_mode = LLVM; + } else if (strncasecmp(ptr, "PCGUARD", 7) == 0 || + + strncasecmp(ptr, "PC-GUARD", 8) == 0) { + + compiler_mode = LLVM; + instrument_mode = INSTRUMENT_PCGUARD; + + } else if (strcasecmp(ptr, "INSTRIM") == 0 || + + strcasecmp(ptr, "CFG") == 0) { + + compiler_mode = LLVM; + instrument_mode = INSTRUMENT_CFG; + + } else if (strcasecmp(ptr, "AFL") == 0 || + + strcasecmp(ptr, "CLASSIC") == 0) { + + compiler_mode = LLVM; + instrument_mode = INSTRUMENT_CLASSIC; + + } else if (strcasecmp(ptr, "LLVMNATIVE") == 0 || + + strcasecmp(ptr, "LLVM-NATIVE") == 0) { + + compiler_mode = LLVM; + instrument_mode = INSTRUMENT_LLVMNATIVE; + } else if (strncasecmp(ptr, "GCC_P", 5) == 0 || strncasecmp(ptr, "GCC-P", 5) == 0 || @@ -1083,6 +1144,10 @@ int main(int argc, char **argv, char **envp) { compiler_mode = GCC; + } else if (strcasecmp(ptr, "CLANG") == 0) { + + compiler_mode = CLANG; + } else FATAL("Unknown --afl-... compiler mode: %s\n", argv[i]); @@ -1212,6 +1277,28 @@ int main(int argc, char **argv, char **envp) { } + if (strcasecmp(ptr, "gcc") == 0) { + + if (!instrument_mode || instrument_mode == INSTRUMENT_GCC) + instrument_mode = INSTRUMENT_GCC; + else if (instrument_mode != INSTRUMENT_GCC) + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + compiler_mode = GCC; + + } + + if (strcasecmp(ptr, "clang") == 0) { + + if (!instrument_mode || instrument_mode == INSTRUMENT_CLANG) + instrument_mode = INSTRUMENT_CLANG; + else if (instrument_mode != INSTRUMENT_CLANG) + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + compiler_mode = CLANG; + + } + if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) { instrument_opt_mode |= INSTRUMENT_OPT_CTX; @@ -1270,6 +1357,22 @@ int main(int argc, char **argv, char **envp) { } + if (compiler_mode == GCC) { + + if (clang_mode) { + + instrument_mode = CLANG; + + } else { + + instrument_mode = GCC; + + } + + } + + if (compiler_mode == CLANG) { instrument_mode = CLANG; } + if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) { printf("afl-cc" VERSION @@ -1316,7 +1419,7 @@ int main(int argc, char **argv, char **envp) { " [GCC_PLUGIN] gcc plugin: %s%s\n" " CLASSIC DEFAULT no yes yes no no no " " yes\n" - " [GCC] simple gcc: %s%s\n" + " [GCC/CLANG] simple gcc/clang: %s%s\n" " CLASSIC DEFAULT no no no no no no " " no\n\n", have_lto ? "AVAILABLE" : "unavailable!", @@ -1328,7 +1431,7 @@ int main(int argc, char **argv, char **envp) { have_gcc_plugin ? "AVAILABLE" : "unavailable!", compiler_mode == GCC_PLUGIN ? " [SELECTED]" : "", have_gcc ? "AVAILABLE" : "unavailable!", - compiler_mode == GCC ? " [SELECTED]" : ""); + (compiler_mode == GCC || compiler_mode == CLANG) ? " [SELECTED]" : ""); SAYF( "Modes:\n" @@ -1445,7 +1548,8 @@ int main(int argc, char **argv, char **envp) { " AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen " "mutator)\n" " AFL_LLVM_INSTRUMENT: set instrumentation mode:\n" - " CLASSIC, INSTRIM, PCGUARD, LTO, CTX, NGRAM-2 ... NGRAM-16\n" + " CLASSIC, INSTRIM, PCGUARD, LTO, GCC, CLANG, CTX, NGRAM-2 ... " + "NGRAM-16\n" " You can also use the old environment variables instead:\n" " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n" " AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n" -- cgit 1.4.1 From a06b25538fd7b6eef6755094aa4678c2cb5333fd Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 7 Jan 2021 23:21:10 +0100 Subject: cleaned up AFL_KILL_SIGNAL --- afl-cmin | 1 + docs/Changelog.md | 2 +- docs/env_variables.md | 4 ++++ src/afl-forkserver.c | 45 +++++++-------------------------------------- src/afl-fuzz.c | 30 +++++++++++++++++++++++++++++- src/afl-showmap.c | 37 +++++++++++++++++++++++++++++++++---- src/afl-tmin.c | 29 +++++++++++++++++++++++++++++ 7 files changed, 104 insertions(+), 44 deletions(-) (limited to 'docs/env_variables.md') diff --git a/afl-cmin b/afl-cmin index eef2b7ef..726e90ab 100755 --- a/afl-cmin +++ b/afl-cmin @@ -120,6 +120,7 @@ function usage() { "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \ "AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" \ "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ +"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n" "AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \ "AFL_SKIP_BIN_CHECK: skip check for target binary\n" exit 1 diff --git a/docs/Changelog.md b/docs/Changelog.md index 03b8e036..81ac91b0 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -32,7 +32,7 @@ sending a mail to . already building with all cores, the gcc plugin needs only one. - added dummy Makefile to instrumentation/ - Updated utils/afl_frida to be 5% faster - + - Added AFL_KILL_SIGNAL env variable for custom targets (thanks @v-p-b) ### Version ++3.00c (release) - llvm_mode/ and gcc_plugin/ moved to instrumentation/ diff --git a/docs/env_variables.md b/docs/env_variables.md index e6b9381b..26128b01 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -350,6 +350,10 @@ checks or alter some of the more exotic semantics of the tool: - Note that `AFL_POST_LIBRARY` is deprecated, use `AFL_CUSTOM_MUTATOR_LIBRARY` instead (see below). + - `AFL_KILL_SIGNAL`: Set the signal ID to be delivered to child processes on timeout. + Unless you implement your own targets or instrumentation, you likely don't have to set it. + By default, on timeout and on exit, `SIGKILL` (`AFL_KILL_SIGNAL=9`) will be delivered to the child. + - Setting `AFL_CUSTOM_MUTATOR_LIBRARY` to a shared library with afl_custom_fuzz() creates additional mutations through this library. If afl-fuzz is compiled with Python (which is autodetected during builing diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 70fb9572..b7aa87f8 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -84,6 +84,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT; fsrv->mem_limit = MEM_LIMIT; fsrv->out_file = NULL; + fsrv->kill_signal = SIGKILL; /* exec related stuff */ fsrv->child_pid = -1; @@ -95,30 +96,6 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->uses_asan = false; fsrv->init_child_func = fsrv_exec_child; - fsrv->kill_signal = SIGKILL; - - char *kill_signal_env = get_afl_env("AFL_KILL_SIGNAL"); - if (kill_signal_env) { - - char *endptr; - u8 signal_code; - signal_code = (u8)strtoul(kill_signal_env, &endptr, 10); - /* Did we manage to parse the full string? */ - if (*endptr != '\0' || endptr == kill_signal_env) { - - FATAL("Invalid kill signal value!"); - - } - - fsrv->kill_signal = signal_code; - - } else { - - /* Using hardcoded code for SIGKILL for the sake of simplicity */ - setenv("AFL_KILL_SIGNAL", "9", 1); - - } - list_append(&fsrv_list, fsrv); } @@ -139,6 +116,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->no_unlink = from->no_unlink; fsrv_to->uses_crash_exitcode = from->uses_crash_exitcode; fsrv_to->crash_exitcode = from->crash_exitcode; + fsrv_to->kill_signal = from->kill_signal; // These are forkserver specific. fsrv_to->out_dir_fd = -1; @@ -149,8 +127,6 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->init_child_func = from->init_child_func; // Note: do not copy ->add_extra_func - fsrv_to->kill_signal = from->kill_signal; - list_append(&fsrv_list, fsrv_to); } @@ -1162,25 +1138,18 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* Report outcome to caller. */ - /* TODO We use SIGTERM here as an indicator of Xen mode, - although it's not equivalent! */ - if (fsrv->kill_signal == SIGTERM && !*stop_soon_p && - fsrv->last_run_timed_out) { + /* Did we timeout? */ + if (unlikely(fsrv->last_run_timed_out)) { + fsrv->last_kill_signal = fsrv->kill_signal; return FSRV_RUN_TMOUT; } - if (WIFSIGNALED(fsrv->child_status) && !*stop_soon_p) { + /* Did we crash? */ + if (unlikely(WIFSIGNALED(fsrv->child_status) && !*stop_soon_p)) { fsrv->last_kill_signal = WTERMSIG(fsrv->child_status); - - if (fsrv->last_run_timed_out && fsrv->last_kill_signal == SIGKILL) { - - return FSRV_RUN_TMOUT; - - } - return FSRV_RUN_CRASH; } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 00625f2e..5c363c63 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -194,10 +194,11 @@ static void usage(u8 *argv0, int more_help) { "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60 minutes and a cycle without finds)\n" "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n" "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n" - "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n" "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n" + "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n" "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n" "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n" + "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" " the target was compiled for\n" "AFL_MAX_DET_EXTRAS: if more entries are in the dictionary list than this value\n" @@ -986,6 +987,33 @@ int main(int argc, char **argv_orig, char **envp) { #endif + afl->fsrv.kill_signal = SIGKILL; + if (afl->afl_env.afl_kill_signal) { + + char *endptr; + u8 signal_code; + signal_code = (u8)strtoul(afl->afl_env.afl_kill_signal, &endptr, 10); + /* Did we manage to parse the full string? */ + if (*endptr != '\0' || endptr == (char *)afl->afl_env.afl_kill_signal) { + + FATAL("Invalid AFL_KILL_SIGNAL: %s (expected unsigned int)", + afl->afl_env.afl_kill_signal); + + } + + afl->fsrv.kill_signal = signal_code; + + } else { + + char *sigstr = alloc_printf("%d", (int)SIGKILL); + if (!sigstr) { FATAL("Failed to alloc mem for signal buf"); } + + /* Set the env for signal handler */ + setenv("AFL_KILL_SIGNAL", sigstr, 1); + free(sigstr); + + } + setup_signal_handlers(); check_asan_opts(afl); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index d50601fc..2c9c38ed 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -693,12 +693,13 @@ static void usage(u8 *argv0) { "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as " "crash\n" "AFL_DEBUG: enable extra developer output\n" - "AFL_MAP_SIZE: the shared memory size for that target. must be >= the " - "size\n" - " the target was compiled for\n" - "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during " "startup (in milliseconds)\n" + "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, " + "etc. (default: SIGKILL)\n" + "AFL_MAP_SIZE: the shared memory size for that target. must be >= the " + "size the target was compiled for\n" + "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_QUIET: do not print extra informational output\n", argv0, MEM_LIMIT, doc_path); @@ -1115,6 +1116,34 @@ int main(int argc, char **argv_orig, char **envp) { } + fsrv->kill_signal = SIGKILL; + char *afl_kill_signal_env = getenv("AFL_KILL_SIGNAL"); + if (afl_kill_signal_env && afl_kill_signal_env[0]) { + + char *endptr; + u8 signal_code; + signal_code = (u8)strtoul(afl_kill_signal_env, &endptr, 10); + /* Did we manage to parse the full string? */ + if (*endptr != '\0' || endptr == afl_kill_signal_env) { + + FATAL("Invalid AFL_KILL_SIGNAL: %s (expected unsigned int)", + afl_kill_signal_env); + + } + + fsrv->kill_signal = signal_code; + + } else { + + char *sigstr = alloc_printf("%d", (int)SIGKILL); + if (!sigstr) { FATAL("Failed to alloc mem for signal buf"); } + + /* Set the env for signal handler */ + setenv("AFL_KILL_SIGNAL", sigstr, 1); + free(sigstr); + + } + if (getenv("AFL_CRASH_EXITCODE")) { long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 09d97f58..342de9c8 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -855,6 +855,7 @@ static void usage(u8 *argv0) { "Environment variables used:\n" "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n" + "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" " the target was compiled for\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" @@ -1134,6 +1135,34 @@ int main(int argc, char **argv_orig, char **envp) { } + fsrv->kill_signal = SIGKILL; + char *afl_kill_signal_env = getenv("AFL_KILL_SIGNAL"); + if (afl_kill_signal_env && afl_kill_signal_env[0]) { + + char *endptr; + u8 signal_code; + signal_code = (u8)strtoul(afl_kill_signal_env, &endptr, 10); + /* Did we manage to parse the full string? */ + if (*endptr != '\0' || endptr == afl_kill_signal_env) { + + FATAL("Invalid AFL_KILL_SIGNAL: %s (expected unsigned int)", + afl_kill_signal_env); + + } + + fsrv->kill_signal = signal_code; + + } else { + + char *sigstr = alloc_printf("%d", (int)SIGKILL); + if (!sigstr) { FATAL("Failed to alloc mem for signal buf"); } + + /* Set the env for signal handler */ + setenv("AFL_KILL_SIGNAL", sigstr, 1); + free(sigstr); + + } + if (getenv("AFL_CRASH_EXITCODE")) { long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); -- cgit 1.4.1 From e8c1b43a3de7ae3d173c749c3be4e58a95d3372b Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 21 Jan 2021 15:24:34 +0100 Subject: fix docs --- docs/env_variables.md | 2 +- src/afl-fuzz.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index 26128b01..baf69e6a 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -519,7 +519,7 @@ The corpus minimization script offers very little customization: a modest security risk on multi-user systems with rogue users, but should be safe on dedicated fuzzing boxes. -# #6) Settings for afl-tmin +## 7) Settings for afl-tmin Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be searched for afl-qemu-trace. In addition to this, `TMPDIR` may be used if a diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 95bc0694..9a8159bd 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -123,7 +123,7 @@ static void usage(u8 *argv0, int more_help) { "it.\n" " if using QEMU, just use -c 0.\n" " -l cmplog_level - set the complexity/intensivity of CmpLog.\n" - " Values: 1 (default), 2 (intensive) and 3 (heavy)\n\n" + " Values: 1 (integer+string), 2 (+FP) and 3 (+transform)\n\n" "Fuzzing behavior settings:\n" " -Z - sequential queue selection instead of weighted " -- cgit 1.4.1 From 0a12d519f7d914f16ead8d31f426f814021ec3dc Mon Sep 17 00:00:00 2001 From: Edznux Date: Fri, 22 Jan 2021 00:18:56 +0100 Subject: Add better doc for AFL_STATSD_TAGS_FLAVOR --- docs/env_variables.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index baf69e6a..66d85749 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -431,13 +431,18 @@ checks or alter some of the more exotic semantics of the tool: normally done when starting up the forkserver and causes a pretty significant performance drop. - - Setting `AFL_STATSD` enable StatsD metrics collection. + - Setting `AFL_STATSD` enables StatsD metrics collection. By default AFL++ will send these metrics over UDP to 127.0.0.1:8125. - The host and port are configurable with `AFL_STATSD_HOST` and `AFL_STATSD_PORT` - respectively. - To get the most out of this, you should provide `AFL_STATSD_TAGS_FLAVOR` that - matches your StatsD server. - Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`. + The host and port are configurable with `AFL_STATSD_HOST` and `AFL_STATSD_PORT` respectively. + To enable tags (banner and afl_version) you should provide `AFL_STATSD_TAGS_FLAVOR` that matches + your StatsD server (see `AFL_STATSD_TAGS_FLAVOR`) + + - Setting `AFL_STATSD_TAGS_FLAVOR` to one of `dogstatsd`, `librato`, `signalfx` or `influxdb` + allows you to add tags to your fuzzing instances. This is especially useful when running + multiple instances (`-M/-S` for example). Applied tags are `banner` and `afl_version`. + `banner` corresponds to the name of the fuzzer provided through `-M/-S`. + `afl_version` corresponds to the currently running afl version (e.g `++3.0c`). + Default (empty/non present) will add no tags to the metrics. - Setting `AFL_CRASH_EXITCODE` sets the exit code afl treats as crash. For example, if `AFL_CRASH_EXITCODE='-1'` is set, each input resulting -- cgit 1.4.1 From 9d08f0d098c91e69b5fe41674e4c5d05363af604 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 30 Jan 2021 15:39:47 +0100 Subject: added AFL_CMPLOG_ONLY_NEW feature --- docs/Changelog.md | 2 + docs/env_variables.md | 5 ++ include/afl-fuzz.h | 2 +- include/common.h | 2 +- include/envs.h | 1 + src/afl-analyze.c | 22 ++++---- src/afl-common.c | 6 +-- src/afl-fuzz-init.c | 3 ++ src/afl-fuzz-one.c | 5 +- src/afl-fuzz-redqueen.c | 135 +++++++++++++++++++++++++----------------------- src/afl-fuzz-state.c | 7 +++ src/afl-fuzz.c | 35 +++++++------ src/afl-showmap.c | 24 ++++----- src/afl-tmin.c | 24 ++++----- 14 files changed, 147 insertions(+), 126 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 329b7520..6e59961b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,8 @@ sending a mail to . transformations (e.g. toupper, tolower, to/from hex, xor, arithmetics, etc.). this is costly hence new command line option -l that sets the intensity (values 1 to 3). recommended is 1 or 2. + - added `AFL_CMPLOG_ONLY_NEW` to not use cmplog on initial testcases from + `-i` or resumes (as these have most likely already been done) - fix crash for very, very fast targets+systems (thanks to mhlakhani for reporting) - if determinstic mode is active (-D, or -M without -d) then we sync diff --git a/docs/env_variables.md b/docs/env_variables.md index 66d85749..4c3b1cfb 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -287,6 +287,11 @@ checks or alter some of the more exotic semantics of the tool: the target. This must be equal or larger than the size the target was compiled with. + - `AFL_CMPLOG_ONLY_NEW` will only perform the expensive cmplog feature for + newly found testcases and not for testcases that are loaded on startup + (`-i in`). This is an important feature to set when resuming a fuzzing + session. + - `AFL_TESTCACHE_SIZE` allows you to override the size of `#define TESTCASE_CACHE` in config.h. Recommended values are 50-250MB - or more if your fuzzing finds a huge amount of paths for large inputs. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 12db9e4d..e8a21cb5 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -384,7 +384,7 @@ typedef struct afl_env_vars { afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, - afl_cycle_schedules, afl_expand_havoc, afl_statsd; + afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, diff --git a/include/common.h b/include/common.h index bdaa1735..bb8831f2 100644 --- a/include/common.h +++ b/include/common.h @@ -47,7 +47,7 @@ void argv_cpy_free(char **argv); char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv); char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv); char * get_afl_env(char *env); -u8 *get_libqasan_path(u8 *own_loc); +u8 * get_libqasan_path(u8 *own_loc); extern u8 be_quiet; extern u8 *doc_path; /* path to documentation dir */ diff --git a/include/envs.h b/include/envs.h index 926c9e27..210b34a6 100644 --- a/include/envs.h +++ b/include/envs.h @@ -28,6 +28,7 @@ static char *afl_environment_variables[] = { "AFL_CC", "AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", + "AFL_CMPLOG_ONLY_NEW", "AFL_CODE_END", "AFL_CODE_START", "AFL_COMPCOV_BINNAME", diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 28598ba0..20aef2da 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -1079,28 +1079,28 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !in_file) { usage(argv[0]); } if (qemu_mode && getenv("AFL_USE_QASAN")) { - - u8* preload = getenv("AFL_PRELOAD"); - u8* libqasan = get_libqasan_path(argv_orig[0]); - + + u8 *preload = getenv("AFL_PRELOAD"); + u8 *libqasan = get_libqasan_path(argv_orig[0]); + if (!preload) { - + setenv("AFL_PRELOAD", libqasan, 0); - + } else { - + u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2); strcpy(result, libqasan); strcat(result, " "); strcat(result, preload); - + setenv("AFL_PRELOAD", result, 1); ck_free(result); - + } - + ck_free(libqasan); - + } map_size = get_map_size(); diff --git a/src/afl-common.c b/src/afl-common.c index a69f2e97..235c4c05 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -364,11 +364,7 @@ u8 *get_libqasan_path(u8 *own_loc) { cp = alloc_printf("%s/libqasan.so", own_copy); ck_free(own_copy); - if (!access(cp, X_OK)) { - - return cp; - - } + if (!access(cp, X_OK)) { return cp; } } else { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 1808f0a1..2a7864f9 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -25,6 +25,7 @@ #include "afl-fuzz.h" #include +#include "cmplog.h" #ifdef HAVE_AFFINITY @@ -833,6 +834,8 @@ void perform_dry_run(afl_state_t *afl) { } + if (afl->afl_env.afl_cmplog_only_new) { q->colorized = CMPLOG_LVL_MAX; } + u8 *fn = strrchr(q->fname, '/') + 1; ACTF("Attempting dry run with '%s'...", fn); diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index ff766158..0cf889a8 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -26,6 +26,7 @@ #include "afl-fuzz.h" #include #include +#include "cmplog.h" /* MOpt */ @@ -553,7 +554,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (unlikely(len < 4)) { - afl->queue_cur->colorized = 0xff; + afl->queue_cur->colorized = CMPLOG_LVL_MAX; } else { @@ -2981,7 +2982,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (unlikely(len < 4)) { - afl->queue_cur->colorized = 0xff; + afl->queue_cur->colorized = CMPLOG_LVL_MAX; } else { diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index fc620781..d7657c1d 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -1118,7 +1118,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, #ifdef ARITHMETIC_LESSER_GREATER if (lvl < LVL3 || attr == IS_TRANSFORM) { return 0; } - if (!(attr & (IS_GREATER | IS_LESSER)) || SHAPE_BYTES(h->shape) < 4) { return 0; } + if (!(attr & (IS_GREATER | IS_LESSER)) || SHAPE_BYTES(h->shape) < 4) { + + return 0; + + } // transform >= to < and <= to > if ((attr & IS_EQUAL) && (attr & (IS_GREATER | IS_LESSER))) { @@ -1138,110 +1142,110 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // lesser/greater FP comparison if (attr >= IS_FP && attr < IS_FP_MOD) { - u64 repl_new; - - if (attr & IS_GREATER) { + u64 repl_new; - if (SHAPE_BYTES(h->shape) == 4 && its_len >= 4) { + if (attr & IS_GREATER) { - float *f = (float *)&repl; - float g = *f; - g += 1.0; - u32 *r = (u32 *)&g; - repl_new = (u32)*r; + if (SHAPE_BYTES(h->shape) == 4 && its_len >= 4) { - } else if (SHAPE_BYTES(h->shape) == 8 && its_len >= 8) { + float *f = (float *)&repl; + float g = *f; + g += 1.0; + u32 *r = (u32 *)&g; + repl_new = (u32)*r; - double *f = (double *)&repl; - double g = *f; - g += 1.0; + } else if (SHAPE_BYTES(h->shape) == 8 && its_len >= 8) { - u64 *r = (u64 *)&g; - repl_new = *r; + double *f = (double *)&repl; + double g = *f; + g += 1.0; - } else { + u64 *r = (u64 *)&g; + repl_new = *r; - return 0; + } else { - } + return 0; - changed_val = repl_new; + } - if (unlikely(cmp_extend_encoding( - afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, - taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + changed_val = repl_new; - return 1; + if (unlikely(cmp_extend_encoding( + afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { - } + return 1; - } else { + } - if (SHAPE_BYTES(h->shape) == 4) { + } else { - float *f = (float *)&repl; - float g = *f; - g -= 1.0; - u32 *r = (u32 *)&g; - repl_new = (u32)*r; + if (SHAPE_BYTES(h->shape) == 4) { - } else if (SHAPE_BYTES(h->shape) == 8) { + float *f = (float *)&repl; + float g = *f; + g -= 1.0; + u32 *r = (u32 *)&g; + repl_new = (u32)*r; - double *f = (double *)&repl; - double g = *f; - g -= 1.0; - u64 *r = (u64 *)&g; - repl_new = *r; + } else if (SHAPE_BYTES(h->shape) == 8) { - } else { + double *f = (double *)&repl; + double g = *f; + g -= 1.0; + u64 *r = (u64 *)&g; + repl_new = *r; - return 0; + } else { - } + return 0; - changed_val = repl_new; + } - if (unlikely(cmp_extend_encoding( - afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, - taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + changed_val = repl_new; - return 1; + if (unlikely(cmp_extend_encoding( + afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { - } + return 1; } - // transform double to float, llvm likes to do that internally ... - if (SHAPE_BYTES(h->shape) == 8 && its_len >= 4) { + } - double *f = (double *)&repl; - float g = (float)*f; - repl_new = 0; + // transform double to float, llvm likes to do that internally ... + if (SHAPE_BYTES(h->shape) == 8 && its_len >= 4) { + + double *f = (double *)&repl; + float g = (float)*f; + repl_new = 0; #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - memcpy((char *)&repl_new, (char *)&g, 4); + memcpy((char *)&repl_new, (char *)&g, 4); #else - memcpy(((char *)&repl_new) + 4, (char *)&g, 4); + memcpy(((char *)&repl_new) + 4, (char *)&g, 4); #endif - changed_val = repl_new; - h->shape = 3; // modify shape - - // fprintf(stderr, "DOUBLE2FLOAT %llx\n", repl_new); + changed_val = repl_new; + h->shape = 3; // modify shape - if (unlikely(cmp_extend_encoding( - afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, - taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { + // fprintf(stderr, "DOUBLE2FLOAT %llx\n", repl_new); - h->shape = 7; // recover shape - return 1; - - } + if (unlikely(cmp_extend_encoding( + afl, h, pattern, repl_new, o_pattern, changed_val, 16, idx, + taint_len, orig_buf, buf, cbuf, len, 1, lvl, status))) { h->shape = 7; // recover shape + return 1; } + h->shape = 7; // recover shape + } + } + else if (attr < IS_FP) { // lesser/greater integer comparison @@ -1707,6 +1711,7 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, try_to_add_to_dictN(afl, s128_v1, SHAPE_BYTES(h->shape)); } else + #endif { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 8423a3d1..5040e3ef 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -236,6 +236,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_custom_mutator_only = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_CMPLOG_ONLY_NEW", + + afl_environment_variable_len)) { + + afl->afl_env.afl_cmplog_only_new = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_NO_UI", afl_environment_variable_len)) { afl->afl_env.afl_no_ui = diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 312d9424..9d9b0434 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -181,6 +181,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n" "AFL_BENCH_JUST_ONE: run the target just once\n" "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n" + "AFL_CMPLOG_ONLY_NEW: do not run cmplog on initial testcases (good for resumes!)\n" "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n" "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n" @@ -326,8 +327,9 @@ int main(int argc, char **argv_orig, char **envp) { "compile time)"); } + #endif - + char **argv = argv_cpy_dup(argc, argv_orig); afl_state_t *afl = calloc(1, sizeof(afl_state_t)); @@ -356,8 +358,7 @@ int main(int argc, char **argv_orig, char **envp) { while ((opt = getopt( argc, argv, - "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNo:p:RQs:S:t:T:UV:Wx:Z")) > - 0) { + "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNo:p:RQs:S:t:T:UV:Wx:Z")) > 0) { switch (opt) { @@ -984,31 +985,31 @@ int main(int argc, char **argv_orig, char **envp) { usage(argv[0], show_help); } - + if (afl->fsrv.qemu_mode && getenv("AFL_USE_QASAN")) { - - u8* preload = getenv("AFL_PRELOAD"); - u8* libqasan = get_libqasan_path(argv_orig[0]); - + + u8 *preload = getenv("AFL_PRELOAD"); + u8 *libqasan = get_libqasan_path(argv_orig[0]); + if (!preload) { - + setenv("AFL_PRELOAD", libqasan, 0); - + } else { - + u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2); strcpy(result, libqasan); strcat(result, " "); strcat(result, preload); - + setenv("AFL_PRELOAD", result, 1); ck_free(result); - + } - + afl->afl_env.afl_preload = (u8 *)getenv("AFL_PRELOAD"); ck_free(libqasan); - + } if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260; @@ -1270,7 +1271,7 @@ int main(int argc, char **argv_orig, char **envp) { "instead of using AFL_PRELOAD?"); } - + if (afl->afl_env.afl_preload) { if (afl->fsrv.qemu_mode) { @@ -1322,7 +1323,7 @@ int main(int argc, char **argv_orig, char **envp) { FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD"); } - + save_cmdline(afl, argc, argv); fix_up_banner(afl, argv[optind]); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index f3cd5a90..62bf1021 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -942,30 +942,30 @@ int main(int argc, char **argv_orig, char **envp) { } if (optind == argc || !out_file) { usage(argv[0]); } - + if (fsrv->qemu_mode && getenv("AFL_USE_QASAN")) { - - u8* preload = getenv("AFL_PRELOAD"); - u8* libqasan = get_libqasan_path(argv_orig[0]); - + + u8 *preload = getenv("AFL_PRELOAD"); + u8 *libqasan = get_libqasan_path(argv_orig[0]); + if (!preload) { - + setenv("AFL_PRELOAD", libqasan, 0); - + } else { - + u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2); strcpy(result, libqasan); strcat(result, " "); strcat(result, preload); - + setenv("AFL_PRELOAD", result, 1); ck_free(result); - + } - + ck_free(libqasan); - + } if (in_dir) { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 9e9e2d63..09b5211d 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1074,30 +1074,30 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !in_file || !output_file) { usage(argv[0]); } check_environment_vars(envp); - + if (fsrv->qemu_mode && getenv("AFL_USE_QASAN")) { - - u8* preload = getenv("AFL_PRELOAD"); - u8* libqasan = get_libqasan_path(argv_orig[0]); - + + u8 *preload = getenv("AFL_PRELOAD"); + u8 *libqasan = get_libqasan_path(argv_orig[0]); + if (!preload) { - + setenv("AFL_PRELOAD", libqasan, 0); - + } else { - + u8 *result = ck_alloc(strlen(libqasan) + strlen(preload) + 2); strcpy(result, libqasan); strcat(result, " "); strcat(result, preload); - + setenv("AFL_PRELOAD", result, 1); ck_free(result); - + } - + ck_free(libqasan); - + } /* initialize cmplog_mode */ -- cgit 1.4.1 From 267b085f80074e61bdacf1e85e99014b6b2cdad2 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 10 Feb 2021 15:15:16 +0100 Subject: dlmalloc only for non glibc qasan and AFL_QEMU_FORCE_DFL --- docs/env_variables.md | 6 + qemu_mode/QEMUAFL_VERSION | 2 +- qemu_mode/libqasan/dlmalloc.c | 4769 ++++++++++++++++------------------------- qemu_mode/libqasan/malloc.c | 147 +- qemu_mode/qemuafl | 2 +- 5 files changed, 2003 insertions(+), 2923 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index 4c3b1cfb..ab56c178 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -514,6 +514,12 @@ The QEMU wrapper used to instrument binary-only code supports several settings: stack pointer in which QEMU can find the return address when `start addr` is hit. + - With `AFL_USE_QASAN` you can enable QEMU AddressSanitizer for dynamically + linked binaries. + + - With `AFL_QEMU_FORCE_DFL` you force QEMU to ignore the registered singal + handlers of the target. + ## 6) Settings for afl-cmin The corpus minimization script offers very little customization: diff --git a/qemu_mode/QEMUAFL_VERSION b/qemu_mode/QEMUAFL_VERSION index 97184973..d9f0ec33 100644 --- a/qemu_mode/QEMUAFL_VERSION +++ b/qemu_mode/QEMUAFL_VERSION @@ -1 +1 @@ -6ab6bf28de +47722f64e4 diff --git a/qemu_mode/libqasan/dlmalloc.c b/qemu_mode/libqasan/dlmalloc.c index 3c7dcea8..7e3cb159 100644 --- a/qemu_mode/libqasan/dlmalloc.c +++ b/qemu_mode/libqasan/dlmalloc.c @@ -1,3 +1,7 @@ +#include + +#ifndef __GLIBC__ + /* This is a version (aka dlmalloc) of malloc/free/realloc written by Doug Lea and released to the public domain, as explained at @@ -203,12 +207,9 @@ mspaces as thread-locals. For example: static __thread mspace tlms = 0; void* tlmalloc(size_t bytes) { - if (tlms == 0) tlms = create_mspace(0, 0); return mspace_malloc(tlms, bytes); - } - void tlfree(void* mem) { mspace_free(tlms, mem); } Unless FOOTERS is defined, each mspace is completely independent. @@ -528,198 +529,197 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP /* Version identifier to allow people to support multiple versions */ #ifndef DLMALLOC_VERSION - #define DLMALLOC_VERSION 20806 -#endif /* DLMALLOC_VERSION */ +#define DLMALLOC_VERSION 20806 +#endif /* DLMALLOC_VERSION */ #ifndef DLMALLOC_EXPORT - #define DLMALLOC_EXPORT extern +#define DLMALLOC_EXPORT extern #endif #ifndef WIN32 - #ifdef _WIN32 - #define WIN32 1 - #endif /* _WIN32 */ - #ifdef _WIN32_WCE - #define LACKS_FCNTL_H - #define WIN32 1 - #endif /* _WIN32_WCE */ -#endif /* WIN32 */ +#ifdef _WIN32 +#define WIN32 1 +#endif /* _WIN32 */ +#ifdef _WIN32_WCE +#define LACKS_FCNTL_H +#define WIN32 1 +#endif /* _WIN32_WCE */ +#endif /* WIN32 */ #ifdef WIN32 - #define WIN32_LEAN_AND_MEAN - #include - #include - #define HAVE_MMAP 1 - #define HAVE_MORECORE 0 - #define LACKS_UNISTD_H - #define LACKS_SYS_PARAM_H - #define LACKS_SYS_MMAN_H - #define LACKS_STRING_H - #define LACKS_STRINGS_H - #define LACKS_SYS_TYPES_H - #define LACKS_ERRNO_H - #define LACKS_SCHED_H - #ifndef MALLOC_FAILURE_ACTION - #define MALLOC_FAILURE_ACTION - #endif /* MALLOC_FAILURE_ACTION */ - #ifndef MMAP_CLEARS - #ifdef _WIN32_WCE /* WINCE reportedly does not clear */ - #define MMAP_CLEARS 0 - #else - #define MMAP_CLEARS 1 - #endif /* _WIN32_WCE */ - #endif /*MMAP_CLEARS */ -#endif /* WIN32 */ +#define WIN32_LEAN_AND_MEAN +#include +#include +#define HAVE_MMAP 1 +#define HAVE_MORECORE 0 +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H +#define LACKS_STRING_H +#define LACKS_STRINGS_H +#define LACKS_SYS_TYPES_H +#define LACKS_ERRNO_H +#define LACKS_SCHED_H +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef MMAP_CLEARS +#ifdef _WIN32_WCE /* WINCE reportedly does not clear */ +#define MMAP_CLEARS 0 +#else +#define MMAP_CLEARS 1 +#endif /* _WIN32_WCE */ +#endif /*MMAP_CLEARS */ +#endif /* WIN32 */ #if defined(DARWIN) || defined(_DARWIN) - /* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ - #ifndef HAVE_MORECORE - #define HAVE_MORECORE 0 - #define HAVE_MMAP 1 - /* OSX allocators provide 16 byte alignment */ - #ifndef MALLOC_ALIGNMENT - #define MALLOC_ALIGNMENT ((size_t)16U) - #endif - #endif /* HAVE_MORECORE */ -#endif /* DARWIN */ +/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ +#ifndef HAVE_MORECORE +#define HAVE_MORECORE 0 +#define HAVE_MMAP 1 +/* OSX allocators provide 16 byte alignment */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)16U) +#endif +#endif /* HAVE_MORECORE */ +#endif /* DARWIN */ #ifndef LACKS_SYS_TYPES_H - #include /* For size_t */ -#endif /* LACKS_SYS_TYPES_H */ +#include /* For size_t */ +#endif /* LACKS_SYS_TYPES_H */ /* The maximum possible size_t value has all bits set */ -#define MAX_SIZE_T (~(size_t)0) - -#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */ - #define USE_LOCKS \ - ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \ - (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0)) -#endif /* USE_LOCKS */ - -#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */ - #if ((defined(__GNUC__) && \ - ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ - defined(__i386__) || defined(__x86_64__))) || \ - (defined(_MSC_VER) && _MSC_VER >= 1310)) - #ifndef USE_SPIN_LOCKS - #define USE_SPIN_LOCKS 1 - #endif /* USE_SPIN_LOCKS */ - #elif USE_SPIN_LOCKS - #error "USE_SPIN_LOCKS defined without implementation" - #endif /* ... locks available... */ +#define MAX_SIZE_T (~(size_t)0) + +#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */ +#define USE_LOCKS ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \ + (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0)) +#endif /* USE_LOCKS */ + +#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */ +#if ((defined(__GNUC__) && \ + ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ + defined(__i386__) || defined(__x86_64__))) || \ + (defined(_MSC_VER) && _MSC_VER>=1310)) +#ifndef USE_SPIN_LOCKS +#define USE_SPIN_LOCKS 1 +#endif /* USE_SPIN_LOCKS */ +#elif USE_SPIN_LOCKS +#error "USE_SPIN_LOCKS defined without implementation" +#endif /* ... locks available... */ #elif !defined(USE_SPIN_LOCKS) - #define USE_SPIN_LOCKS 0 -#endif /* USE_LOCKS */ +#define USE_SPIN_LOCKS 0 +#endif /* USE_LOCKS */ #ifndef ONLY_MSPACES - #define ONLY_MSPACES 0 -#endif /* ONLY_MSPACES */ +#define ONLY_MSPACES 0 +#endif /* ONLY_MSPACES */ #ifndef MSPACES - #if ONLY_MSPACES - #define MSPACES 1 - #else /* ONLY_MSPACES */ - #define MSPACES 0 - #endif /* ONLY_MSPACES */ -#endif /* MSPACES */ +#if ONLY_MSPACES +#define MSPACES 1 +#else /* ONLY_MSPACES */ +#define MSPACES 0 +#endif /* ONLY_MSPACES */ +#endif /* MSPACES */ #ifndef MALLOC_ALIGNMENT - #define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *))) -#endif /* MALLOC_ALIGNMENT */ +#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *))) +#endif /* MALLOC_ALIGNMENT */ #ifndef FOOTERS - #define FOOTERS 0 -#endif /* FOOTERS */ +#define FOOTERS 0 +#endif /* FOOTERS */ #ifndef ABORT - #define ABORT abort() -#endif /* ABORT */ +#define ABORT abort() +#endif /* ABORT */ #ifndef ABORT_ON_ASSERT_FAILURE - #define ABORT_ON_ASSERT_FAILURE 1 -#endif /* ABORT_ON_ASSERT_FAILURE */ +#define ABORT_ON_ASSERT_FAILURE 1 +#endif /* ABORT_ON_ASSERT_FAILURE */ #ifndef PROCEED_ON_ERROR - #define PROCEED_ON_ERROR 0 -#endif /* PROCEED_ON_ERROR */ +#define PROCEED_ON_ERROR 0 +#endif /* PROCEED_ON_ERROR */ #ifndef INSECURE - #define INSECURE 0 -#endif /* INSECURE */ +#define INSECURE 0 +#endif /* INSECURE */ #ifndef MALLOC_INSPECT_ALL - #define MALLOC_INSPECT_ALL 0 -#endif /* MALLOC_INSPECT_ALL */ +#define MALLOC_INSPECT_ALL 0 +#endif /* MALLOC_INSPECT_ALL */ #ifndef HAVE_MMAP - #define HAVE_MMAP 1 -#endif /* HAVE_MMAP */ +#define HAVE_MMAP 1 +#endif /* HAVE_MMAP */ #ifndef MMAP_CLEARS - #define MMAP_CLEARS 1 -#endif /* MMAP_CLEARS */ +#define MMAP_CLEARS 1 +#endif /* MMAP_CLEARS */ #ifndef HAVE_MREMAP - #ifdef linux - #define HAVE_MREMAP 1 - #define _GNU_SOURCE /* Turns on mremap() definition */ - #else /* linux */ - #define HAVE_MREMAP 0 - #endif /* linux */ -#endif /* HAVE_MREMAP */ +#ifdef linux +#define HAVE_MREMAP 1 +#define _GNU_SOURCE /* Turns on mremap() definition */ +#else /* linux */ +#define HAVE_MREMAP 0 +#endif /* linux */ +#endif /* HAVE_MREMAP */ #ifndef MALLOC_FAILURE_ACTION - #define MALLOC_FAILURE_ACTION errno = ENOMEM; -#endif /* MALLOC_FAILURE_ACTION */ +#define MALLOC_FAILURE_ACTION errno = ENOMEM; +#endif /* MALLOC_FAILURE_ACTION */ #ifndef HAVE_MORECORE - #if ONLY_MSPACES - #define HAVE_MORECORE 0 - #else /* ONLY_MSPACES */ - #define HAVE_MORECORE 1 - #endif /* ONLY_MSPACES */ -#endif /* HAVE_MORECORE */ +#if ONLY_MSPACES +#define HAVE_MORECORE 0 +#else /* ONLY_MSPACES */ +#define HAVE_MORECORE 1 +#endif /* ONLY_MSPACES */ +#endif /* HAVE_MORECORE */ #if !HAVE_MORECORE - #define MORECORE_CONTIGUOUS 0 -#else /* !HAVE_MORECORE */ - #define MORECORE_DEFAULT sbrk - #ifndef MORECORE_CONTIGUOUS - #define MORECORE_CONTIGUOUS 1 - #endif /* MORECORE_CONTIGUOUS */ -#endif /* HAVE_MORECORE */ +#define MORECORE_CONTIGUOUS 0 +#else /* !HAVE_MORECORE */ +#define MORECORE_DEFAULT sbrk +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif /* MORECORE_CONTIGUOUS */ +#endif /* HAVE_MORECORE */ #ifndef DEFAULT_GRANULARITY - #if (MORECORE_CONTIGUOUS || defined(WIN32)) - #define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ - #else /* MORECORE_CONTIGUOUS */ - #define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) - #endif /* MORECORE_CONTIGUOUS */ -#endif /* DEFAULT_GRANULARITY */ +#if (MORECORE_CONTIGUOUS || defined(WIN32)) +#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ +#else /* MORECORE_CONTIGUOUS */ +#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) +#endif /* MORECORE_CONTIGUOUS */ +#endif /* DEFAULT_GRANULARITY */ #ifndef DEFAULT_TRIM_THRESHOLD - #ifndef MORECORE_CANNOT_TRIM - #define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) - #else /* MORECORE_CANNOT_TRIM */ - #define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T - #endif /* MORECORE_CANNOT_TRIM */ -#endif /* DEFAULT_TRIM_THRESHOLD */ +#ifndef MORECORE_CANNOT_TRIM +#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) +#else /* MORECORE_CANNOT_TRIM */ +#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T +#endif /* MORECORE_CANNOT_TRIM */ +#endif /* DEFAULT_TRIM_THRESHOLD */ #ifndef DEFAULT_MMAP_THRESHOLD - #if HAVE_MMAP - #define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) - #else /* HAVE_MMAP */ - #define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T - #endif /* HAVE_MMAP */ -#endif /* DEFAULT_MMAP_THRESHOLD */ +#if HAVE_MMAP +#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) +#else /* HAVE_MMAP */ +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* DEFAULT_MMAP_THRESHOLD */ #ifndef MAX_RELEASE_CHECK_RATE - #if HAVE_MMAP - #define MAX_RELEASE_CHECK_RATE 4095 - #else - #define MAX_RELEASE_CHECK_RATE MAX_SIZE_T - #endif /* HAVE_MMAP */ -#endif /* MAX_RELEASE_CHECK_RATE */ +#if HAVE_MMAP +#define MAX_RELEASE_CHECK_RATE 4095 +#else +#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* MAX_RELEASE_CHECK_RATE */ #ifndef USE_BUILTIN_FFS - #define USE_BUILTIN_FFS 0 -#endif /* USE_BUILTIN_FFS */ +#define USE_BUILTIN_FFS 0 +#endif /* USE_BUILTIN_FFS */ #ifndef USE_DEV_RANDOM - #define USE_DEV_RANDOM 0 -#endif /* USE_DEV_RANDOM */ +#define USE_DEV_RANDOM 0 +#endif /* USE_DEV_RANDOM */ #ifndef NO_MALLINFO - #define NO_MALLINFO 0 -#endif /* NO_MALLINFO */ +#define NO_MALLINFO 0 +#endif /* NO_MALLINFO */ #ifndef MALLINFO_FIELD_TYPE - #define MALLINFO_FIELD_TYPE size_t -#endif /* MALLINFO_FIELD_TYPE */ +#define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ #ifndef NO_MALLOC_STATS - #define NO_MALLOC_STATS 0 -#endif /* NO_MALLOC_STATS */ +#define NO_MALLOC_STATS 0 +#endif /* NO_MALLOC_STATS */ #ifndef NO_SEGMENT_TRAVERSAL - #define NO_SEGMENT_TRAVERSAL 0 -#endif /* NO_SEGMENT_TRAVERSAL */ +#define NO_SEGMENT_TRAVERSAL 0 +#endif /* NO_SEGMENT_TRAVERSAL */ /* mallopt tuning options. SVID/XPG defines four standard parameter @@ -731,9 +731,9 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP #undef M_TRIM_THRESHOLD #undef M_GRANULARITY #undef M_MMAP_THRESHOLD -#define M_TRIM_THRESHOLD (-1) -#define M_GRANULARITY (-2) -#define M_MMAP_THRESHOLD (-3) +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) /* ------------------------ Mallinfo declarations ------------------------ */ @@ -762,32 +762,28 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP /* #define HAVE_USR_INCLUDE_MALLOC_H */ - #ifdef HAVE_USR_INCLUDE_MALLOC_H - #include "/usr/include/malloc.h" - #else /* HAVE_USR_INCLUDE_MALLOC_H */ - #ifndef STRUCT_MALLINFO_DECLARED - /* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is - * defined */ - #define _STRUCT_MALLINFO - #define STRUCT_MALLINFO_DECLARED 1 +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else /* HAVE_USR_INCLUDE_MALLOC_H */ +#ifndef STRUCT_MALLINFO_DECLARED +/* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is defined */ +#define _STRUCT_MALLINFO +#define STRUCT_MALLINFO_DECLARED 1 struct mallinfo { - - MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ - MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ - MALLINFO_FIELD_TYPE smblks; /* always 0 */ - MALLINFO_FIELD_TYPE hblks; /* always 0 */ - MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ - MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ - MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ - MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ - MALLINFO_FIELD_TYPE fordblks; /* total free space */ - MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ - + MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ + MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ + MALLINFO_FIELD_TYPE smblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ + MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ + MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ + MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ + MALLINFO_FIELD_TYPE fordblks; /* total free space */ + MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ }; - - #endif /* STRUCT_MALLINFO_DECLARED */ - #endif /* HAVE_USR_INCLUDE_MALLOC_H */ -#endif /* NO_MALLINFO */ +#endif /* STRUCT_MALLINFO_DECLARED */ +#endif /* HAVE_USR_INCLUDE_MALLOC_H */ +#endif /* NO_MALLINFO */ /* Try to persuade compilers to inline. The most critical functions for @@ -796,14 +792,14 @@ struct mallinfo { #ifndef FORCEINLINE #if defined(__GNUC__) - #define FORCEINLINE __inline __attribute__((always_inline)) +#define FORCEINLINE __inline __attribute__ ((always_inline)) #elif defined(_MSC_VER) #define FORCEINLINE __forceinline #endif #endif #ifndef NOINLINE #if defined(__GNUC__) - #define NOINLINE __attribute__((noinline)) + #define NOINLINE __attribute__ ((noinline)) #elif defined(_MSC_VER) #define NOINLINE __declspec(noinline) #else @@ -813,43 +809,42 @@ struct mallinfo { #ifdef __cplusplus extern "C" { - - #ifndef FORCEINLINE - #define FORCEINLINE inline - #endif -#endif /* __cplusplus */ #ifndef FORCEINLINE - #define FORCEINLINE + #define FORCEINLINE inline +#endif +#endif /* __cplusplus */ +#ifndef FORCEINLINE + #define FORCEINLINE #endif #if !ONLY_MSPACES /* ------------------- Declarations of public routines ------------------- */ - #ifndef USE_DL_PREFIX - #define dlcalloc calloc - #define dlfree free - #define dlmalloc malloc - #define dlmemalign memalign - #define dlposix_memalign posix_memalign - #define dlrealloc realloc - #define dlrealloc_in_place realloc_in_place - #define dlvalloc valloc - #define dlpvalloc pvalloc - #define dlmallinfo mallinfo - #define dlmallopt mallopt - #define dlmalloc_trim malloc_trim - #define dlmalloc_stats malloc_stats - #define dlmalloc_usable_size malloc_usable_size - #define dlmalloc_footprint malloc_footprint - #define dlmalloc_max_footprint malloc_max_footprint - #define dlmalloc_footprint_limit malloc_footprint_limit - #define dlmalloc_set_footprint_limit malloc_set_footprint_limit - #define dlmalloc_inspect_all malloc_inspect_all - #define dlindependent_calloc independent_calloc - #define dlindependent_comalloc independent_comalloc - #define dlbulk_free bulk_free - #endif /* USE_DL_PREFIX */ +#ifndef USE_DL_PREFIX +#define dlcalloc calloc +#define dlfree free +#define dlmalloc malloc +#define dlmemalign memalign +#define dlposix_memalign posix_memalign +#define dlrealloc realloc +#define dlrealloc_in_place realloc_in_place +#define dlvalloc valloc +#define dlpvalloc pvalloc +#define dlmallinfo mallinfo +#define dlmallopt mallopt +#define dlmalloc_trim malloc_trim +#define dlmalloc_stats malloc_stats +#define dlmalloc_usable_size malloc_usable_size +#define dlmalloc_footprint malloc_footprint +#define dlmalloc_max_footprint malloc_max_footprint +#define dlmalloc_footprint_limit malloc_footprint_limit +#define dlmalloc_set_footprint_limit malloc_set_footprint_limit +#define dlmalloc_inspect_all malloc_inspect_all +#define dlindependent_calloc independent_calloc +#define dlindependent_comalloc independent_comalloc +#define dlbulk_free bulk_free +#endif /* USE_DL_PREFIX */ /* malloc(size_t n) @@ -865,7 +860,7 @@ extern "C" { maximum supported value of n differs across systems, but is in all cases less than the maximum representable value of a size_t. */ -DLMALLOC_EXPORT void *dlmalloc(size_t); +DLMALLOC_EXPORT void* dlmalloc(size_t); /* free(void* p) @@ -874,14 +869,14 @@ DLMALLOC_EXPORT void *dlmalloc(size_t); It has no effect if p is null. If p was not malloced or already freed, free(p) will by default cause the current program to abort. */ -DLMALLOC_EXPORT void dlfree(void *); +DLMALLOC_EXPORT void dlfree(void*); /* calloc(size_t n_elements, size_t element_size); Returns a pointer to n_elements * element_size bytes, with all locations set to zero. */ -DLMALLOC_EXPORT void *dlcalloc(size_t, size_t); +DLMALLOC_EXPORT void* dlcalloc(size_t, size_t); /* realloc(void* p, size_t n) @@ -905,7 +900,7 @@ DLMALLOC_EXPORT void *dlcalloc(size_t, size_t); The old unix realloc convention of allowing the last-free'd chunk to be used as an argument to realloc is not supported. */ -DLMALLOC_EXPORT void *dlrealloc(void *, size_t); +DLMALLOC_EXPORT void* dlrealloc(void*, size_t); /* realloc_in_place(void* p, size_t n) @@ -920,7 +915,7 @@ DLMALLOC_EXPORT void *dlrealloc(void *, size_t); Returns p if successful; otherwise null. */ -DLMALLOC_EXPORT void *dlrealloc_in_place(void *, size_t); +DLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t); /* memalign(size_t alignment, size_t n); @@ -934,7 +929,7 @@ DLMALLOC_EXPORT void *dlrealloc_in_place(void *, size_t); Overreliance on memalign is a sure way to fragment space. */ -DLMALLOC_EXPORT void *dlmemalign(size_t, size_t); +DLMALLOC_EXPORT void* dlmemalign(size_t, size_t); /* int posix_memalign(void** pp, size_t alignment, size_t n); @@ -944,14 +939,14 @@ DLMALLOC_EXPORT void *dlmemalign(size_t, size_t); returns EINVAL if the alignment is not a power of two (3) fails and returns ENOMEM if memory cannot be allocated. */ -DLMALLOC_EXPORT int dlposix_memalign(void **, size_t, size_t); +DLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t); /* valloc(size_t n); Equivalent to memalign(pagesize, n), where pagesize is the page size of the system. If the pagesize is unknown, 4096 is used. */ -DLMALLOC_EXPORT void *dlvalloc(size_t); +DLMALLOC_EXPORT void* dlvalloc(size_t); /* mallopt(int parameter_number, int parameter_value) @@ -1026,7 +1021,7 @@ DLMALLOC_EXPORT size_t dlmalloc_footprint_limit(); */ DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes); - #if MALLOC_INSPECT_ALL +#if MALLOC_INSPECT_ALL /* malloc_inspect_all(void(*handler)(void *start, void *end, @@ -1048,23 +1043,19 @@ DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes); than 1000, you could write: static int count = 0; void count_chunks(void* start, void* end, size_t used, void* arg) { - if (used >= 1000) ++count; - } - then: malloc_inspect_all(count_chunks, NULL); malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined. */ -DLMALLOC_EXPORT void dlmalloc_inspect_all(void (*handler)(void *, void *, - size_t, void *), - void *arg); +DLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*), + void* arg); - #endif /* MALLOC_INSPECT_ALL */ +#endif /* MALLOC_INSPECT_ALL */ - #if !NO_MALLINFO +#if !NO_MALLINFO /* mallinfo() Returns (by copy) a struct containing various summary statistics: @@ -1088,7 +1079,7 @@ DLMALLOC_EXPORT void dlmalloc_inspect_all(void (*handler)(void *, void *, thus be inaccurate. */ DLMALLOC_EXPORT struct mallinfo dlmallinfo(void); - #endif /* NO_MALLINFO */ +#endif /* NO_MALLINFO */ /* independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); @@ -1126,7 +1117,6 @@ DLMALLOC_EXPORT struct mallinfo dlmallinfo(void); struct Node { int item; struct Node* next; }; struct Node* build_list() { - struct Node** pool; int n = read_number_of_nodes_needed(); if (n <= 0) return 0; @@ -1138,11 +1128,9 @@ DLMALLOC_EXPORT struct mallinfo dlmallinfo(void); pool[i]->next = pool[i+1]; free(pool); // Can now free the array (or not, if it is needed later) return first; - } - */ -DLMALLOC_EXPORT void **dlindependent_calloc(size_t, size_t, void **); +DLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**); /* independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); @@ -1181,7 +1169,6 @@ DLMALLOC_EXPORT void **dlindependent_calloc(size_t, size_t, void **); struct Foot { ... } void send_message(char* msg) { - int msglen = strlen(msg); size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; void* chunks[3]; @@ -1191,7 +1178,6 @@ DLMALLOC_EXPORT void **dlindependent_calloc(size_t, size_t, void **); char* body = (char*)(chunks[1]); struct Foot* foot = (struct Foot*)(chunks[2]); // ... - } In general though, independent_comalloc is worth using only for @@ -1202,7 +1188,7 @@ DLMALLOC_EXPORT void **dlindependent_calloc(size_t, size_t, void **); since it cannot reuse existing noncontiguous small chunks that might be available for some of the elements. */ -DLMALLOC_EXPORT void **dlindependent_comalloc(size_t, size_t *, void **); +DLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**); /* bulk_free(void* array[], size_t n_elements) @@ -1213,14 +1199,14 @@ DLMALLOC_EXPORT void **dlindependent_comalloc(size_t, size_t *, void **); is returned. For large arrays of pointers with poor locality, it may be worthwhile to sort this array before calling bulk_free. */ -DLMALLOC_EXPORT size_t dlbulk_free(void **, size_t n_elements); +DLMALLOC_EXPORT size_t dlbulk_free(void**, size_t n_elements); /* pvalloc(size_t n); Equivalent to valloc(minimum-page-that-holds(n)), that is, round up n to nearest pagesize. */ -DLMALLOC_EXPORT void *dlpvalloc(size_t); +DLMALLOC_EXPORT void* dlpvalloc(size_t); /* malloc_trim(size_t pad); @@ -1243,7 +1229,7 @@ DLMALLOC_EXPORT void *dlpvalloc(size_t); Malloc_trim returns 1 if it actually released any memory, else 0. */ -DLMALLOC_EXPORT int dlmalloc_trim(size_t); +DLMALLOC_EXPORT int dlmalloc_trim(size_t); /* malloc_stats(); @@ -1264,7 +1250,7 @@ DLMALLOC_EXPORT int dlmalloc_trim(size_t); malloc_stats prints only the most commonly interesting statistics. More information can be obtained by calling mallinfo. */ -DLMALLOC_EXPORT void dlmalloc_stats(void); +DLMALLOC_EXPORT void dlmalloc_stats(void); /* malloc_usable_size(void* p); @@ -1280,9 +1266,9 @@ DLMALLOC_EXPORT void dlmalloc_stats(void); p = malloc(n); assert(malloc_usable_size(p) >= 256); */ -size_t dlmalloc_usable_size(void *); +size_t dlmalloc_usable_size(void*); -#endif /* ONLY_MSPACES */ +#endif /* ONLY_MSPACES */ #if MSPACES @@ -1290,7 +1276,7 @@ size_t dlmalloc_usable_size(void *); mspace is an opaque type representing an independent region of space that supports mspace_malloc, etc. */ -typedef void *mspace; +typedef void* mspace; /* create_mspace creates and returns a new independent space with the @@ -1322,8 +1308,7 @@ DLMALLOC_EXPORT size_t destroy_mspace(mspace msp); Destroying this space will deallocate all additionally allocated space (if possible) but not the initial base. */ -DLMALLOC_EXPORT mspace create_mspace_with_base(void *base, size_t capacity, - int locked); +DLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked); /* mspace_track_large_chunks controls whether requests for large chunks @@ -1338,11 +1323,12 @@ DLMALLOC_EXPORT mspace create_mspace_with_base(void *base, size_t capacity, */ DLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable); + /* mspace_malloc behaves as malloc, but operates within the given space. */ -DLMALLOC_EXPORT void *mspace_malloc(mspace msp, size_t bytes); +DLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes); /* mspace_free behaves as free, but operates within @@ -1352,7 +1338,7 @@ DLMALLOC_EXPORT void *mspace_malloc(mspace msp, size_t bytes); free may be called instead of mspace_free because freed chunks from any space are handled by their originating spaces. */ -DLMALLOC_EXPORT void mspace_free(mspace msp, void *mem); +DLMALLOC_EXPORT void mspace_free(mspace msp, void* mem); /* mspace_realloc behaves as realloc, but operates within @@ -1363,38 +1349,33 @@ DLMALLOC_EXPORT void mspace_free(mspace msp, void *mem); realloced chunks from any space are handled by their originating spaces. */ -DLMALLOC_EXPORT void *mspace_realloc(mspace msp, void *mem, size_t newsize); +DLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize); /* mspace_calloc behaves as calloc, but operates within the given space. */ -DLMALLOC_EXPORT void *mspace_calloc(mspace msp, size_t n_elements, - size_t elem_size); +DLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); /* mspace_memalign behaves as memalign, but operates within the given space. */ -DLMALLOC_EXPORT void *mspace_memalign(mspace msp, size_t alignment, - size_t bytes); +DLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); /* mspace_independent_calloc behaves as independent_calloc, but operates within the given space. */ -DLMALLOC_EXPORT void **mspace_independent_calloc(mspace msp, size_t n_elements, - size_t elem_size, - void * chunks[]); +DLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]); /* mspace_independent_comalloc behaves as independent_comalloc, but operates within the given space. */ -DLMALLOC_EXPORT void **mspace_independent_comalloc(mspace msp, - size_t n_elements, - size_t sizes[], - void * chunks[]); +DLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]); /* mspace_footprint() returns the number of bytes obtained from the @@ -1408,18 +1389,19 @@ DLMALLOC_EXPORT size_t mspace_footprint(mspace msp); */ DLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp); - #if !NO_MALLINFO + +#if !NO_MALLINFO /* mspace_mallinfo behaves as mallinfo, but reports properties of the given space. */ DLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp); - #endif /* NO_MALLINFO */ +#endif /* NO_MALLINFO */ /* malloc_usable_size(void* p) behaves the same as malloc_usable_size; */ -DLMALLOC_EXPORT size_t mspace_usable_size(const void *mem); +DLMALLOC_EXPORT size_t mspace_usable_size(const void* mem); /* mspace_malloc_stats behaves as malloc_stats, but reports @@ -1438,13 +1420,11 @@ DLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad); */ DLMALLOC_EXPORT int mspace_mallopt(int, int); -#endif /* MSPACES */ +#endif /* MSPACES */ #ifdef __cplusplus - -} /* end of extern "C" */ - -#endif /* __cplusplus */ +} /* end of extern "C" */ +#endif /* __cplusplus */ /* ======================================================================== @@ -1459,207 +1439,195 @@ DLMALLOC_EXPORT int mspace_mallopt(int, int); /*------------------------------ internal #includes ---------------------- */ #ifdef _MSC_VER - #pragma warning(disable : 4146) /* no "unsigned" warnings */ -#endif /* _MSC_VER */ +#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif /* _MSC_VER */ #if !NO_MALLOC_STATS - #include /* for printing in malloc_stats */ -#endif /* NO_MALLOC_STATS */ +#include /* for printing in malloc_stats */ +#endif /* NO_MALLOC_STATS */ #ifndef LACKS_ERRNO_H - #include /* for MALLOC_FAILURE_ACTION */ -#endif /* LACKS_ERRNO_H */ +#include /* for MALLOC_FAILURE_ACTION */ +#endif /* LACKS_ERRNO_H */ #ifdef DEBUG - #if ABORT_ON_ASSERT_FAILURE - #undef assert - #define assert(x) \ - if (!(x)) ABORT - #else /* ABORT_ON_ASSERT_FAILURE */ - #include - #endif /* ABORT_ON_ASSERT_FAILURE */ -#else /* DEBUG */ - #ifndef assert - #define assert(x) - #endif - #define DEBUG 0 -#endif /* DEBUG */ +#if ABORT_ON_ASSERT_FAILURE +#undef assert +#define assert(x) if(!(x)) ABORT +#else /* ABORT_ON_ASSERT_FAILURE */ +#include +#endif /* ABORT_ON_ASSERT_FAILURE */ +#else /* DEBUG */ +#ifndef assert +#define assert(x) +#endif +#define DEBUG 0 +#endif /* DEBUG */ #if !defined(WIN32) && !defined(LACKS_TIME_H) - #include /* for magic initialization */ -#endif /* WIN32 */ +#include /* for magic initialization */ +#endif /* WIN32 */ #ifndef LACKS_STDLIB_H - #include /* for abort() */ -#endif /* LACKS_STDLIB_H */ +#include /* for abort() */ +#endif /* LACKS_STDLIB_H */ #ifndef LACKS_STRING_H - #include /* for memset etc */ -#endif /* LACKS_STRING_H */ +#include /* for memset etc */ +#endif /* LACKS_STRING_H */ #if USE_BUILTIN_FFS - #ifndef LACKS_STRINGS_H - #include /* for ffs */ - #endif /* LACKS_STRINGS_H */ -#endif /* USE_BUILTIN_FFS */ +#ifndef LACKS_STRINGS_H +#include /* for ffs */ +#endif /* LACKS_STRINGS_H */ +#endif /* USE_BUILTIN_FFS */ #if HAVE_MMAP - #ifndef LACKS_SYS_MMAN_H - /* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */ - #if (defined(linux) && !defined(__USE_GNU)) - #define __USE_GNU 1 - #include /* for mmap */ - #undef __USE_GNU - #else - #include /* for mmap */ - #endif /* linux */ - #endif /* LACKS_SYS_MMAN_H */ - #ifndef LACKS_FCNTL_H - #include - #endif /* LACKS_FCNTL_H */ -#endif /* HAVE_MMAP */ +#ifndef LACKS_SYS_MMAN_H +/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */ +#if (defined(linux) && !defined(__USE_GNU)) +#define __USE_GNU 1 +#include /* for mmap */ +#undef __USE_GNU +#else +#include /* for mmap */ +#endif /* linux */ +#endif /* LACKS_SYS_MMAN_H */ +#ifndef LACKS_FCNTL_H +#include +#endif /* LACKS_FCNTL_H */ +#endif /* HAVE_MMAP */ #ifndef LACKS_UNISTD_H - #include /* for sbrk, sysconf */ -#else /* LACKS_UNISTD_H */ - #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) -extern void *sbrk(ptrdiff_t); - #endif /* FreeBSD etc */ -#endif /* LACKS_UNISTD_H */ +#include /* for sbrk, sysconf */ +#else /* LACKS_UNISTD_H */ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +extern void* sbrk(ptrdiff_t); +#endif /* FreeBSD etc */ +#endif /* LACKS_UNISTD_H */ /* Declarations for locking */ #if USE_LOCKS - #ifndef WIN32 - #if defined(__SVR4) && defined(__sun) /* solaris */ - #include - #elif !defined(LACKS_SCHED_H) - #include - #endif /* solaris or LACKS_SCHED_H */ - #if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || \ - !USE_SPIN_LOCKS - #include - #endif /* USE_RECURSIVE_LOCKS ... */ - #elif defined(_MSC_VER) - #ifndef _M_AMD64 - /* These are already defined on AMD64 builds */ - #ifdef __cplusplus +#ifndef WIN32 +#if defined (__SVR4) && defined (__sun) /* solaris */ +#include +#elif !defined(LACKS_SCHED_H) +#include +#endif /* solaris or LACKS_SCHED_H */ +#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS +#include +#endif /* USE_RECURSIVE_LOCKS ... */ +#elif defined(_MSC_VER) +#ifndef _M_AMD64 +/* These are already defined on AMD64 builds */ +#ifdef __cplusplus extern "C" { - - #endif /* __cplusplus */ -LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, - LONG Comp); +#endif /* __cplusplus */ +LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp); LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value); - #ifdef __cplusplus - +#ifdef __cplusplus } - - #endif /* __cplusplus */ - #endif /* _M_AMD64 */ - #pragma intrinsic(_InterlockedCompareExchange) - #pragma intrinsic(_InterlockedExchange) - #define interlockedcompareexchange _InterlockedCompareExchange - #define interlockedexchange _InterlockedExchange - #elif defined(WIN32) && defined(__GNUC__) - #define interlockedcompareexchange(a, b, c) \ - __sync_val_compare_and_swap(a, c, b) - #define interlockedexchange __sync_lock_test_and_set - #endif /* Win32 */ -#else /* USE_LOCKS */ -#endif /* USE_LOCKS */ +#endif /* __cplusplus */ +#endif /* _M_AMD64 */ +#pragma intrinsic (_InterlockedCompareExchange) +#pragma intrinsic (_InterlockedExchange) +#define interlockedcompareexchange _InterlockedCompareExchange +#define interlockedexchange _InterlockedExchange +#elif defined(WIN32) && defined(__GNUC__) +#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b) +#define interlockedexchange __sync_lock_test_and_set +#endif /* Win32 */ +#else /* USE_LOCKS */ +#endif /* USE_LOCKS */ #ifndef LOCK_AT_FORK - #define LOCK_AT_FORK 0 +#define LOCK_AT_FORK 0 #endif /* Declarations for bit scanning on win32 */ -#if defined(_MSC_VER) && _MSC_VER >= 1300 - #ifndef BitScanForward /* Try to avoid pulling in WinNT.h */ - #ifdef __cplusplus +#if defined(_MSC_VER) && _MSC_VER>=1300 +#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */ +#ifdef __cplusplus extern "C" { - - #endif /* __cplusplus */ +#endif /* __cplusplus */ unsigned char _BitScanForward(unsigned long *index, unsigned long mask); unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); - #ifdef __cplusplus - +#ifdef __cplusplus } +#endif /* __cplusplus */ - #endif /* __cplusplus */ - - #define BitScanForward _BitScanForward - #define BitScanReverse _BitScanReverse - #pragma intrinsic(_BitScanForward) - #pragma intrinsic(_BitScanReverse) - #endif /* BitScanForward */ -#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */ +#define BitScanForward _BitScanForward +#define BitScanReverse _BitScanReverse +#pragma intrinsic(_BitScanForward) +#pragma intrinsic(_BitScanReverse) +#endif /* BitScanForward */ +#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */ #ifndef WIN32 - #ifndef malloc_getpagesize - #ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ - #ifndef _SC_PAGE_SIZE - #define _SC_PAGE_SIZE _SC_PAGESIZE - #endif - #endif - #ifdef _SC_PAGE_SIZE - #define malloc_getpagesize sysconf(_SC_PAGE_SIZE) - #else - #if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) -extern size_t getpagesize(); - #define malloc_getpagesize getpagesize() - #else - #ifdef WIN32 /* use supplied emulation of getpagesize */ - #define malloc_getpagesize getpagesize() - #else - #ifndef LACKS_SYS_PARAM_H - #include - #endif - #ifdef EXEC_PAGESIZE - #define malloc_getpagesize EXEC_PAGESIZE - #else - #ifdef NBPG - #ifndef CLSIZE - #define malloc_getpagesize NBPG - #else - #define malloc_getpagesize (NBPG * CLSIZE) - #endif - #else - #ifdef NBPC - #define malloc_getpagesize NBPC - #else - #ifdef PAGESIZE - #define malloc_getpagesize PAGESIZE - #else /* just guess */ - #define malloc_getpagesize ((size_t)4096U) - #endif - #endif - #endif - #endif - #endif - #endif - #endif - #endif +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize ((size_t)4096U) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif #endif /* ------------------- size_t and alignment properties -------------------- */ /* The byte and bit size of a size_t */ -#define SIZE_T_SIZE (sizeof(size_t)) -#define SIZE_T_BITSIZE (sizeof(size_t) << 3) +#define SIZE_T_SIZE (sizeof(size_t)) +#define SIZE_T_BITSIZE (sizeof(size_t) << 3) /* Some constants coerced to size_t */ /* Annoying but necessary to avoid errors on some platforms */ -#define SIZE_T_ZERO ((size_t)0) -#define SIZE_T_ONE ((size_t)1) -#define SIZE_T_TWO ((size_t)2) -#define SIZE_T_FOUR ((size_t)4) -#define TWO_SIZE_T_SIZES (SIZE_T_SIZE << 1) -#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE << 2) -#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES + TWO_SIZE_T_SIZES) -#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) +#define SIZE_T_ZERO ((size_t)0) +#define SIZE_T_ONE ((size_t)1) +#define SIZE_T_TWO ((size_t)2) +#define SIZE_T_FOUR ((size_t)4) +#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) +#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) +#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) +#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) /* The bit mask value corresponding to MALLOC_ALIGNMENT */ -#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) +#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) /* True if address a has acceptable alignment */ -#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) +#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) /* the number of bytes to offset an address to align it */ -#define align_offset(A) \ - ((((size_t)(A)&CHUNK_ALIGN_MASK) == 0) \ - ? 0 \ - : ((MALLOC_ALIGNMENT - ((size_t)(A)&CHUNK_ALIGN_MASK)) & \ - CHUNK_ALIGN_MASK)) +#define align_offset(A)\ + ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ + ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) /* -------------------------- MMAP preliminaries ------------------------- */ @@ -1669,202 +1637,193 @@ extern size_t getpagesize(); using so many "#if"s. */ + /* MORECORE and MMAP must return MFAIL on failure */ -#define MFAIL ((void *)(MAX_SIZE_T)) -#define CMFAIL ((char *)(MFAIL)) /* defined for convenience */ +#define MFAIL ((void*)(MAX_SIZE_T)) +#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ #if HAVE_MMAP - #ifndef WIN32 - #define MMAP_PROT (PROT_READ | PROT_WRITE) - #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) - #define MAP_ANONYMOUS MAP_ANON - #endif /* MAP_ANON */ - #ifdef MAP_ANONYMOUS - - #define MMAP_FLAGS (MAP_PRIVATE | MAP_ANONYMOUS) +#ifndef WIN32 +#define MMAP_PROT (PROT_READ|PROT_WRITE) +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif /* MAP_ANON */ +#ifdef MAP_ANONYMOUS -static FORCEINLINE void *unixmmap(size_t size) { +#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) - void *result; +static FORCEINLINE void* unixmmap(size_t size) { + void* result; result = mmap(0, size, MMAP_PROT, MMAP_FLAGS, -1, 0); - if (result == MFAIL) return MFAIL; + if (result == MFAIL) + return MFAIL; return result; - } -static FORCEINLINE int unixmunmap(void *ptr, size_t size) { - +static FORCEINLINE int unixmunmap(void* ptr, size_t size) { int result; result = munmap(ptr, size); - if (result != 0) return result; + if (result != 0) + return result; return result; - } - #define MMAP_DEFAULT(s) unixmmap(s) - #define MUNMAP_DEFAULT(a, s) unixmunmap((a), (s)) +#define MMAP_DEFAULT(s) unixmmap(s) +#define MUNMAP_DEFAULT(a, s) unixmunmap((a), (s)) - #else /* MAP_ANONYMOUS */ - /* - Nearly all versions of mmap support MAP_ANONYMOUS, so the following - is unlikely to be needed, but is supplied just in case. - */ - #define MMAP_FLAGS (MAP_PRIVATE) -static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ - #define MMAP_DEFAULT(s) \ - ((dev_zero_fd < 0) \ - ? (dev_zero_fd = open("/dev/zero", O_RDWR), \ - mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) \ - : mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) - #define MUNMAP_DEFAULT(a, s) munmap((a), (s)) - #endif /* MAP_ANONYMOUS */ +#else /* MAP_ANONYMOUS */ +/* + Nearly all versions of mmap support MAP_ANONYMOUS, so the following + is unlikely to be needed, but is supplied just in case. +*/ +#define MMAP_FLAGS (MAP_PRIVATE) +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ +#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) +#define MUNMAP_DEFAULT(a, s) munmap((a), (s)) +#endif /* MAP_ANONYMOUS */ - #define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s) +#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s) - #else /* WIN32 */ +#else /* WIN32 */ /* Win32 MMAP via VirtualAlloc */ -static FORCEINLINE void *win32mmap(size_t size) { - - void *ptr; +static FORCEINLINE void* win32mmap(size_t size) { + void* ptr; - ptr = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (ptr == 0) return MFAIL; + ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); + if (ptr == 0) + return MFAIL; return ptr; - } /* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ -static FORCEINLINE void *win32direct_mmap(size_t size) { - - void *ptr; +static FORCEINLINE void* win32direct_mmap(size_t size) { + void* ptr; - ptr = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, - PAGE_READWRITE); - if (ptr == 0) return MFAIL; + ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, + PAGE_READWRITE); + if (ptr == 0) + return MFAIL; return ptr; - } /* This function supports releasing coalesed segments */ -static FORCEINLINE int win32munmap(void *ptr, size_t size) { - +static FORCEINLINE int win32munmap(void* ptr, size_t size) { MEMORY_BASIC_INFORMATION minfo; - char *cptr = (char *)ptr; + char* cptr = (char*)ptr; while (size) { - - if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) return -1; + if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) + return -1; if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || minfo.State != MEM_COMMIT || minfo.RegionSize > size) return -1; - if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) return -1; + if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) + return -1; cptr += minfo.RegionSize; size -= minfo.RegionSize; - } return 0; - } - #define MMAP_DEFAULT(s) win32mmap(s) - #define MUNMAP_DEFAULT(a, s) win32munmap((a), (s)) - #define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s) - #endif /* WIN32 */ -#endif /* HAVE_MMAP */ +#define MMAP_DEFAULT(s) win32mmap(s) +#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s)) +#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s) +#endif /* WIN32 */ +#endif /* HAVE_MMAP */ #if HAVE_MREMAP - #ifndef WIN32 - -static FORCEINLINE void *dlmremap(void *old_address, size_t old_size, - size_t new_size, int flags) { +#ifndef WIN32 - void *result; +static FORCEINLINE void* dlmremap(void* old_address, size_t old_size, size_t new_size, int flags) { + void* result; result = mremap(old_address, old_size, new_size, flags); - if (result == MFAIL) return MFAIL; + if (result == MFAIL) + return MFAIL; return result; - } - #define MREMAP_DEFAULT(addr, osz, nsz, mv) \ - dlmremap((addr), (osz), (nsz), (mv)) - #endif /* WIN32 */ -#endif /* HAVE_MREMAP */ +#define MREMAP_DEFAULT(addr, osz, nsz, mv) dlmremap((addr), (osz), (nsz), (mv)) +#endif /* WIN32 */ +#endif /* HAVE_MREMAP */ /** * Define CALL_MORECORE */ #if HAVE_MORECORE - #ifdef MORECORE - #define CALL_MORECORE(S) MORECORE(S) - #else /* MORECORE */ - #define CALL_MORECORE(S) MORECORE_DEFAULT(S) - #endif /* MORECORE */ -#else /* HAVE_MORECORE */ - #define CALL_MORECORE(S) MFAIL -#endif /* HAVE_MORECORE */ + #ifdef MORECORE + #define CALL_MORECORE(S) MORECORE(S) + #else /* MORECORE */ + #define CALL_MORECORE(S) MORECORE_DEFAULT(S) + #endif /* MORECORE */ +#else /* HAVE_MORECORE */ + #define CALL_MORECORE(S) MFAIL +#endif /* HAVE_MORECORE */ /** * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP */ #if HAVE_MMAP - #define USE_MMAP_BIT (SIZE_T_ONE) - - #ifdef MMAP - #define CALL_MMAP(s) MMAP(s) - #else /* MMAP */ - #define CALL_MMAP(s) MMAP_DEFAULT(s) - #endif /* MMAP */ - #ifdef MUNMAP - #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) - #else /* MUNMAP */ - #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s)) - #endif /* MUNMAP */ - #ifdef DIRECT_MMAP - #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) - #else /* DIRECT_MMAP */ - #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s) - #endif /* DIRECT_MMAP */ -#else /* HAVE_MMAP */ - #define USE_MMAP_BIT (SIZE_T_ZERO) - - #define MMAP(s) MFAIL - #define MUNMAP(a, s) (-1) - #define DIRECT_MMAP(s) MFAIL - #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) - #define CALL_MMAP(s) MMAP(s) - #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) -#endif /* HAVE_MMAP */ + #define USE_MMAP_BIT (SIZE_T_ONE) + + #ifdef MMAP + #define CALL_MMAP(s) MMAP(s) + #else /* MMAP */ + #define CALL_MMAP(s) MMAP_DEFAULT(s) + #endif /* MMAP */ + #ifdef MUNMAP + #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) + #else /* MUNMAP */ + #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s)) + #endif /* MUNMAP */ + #ifdef DIRECT_MMAP + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) + #else /* DIRECT_MMAP */ + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s) + #endif /* DIRECT_MMAP */ +#else /* HAVE_MMAP */ + #define USE_MMAP_BIT (SIZE_T_ZERO) + + #define MMAP(s) MFAIL + #define MUNMAP(a, s) (-1) + #define DIRECT_MMAP(s) MFAIL + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) + #define CALL_MMAP(s) MMAP(s) + #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) +#endif /* HAVE_MMAP */ /** * Define CALL_MREMAP */ #if HAVE_MMAP && HAVE_MREMAP - #ifdef MREMAP - #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv)) - #else /* MREMAP */ - #define CALL_MREMAP(addr, osz, nsz, mv) \ - MREMAP_DEFAULT((addr), (osz), (nsz), (mv)) - #endif /* MREMAP */ -#else /* HAVE_MMAP && HAVE_MREMAP */ - #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL -#endif /* HAVE_MMAP && HAVE_MREMAP */ + #ifdef MREMAP + #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv)) + #else /* MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv)) + #endif /* MREMAP */ +#else /* HAVE_MMAP && HAVE_MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL +#endif /* HAVE_MMAP && HAVE_MREMAP */ /* mstate bit set if continguous morecore disabled or failed */ #define USE_NONCONTIGUOUS_BIT (4U) /* segment bit set in create_mspace_with_base */ -#define EXTERN_BIT (8U) +#define EXTERN_BIT (8U) + /* --------------------------- Lock preliminaries ------------------------ */ @@ -1897,284 +1856,247 @@ static FORCEINLINE void *dlmremap(void *old_address, size_t old_size, */ #if !USE_LOCKS - #define USE_LOCK_BIT (0U) - #define INITIAL_LOCK(l) (0) - #define DESTROY_LOCK(l) (0) - #define ACQUIRE_MALLOC_GLOBAL_LOCK() - #define RELEASE_MALLOC_GLOBAL_LOCK() +#define USE_LOCK_BIT (0U) +#define INITIAL_LOCK(l) (0) +#define DESTROY_LOCK(l) (0) +#define ACQUIRE_MALLOC_GLOBAL_LOCK() +#define RELEASE_MALLOC_GLOBAL_LOCK() #else - #if USE_LOCKS > 1 - /* ----------------------- User-defined locks ------------------------ */ - /* Define your own lock implementation here */ - /* #define INITIAL_LOCK(lk) ... */ - /* #define DESTROY_LOCK(lk) ... */ - /* #define ACQUIRE_LOCK(lk) ... */ - /* #define RELEASE_LOCK(lk) ... */ - /* #define TRY_LOCK(lk) ... */ - /* static MLOCK_T malloc_global_mutex = ... */ - - #elif USE_SPIN_LOCKS - - /* First, define CAS_LOCK and CLEAR_LOCK on ints */ - /* Note CAS_LOCK defined to return 0 on success */ - - #if defined(__GNUC__) && \ - (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) - #define CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1) - #define CLEAR_LOCK(sl) __sync_lock_release(sl) - - #elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) +#if USE_LOCKS > 1 +/* ----------------------- User-defined locks ------------------------ */ +/* Define your own lock implementation here */ +/* #define INITIAL_LOCK(lk) ... */ +/* #define DESTROY_LOCK(lk) ... */ +/* #define ACQUIRE_LOCK(lk) ... */ +/* #define RELEASE_LOCK(lk) ... */ +/* #define TRY_LOCK(lk) ... */ +/* static MLOCK_T malloc_global_mutex = ... */ + +#elif USE_SPIN_LOCKS + +/* First, define CAS_LOCK and CLEAR_LOCK on ints */ +/* Note CAS_LOCK defined to return 0 on success */ + +#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) +#define CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1) +#define CLEAR_LOCK(sl) __sync_lock_release(sl) + +#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) /* Custom spin locks for older gcc on x86 */ static FORCEINLINE int x86_cas_lock(int *sl) { - int ret; int val = 1; int cmp = 0; - __asm__ __volatile__("lock; cmpxchgl %1, %2" - : "=a"(ret) - : "r"(val), "m"(*(sl)), "0"(cmp) - : "memory", "cc"); + __asm__ __volatile__ ("lock; cmpxchgl %1, %2" + : "=a" (ret) + : "r" (val), "m" (*(sl)), "0"(cmp) + : "memory", "cc"); return ret; - } -static FORCEINLINE void x86_clear_lock(int *sl) { - +static FORCEINLINE void x86_clear_lock(int* sl) { assert(*sl != 0); int prev = 0; int ret; - __asm__ __volatile__("lock; xchgl %0, %1" - : "=r"(ret) - : "m"(*(sl)), "0"(prev) - : "memory"); - + __asm__ __volatile__ ("lock; xchgl %0, %1" + : "=r" (ret) + : "m" (*(sl)), "0"(prev) + : "memory"); } - #define CAS_LOCK(sl) x86_cas_lock(sl) - #define CLEAR_LOCK(sl) x86_clear_lock(sl) - - #else /* Win32 MSC */ - #define CAS_LOCK(sl) interlockedexchange((volatile LONG *)sl, (LONG)1) - #define CLEAR_LOCK(sl) interlockedexchange((volatile LONG *)sl, (LONG)0) - - #endif /* ... gcc spins locks ... */ - - /* How to yield for a spin lock */ - #define SPINS_PER_YIELD 63 - #if defined(_MSC_VER) - #define SLEEP_EX_DURATION 50 /* delay for yield/sleep */ - #define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE) - #elif defined(__SVR4) && defined(__sun) /* solaris */ - #define SPIN_LOCK_YIELD thr_yield(); - #elif !defined(LACKS_SCHED_H) - #define SPIN_LOCK_YIELD sched_yield(); - #else - #define SPIN_LOCK_YIELD - #endif /* ... yield ... */ - - #if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0 +#define CAS_LOCK(sl) x86_cas_lock(sl) +#define CLEAR_LOCK(sl) x86_clear_lock(sl) + +#else /* Win32 MSC */ +#define CAS_LOCK(sl) interlockedexchange((volatile LONG *)sl, (LONG)1) +#define CLEAR_LOCK(sl) interlockedexchange((volatile LONG *)sl, (LONG)0) + +#endif /* ... gcc spins locks ... */ + +/* How to yield for a spin lock */ +#define SPINS_PER_YIELD 63 +#if defined(_MSC_VER) +#define SLEEP_EX_DURATION 50 /* delay for yield/sleep */ +#define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE) +#elif defined (__SVR4) && defined (__sun) /* solaris */ +#define SPIN_LOCK_YIELD thr_yield(); +#elif !defined(LACKS_SCHED_H) +#define SPIN_LOCK_YIELD sched_yield(); +#else +#define SPIN_LOCK_YIELD +#endif /* ... yield ... */ + +#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0 /* Plain spin locks use single word (embedded in malloc_states) */ static int spin_acquire_lock(int *sl) { - int spins = 0; while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) { - - if ((++spins & SPINS_PER_YIELD) == 0) { SPIN_LOCK_YIELD; } - + if ((++spins & SPINS_PER_YIELD) == 0) { + SPIN_LOCK_YIELD; + } } - return 0; - } - #define MLOCK_T int - #define TRY_LOCK(sl) !CAS_LOCK(sl) - #define RELEASE_LOCK(sl) CLEAR_LOCK(sl) - #define ACQUIRE_LOCK(sl) (CAS_LOCK(sl) ? spin_acquire_lock(sl) : 0) - #define INITIAL_LOCK(sl) (*sl = 0) - #define DESTROY_LOCK(sl) (0) +#define MLOCK_T int +#define TRY_LOCK(sl) !CAS_LOCK(sl) +#define RELEASE_LOCK(sl) CLEAR_LOCK(sl) +#define ACQUIRE_LOCK(sl) (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0) +#define INITIAL_LOCK(sl) (*sl = 0) +#define DESTROY_LOCK(sl) (0) static MLOCK_T malloc_global_mutex = 0; - #else /* USE_RECURSIVE_LOCKS */ - /* types for lock owners */ - #ifdef WIN32 - #define THREAD_ID_T DWORD - #define CURRENT_THREAD GetCurrentThreadId() - #define EQ_OWNER(X, Y) ((X) == (Y)) - #else - /* - Note: the following assume that pthread_t is a type that can be - initialized to (casted) zero. If this is not the case, you will need - to somehow redefine these or not use spin locks. - */ - #define THREAD_ID_T pthread_t - #define CURRENT_THREAD pthread_self() - #define EQ_OWNER(X, Y) pthread_equal(X, Y) - #endif +#else /* USE_RECURSIVE_LOCKS */ +/* types for lock owners */ +#ifdef WIN32 +#define THREAD_ID_T DWORD +#define CURRENT_THREAD GetCurrentThreadId() +#define EQ_OWNER(X,Y) ((X) == (Y)) +#else +/* + Note: the following assume that pthread_t is a type that can be + initialized to (casted) zero. If this is not the case, you will need to + somehow redefine these or not use spin locks. +*/ +#define THREAD_ID_T pthread_t +#define CURRENT_THREAD pthread_self() +#define EQ_OWNER(X,Y) pthread_equal(X, Y) +#endif struct malloc_recursive_lock { - - int sl; + int sl; unsigned int c; - THREAD_ID_T threadid; - + THREAD_ID_T threadid; }; - #define MLOCK_T struct malloc_recursive_lock -static MLOCK_T malloc_global_mutex = {0, 0, (THREAD_ID_T)0}; +#define MLOCK_T struct malloc_recursive_lock +static MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0}; static FORCEINLINE void recursive_release_lock(MLOCK_T *lk) { - assert(lk->sl != 0); - if (--lk->c == 0) { CLEAR_LOCK(&lk->sl); } - + if (--lk->c == 0) { + CLEAR_LOCK(&lk->sl); + } } static FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) { - THREAD_ID_T mythreadid = CURRENT_THREAD; - int spins = 0; + int spins = 0; for (;;) { - if (*((volatile int *)(&lk->sl)) == 0) { - if (!CAS_LOCK(&lk->sl)) { - lk->threadid = mythreadid; lk->c = 1; return 0; - } - - } else if (EQ_OWNER(lk->threadid, mythreadid)) { - + } + else if (EQ_OWNER(lk->threadid, mythreadid)) { ++lk->c; return 0; - } - - if ((++spins & SPINS_PER_YIELD) == 0) { SPIN_LOCK_YIELD; } - + if ((++spins & SPINS_PER_YIELD) == 0) { + SPIN_LOCK_YIELD; + } } - } static FORCEINLINE int recursive_try_lock(MLOCK_T *lk) { - THREAD_ID_T mythreadid = CURRENT_THREAD; if (*((volatile int *)(&lk->sl)) == 0) { - if (!CAS_LOCK(&lk->sl)) { - lk->threadid = mythreadid; lk->c = 1; return 1; - } - - } else if (EQ_OWNER(lk->threadid, mythreadid)) { - + } + else if (EQ_OWNER(lk->threadid, mythreadid)) { ++lk->c; return 1; - } - return 0; - } - #define RELEASE_LOCK(lk) recursive_release_lock(lk) - #define TRY_LOCK(lk) recursive_try_lock(lk) - #define ACQUIRE_LOCK(lk) recursive_acquire_lock(lk) - #define INITIAL_LOCK(lk) \ - ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0) - #define DESTROY_LOCK(lk) (0) - #endif /* USE_RECURSIVE_LOCKS */ - - #elif defined(WIN32) /* Win32 critical sections */ - #define MLOCK_T CRITICAL_SECTION - #define ACQUIRE_LOCK(lk) (EnterCriticalSection(lk), 0) - #define RELEASE_LOCK(lk) LeaveCriticalSection(lk) - #define TRY_LOCK(lk) TryEnterCriticalSection(lk) - #define INITIAL_LOCK(lk) \ - (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000 | 4000)) - #define DESTROY_LOCK(lk) (DeleteCriticalSection(lk), 0) - #define NEED_GLOBAL_LOCK_INIT - -static MLOCK_T malloc_global_mutex; +#define RELEASE_LOCK(lk) recursive_release_lock(lk) +#define TRY_LOCK(lk) recursive_try_lock(lk) +#define ACQUIRE_LOCK(lk) recursive_acquire_lock(lk) +#define INITIAL_LOCK(lk) ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0) +#define DESTROY_LOCK(lk) (0) +#endif /* USE_RECURSIVE_LOCKS */ + +#elif defined(WIN32) /* Win32 critical sections */ +#define MLOCK_T CRITICAL_SECTION +#define ACQUIRE_LOCK(lk) (EnterCriticalSection(lk), 0) +#define RELEASE_LOCK(lk) LeaveCriticalSection(lk) +#define TRY_LOCK(lk) TryEnterCriticalSection(lk) +#define INITIAL_LOCK(lk) (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000)) +#define DESTROY_LOCK(lk) (DeleteCriticalSection(lk), 0) +#define NEED_GLOBAL_LOCK_INIT + +static MLOCK_T malloc_global_mutex; static volatile LONG malloc_global_mutex_status; /* Use spin loop to initialize global lock */ static void init_malloc_global_mutex() { - for (;;) { - long stat = malloc_global_mutex_status; - if (stat > 0) return; + if (stat > 0) + return; /* transition to < 0 while initializing, then to > 0) */ - if (stat == 0 && interlockedcompareexchange(&malloc_global_mutex_status, - (LONG)-1, (LONG)0) == 0) { - + if (stat == 0 && + interlockedcompareexchange(&malloc_global_mutex_status, (LONG)-1, (LONG)0) == 0) { InitializeCriticalSection(&malloc_global_mutex); interlockedexchange(&malloc_global_mutex_status, (LONG)1); return; - } - SleepEx(0, FALSE); - } - } - #else /* pthreads-based locks */ - #define MLOCK_T pthread_mutex_t - #define ACQUIRE_LOCK(lk) pthread_mutex_lock(lk) - #define RELEASE_LOCK(lk) pthread_mutex_unlock(lk) - #define TRY_LOCK(lk) (!pthread_mutex_trylock(lk)) - #define INITIAL_LOCK(lk) pthread_init_lock(lk) - #define DESTROY_LOCK(lk) pthread_mutex_destroy(lk) +#else /* pthreads-based locks */ +#define MLOCK_T pthread_mutex_t +#define ACQUIRE_LOCK(lk) pthread_mutex_lock(lk) +#define RELEASE_LOCK(lk) pthread_mutex_unlock(lk) +#define TRY_LOCK(lk) (!pthread_mutex_trylock(lk)) +#define INITIAL_LOCK(lk) pthread_init_lock(lk) +#define DESTROY_LOCK(lk) pthread_mutex_destroy(lk) - #if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && \ - defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE) +#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE) /* Cope with old-style linux recursive lock initialization by adding */ /* skipped internal declaration from pthread.h */ -extern int pthread_mutexattr_setkind_np __P((pthread_mutexattr_t * __attr, - int __kind)); - #define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP - #define pthread_mutexattr_settype(x, y) pthread_mutexattr_setkind_np(x, y) - #endif /* USE_RECURSIVE_LOCKS ... */ +extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr, + int __kind)); +#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y) +#endif /* USE_RECURSIVE_LOCKS ... */ static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER; -static int pthread_init_lock(MLOCK_T *lk) { - +static int pthread_init_lock (MLOCK_T *lk) { pthread_mutexattr_t attr; if (pthread_mutexattr_init(&attr)) return 1; - #if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 +#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1; - #endif +#endif if (pthread_mutex_init(lk, &attr)) return 1; if (pthread_mutexattr_destroy(&attr)) return 1; return 0; - } - #endif /* ... lock types ... */ +#endif /* ... lock types ... */ - /* Common code for all lock types */ - #define USE_LOCK_BIT (2U) +/* Common code for all lock types */ +#define USE_LOCK_BIT (2U) - #ifndef ACQUIRE_MALLOC_GLOBAL_LOCK - #define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex); - #endif +#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK +#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex); +#endif - #ifndef RELEASE_MALLOC_GLOBAL_LOCK - #define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex); - #endif +#ifndef RELEASE_MALLOC_GLOBAL_LOCK +#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex); +#endif -#endif /* USE_LOCKS */ +#endif /* USE_LOCKS */ /* ----------------------- Chunk representations ------------------------ */ @@ -2314,56 +2236,56 @@ static int pthread_init_lock(MLOCK_T *lk) { */ struct malloc_chunk { - - size_t prev_foot; /* Size of previous chunk (if free). */ - size_t head; /* Size and inuse bits. */ - struct malloc_chunk *fd; /* double links -- used only if free. */ - struct malloc_chunk *bk; - + size_t prev_foot; /* Size of previous chunk (if free). */ + size_t head; /* Size and inuse bits. */ + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; }; typedef struct malloc_chunk mchunk; -typedef struct malloc_chunk *mchunkptr; -typedef struct malloc_chunk *sbinptr; /* The type of bins of chunks */ -typedef unsigned int bindex_t; /* Described below */ -typedef unsigned int binmap_t; /* Described below */ -typedef unsigned int flag_t; /* The type of various bit flag sets */ +typedef struct malloc_chunk* mchunkptr; +typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ +typedef unsigned int bindex_t; /* Described below */ +typedef unsigned int binmap_t; /* Described below */ +typedef unsigned int flag_t; /* The type of various bit flag sets */ /* ------------------- Chunks sizes and alignments ----------------------- */ -#define MCHUNK_SIZE (sizeof(mchunk)) +#define MCHUNK_SIZE (sizeof(mchunk)) #if FOOTERS - #define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) -#else /* FOOTERS */ - #define CHUNK_OVERHEAD (SIZE_T_SIZE) -#endif /* FOOTERS */ +#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +#else /* FOOTERS */ +#define CHUNK_OVERHEAD (SIZE_T_SIZE) +#endif /* FOOTERS */ /* MMapped chunks need a second word of overhead ... */ #define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) /* ... and additional padding for fake next-chunk at foot */ -#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) +#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) /* The smallest size we can malloc is an aligned minimal chunk */ -#define MIN_CHUNK_SIZE ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) +#define MIN_CHUNK_SIZE\ + ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) /* conversion from malloc headers to user pointers, and back */ -#define chunk2mem(p) ((void *)((char *)(p) + TWO_SIZE_T_SIZES)) -#define mem2chunk(mem) ((mchunkptr)((char *)(mem)-TWO_SIZE_T_SIZES)) +#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) /* chunk associated with aligned address A */ -#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) +#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) /* Bounds on request (not chunk) sizes. */ -#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) -#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) +#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) +#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) /* pad request bytes into a usable size */ #define pad_request(req) \ - (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) /* pad request, checking for minimum (but not maximum) */ #define request2size(req) \ - (((req) < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(req)) + (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) + /* ------------------ Operations on head and foot fields ----------------- */ @@ -2375,60 +2297,61 @@ typedef unsigned int flag_t; /* The type of various bit flag sets */ FLAG4_BIT is not used by this malloc, but might be useful in extensions. */ -#define PINUSE_BIT (SIZE_T_ONE) -#define CINUSE_BIT (SIZE_T_TWO) -#define FLAG4_BIT (SIZE_T_FOUR) -#define INUSE_BITS (PINUSE_BIT | CINUSE_BIT) -#define FLAG_BITS (PINUSE_BIT | CINUSE_BIT | FLAG4_BIT) +#define PINUSE_BIT (SIZE_T_ONE) +#define CINUSE_BIT (SIZE_T_TWO) +#define FLAG4_BIT (SIZE_T_FOUR) +#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) +#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT) /* Head value for fenceposts */ -#define FENCEPOST_HEAD (INUSE_BITS | SIZE_T_SIZE) +#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) /* extraction of fields from head words */ -#define cinuse(p) ((p)->head & CINUSE_BIT) -#define pinuse(p) ((p)->head & PINUSE_BIT) -#define flag4inuse(p) ((p)->head & FLAG4_BIT) -#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT) -#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0) +#define cinuse(p) ((p)->head & CINUSE_BIT) +#define pinuse(p) ((p)->head & PINUSE_BIT) +#define flag4inuse(p) ((p)->head & FLAG4_BIT) +#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT) +#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0) -#define chunksize(p) ((p)->head & ~(FLAG_BITS)) +#define chunksize(p) ((p)->head & ~(FLAG_BITS)) -#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) -#define set_flag4(p) ((p)->head |= FLAG4_BIT) -#define clear_flag4(p) ((p)->head &= ~FLAG4_BIT) +#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) +#define set_flag4(p) ((p)->head |= FLAG4_BIT) +#define clear_flag4(p) ((p)->head &= ~FLAG4_BIT) /* Treat space at ptr +/- offset as a chunk */ -#define chunk_plus_offset(p, s) ((mchunkptr)(((char *)(p)) + (s))) -#define chunk_minus_offset(p, s) ((mchunkptr)(((char *)(p)) - (s))) +#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) +#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) /* Ptr to next or previous physical malloc_chunk. */ -#define next_chunk(p) ((mchunkptr)(((char *)(p)) + ((p)->head & ~FLAG_BITS))) -#define prev_chunk(p) ((mchunkptr)(((char *)(p)) - ((p)->prev_foot))) +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS))) +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) /* extract next chunk's pinuse bit */ -#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) +#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) /* Get/set size at footer */ -#define get_foot(p, s) (((mchunkptr)((char *)(p) + (s)))->prev_foot) -#define set_foot(p, s) (((mchunkptr)((char *)(p) + (s)))->prev_foot = (s)) +#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) /* Set size, pinuse bit, and foot */ -#define set_size_and_pinuse_of_free_chunk(p, s) \ - ((p)->head = (s | PINUSE_BIT), set_foot(p, s)) +#define set_size_and_pinuse_of_free_chunk(p, s)\ + ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) /* Set size, pinuse bit, foot, and clear next pinuse */ -#define set_free_with_pinuse(p, s, n) \ +#define set_free_with_pinuse(p, s, n)\ (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) /* Get the internal overhead associated with chunk p */ -#define overhead_for(p) (is_mmapped(p) ? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) +#define overhead_for(p)\ + (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) /* Return true if malloced space is not necessarily cleared */ #if MMAP_CLEARS - #define calloc_must_clear(p) (!is_mmapped(p)) -#else /* MMAP_CLEARS */ - #define calloc_must_clear(p) (1) -#endif /* MMAP_CLEARS */ +#define calloc_must_clear(p) (!is_mmapped(p)) +#else /* MMAP_CLEARS */ +#define calloc_must_clear(p) (1) +#endif /* MMAP_CLEARS */ /* ---------------------- Overlaid data structures ----------------------- */ @@ -2522,25 +2445,23 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ struct malloc_tree_chunk { - /* The first four fields must be compatible with malloc_chunk */ size_t prev_foot; size_t head; - struct malloc_tree_chunk *fd; - struct malloc_tree_chunk *bk; + struct malloc_tree_chunk* fd; + struct malloc_tree_chunk* bk; - struct malloc_tree_chunk *child[2]; - struct malloc_tree_chunk *parent; + struct malloc_tree_chunk* child[2]; + struct malloc_tree_chunk* parent; bindex_t index; - }; typedef struct malloc_tree_chunk tchunk; -typedef struct malloc_tree_chunk *tchunkptr; -typedef struct malloc_tree_chunk *tbinptr; /* The type of bins of trees */ +typedef struct malloc_tree_chunk* tchunkptr; +typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ /* A little helper macro for trees */ -#define leftmost_child(t) ((t)->child[0] != 0 ? (t)->child[0] : (t)->child[1]) +#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) /* ----------------------------- Segments -------------------------------- */ @@ -2600,19 +2521,17 @@ typedef struct malloc_tree_chunk *tbinptr; /* The type of bins of trees */ */ struct malloc_segment { - - char * base; /* base address */ - size_t size; /* allocated size */ - struct malloc_segment *next; /* ptr to next segment */ - flag_t sflags; /* mmap and extern flag */ - + char* base; /* base address */ + size_t size; /* allocated size */ + struct malloc_segment* next; /* ptr to next segment */ + flag_t sflags; /* mmap and extern flag */ }; -#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT) -#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) +#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT) +#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) typedef struct malloc_segment msegment; -typedef struct malloc_segment *msegmentptr; +typedef struct malloc_segment* msegmentptr; /* ---------------------------- malloc_state ----------------------------- */ @@ -2702,43 +2621,41 @@ typedef struct malloc_segment *msegmentptr; */ /* Bin types, widths and sizes */ -#define NSMALLBINS (32U) -#define NTREEBINS (32U) -#define SMALLBIN_SHIFT (3U) -#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) -#define TREEBIN_SHIFT (8U) -#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) -#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) +#define NSMALLBINS (32U) +#define NTREEBINS (32U) +#define SMALLBIN_SHIFT (3U) +#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) +#define TREEBIN_SHIFT (8U) +#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) +#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) #define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) struct malloc_state { - - binmap_t smallmap; - binmap_t treemap; - size_t dvsize; - size_t topsize; - char * least_addr; - mchunkptr dv; - mchunkptr top; - size_t trim_check; - size_t release_checks; - size_t magic; - mchunkptr smallbins[(NSMALLBINS + 1) * 2]; - tbinptr treebins[NTREEBINS]; - size_t footprint; - size_t max_footprint; - size_t footprint_limit; /* zero means no limit */ - flag_t mflags; + binmap_t smallmap; + binmap_t treemap; + size_t dvsize; + size_t topsize; + char* least_addr; + mchunkptr dv; + mchunkptr top; + size_t trim_check; + size_t release_checks; + size_t magic; + mchunkptr smallbins[(NSMALLBINS+1)*2]; + tbinptr treebins[NTREEBINS]; + size_t footprint; + size_t max_footprint; + size_t footprint_limit; /* zero means no limit */ + flag_t mflags; #if USE_LOCKS - MLOCK_T mutex; /* locate lock among fields that rarely change */ -#endif /* USE_LOCKS */ - msegment seg; - void * extp; /* Unused but available for extensions */ - size_t exts; - + MLOCK_T mutex; /* locate lock among fields that rarely change */ +#endif /* USE_LOCKS */ + msegment seg; + void* extp; /* Unused but available for extensions */ + size_t exts; }; -typedef struct malloc_state *mstate; +typedef struct malloc_state* mstate; /* ------------- Global malloc_state and malloc_params ------------------- */ @@ -2750,14 +2667,12 @@ typedef struct malloc_state *mstate; */ struct malloc_params { - size_t magic; size_t page_size; size_t granularity; size_t mmap_threshold; size_t trim_threshold; flag_t default_mflags; - }; static struct malloc_params mparams; @@ -2769,108 +2684,106 @@ static struct malloc_params mparams; /* The global malloc_state used for all non-"mspace" calls */ static struct malloc_state _gm_; - #define gm (&_gm_) - #define is_global(M) ((M) == &_gm_) +#define gm (&_gm_) +#define is_global(M) ((M) == &_gm_) -#endif /* !ONLY_MSPACES */ +#endif /* !ONLY_MSPACES */ -#define is_initialized(M) ((M)->top != 0) +#define is_initialized(M) ((M)->top != 0) /* -------------------------- system alloc setup ------------------------- */ /* Operations on mflags */ -#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) -#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) +#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) +#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) #if USE_LOCKS - #define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) +#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) #else - #define disable_lock(M) +#define disable_lock(M) #endif -#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) -#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) +#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) +#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) #if HAVE_MMAP - #define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) +#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) #else - #define disable_mmap(M) +#define disable_mmap(M) #endif -#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) -#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) +#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) +#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) -#define set_lock(M, L) \ - ((M)->mflags = \ - (L) ? ((M)->mflags | USE_LOCK_BIT) : ((M)->mflags & ~USE_LOCK_BIT)) +#define set_lock(M,L)\ + ((M)->mflags = (L)?\ + ((M)->mflags | USE_LOCK_BIT) :\ + ((M)->mflags & ~USE_LOCK_BIT)) /* page-align a size */ -#define page_align(S) \ - (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE)) +#define page_align(S)\ + (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE)) /* granularity-align a size */ -#define granularity_align(S) \ - (((S) + (mparams.granularity - SIZE_T_ONE)) & \ - ~(mparams.granularity - SIZE_T_ONE)) +#define granularity_align(S)\ + (((S) + (mparams.granularity - SIZE_T_ONE))\ + & ~(mparams.granularity - SIZE_T_ONE)) + /* For mmap, use granularity alignment on windows, else page-align */ #ifdef WIN32 - #define mmap_align(S) granularity_align(S) +#define mmap_align(S) granularity_align(S) #else - #define mmap_align(S) page_align(S) +#define mmap_align(S) page_align(S) #endif /* For sys_alloc, enough padding to ensure can malloc request on success */ #define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT) -#define is_page_aligned(S) \ - (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) -#define is_granularity_aligned(S) \ - (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) +#define is_page_aligned(S)\ + (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) +#define is_granularity_aligned(S)\ + (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) /* True if segment S holds address A */ -#define segment_holds(S, A) \ - ((char *)(A) >= S->base && (char *)(A) < S->base + S->size) +#define segment_holds(S, A)\ + ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) /* Return segment holding given address */ -static msegmentptr segment_holding(mstate m, char *addr) { - +static msegmentptr segment_holding(mstate m, char* addr) { msegmentptr sp = &m->seg; for (;;) { - - if (addr >= sp->base && addr < sp->base + sp->size) return sp; - if ((sp = sp->next) == 0) return 0; - + if (addr >= sp->base && addr < sp->base + sp->size) + return sp; + if ((sp = sp->next) == 0) + return 0; } - } /* Return true if segment contains a segment link */ static int has_segment_link(mstate m, msegmentptr ss) { - msegmentptr sp = &m->seg; for (;;) { - - if ((char *)sp >= ss->base && (char *)sp < ss->base + ss->size) return 1; - if ((sp = sp->next) == 0) return 0; - + if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) + return 1; + if ((sp = sp->next) == 0) + return 0; } - } #ifndef MORECORE_CANNOT_TRIM - #define should_trim(M, s) ((s) > (M)->trim_check) -#else /* MORECORE_CANNOT_TRIM */ - #define should_trim(M, s) (0) -#endif /* MORECORE_CANNOT_TRIM */ +#define should_trim(M,s) ((s) > (M)->trim_check) +#else /* MORECORE_CANNOT_TRIM */ +#define should_trim(M,s) (0) +#endif /* MORECORE_CANNOT_TRIM */ /* TOP_FOOT_SIZE is padding at the end of a segment, including space that may be needed to place segment records and fenceposts when new noncontiguous segments are added. */ -#define TOP_FOOT_SIZE \ - (align_offset(chunk2mem(0)) + pad_request(sizeof(struct malloc_segment)) + \ - MIN_CHUNK_SIZE) +#define TOP_FOOT_SIZE\ + (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) + /* ------------------------------- Hooks -------------------------------- */ @@ -2881,24 +2794,19 @@ static int has_segment_link(mstate m, msegmentptr ss) { */ #if USE_LOCKS - #define PREACTION(M) ((use_lock(M)) ? ACQUIRE_LOCK(&(M)->mutex) : 0) - #define POSTACTION(M) \ - { \ - \ - if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); \ - \ - } -#else /* USE_LOCKS */ +#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) +#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } +#else /* USE_LOCKS */ - #ifndef PREACTION - #define PREACTION(M) (0) - #endif /* PREACTION */ +#ifndef PREACTION +#define PREACTION(M) (0) +#endif /* PREACTION */ - #ifndef POSTACTION - #define POSTACTION(M) - #endif /* POSTACTION */ +#ifndef POSTACTION +#define POSTACTION(M) +#endif /* POSTACTION */ -#endif /* USE_LOCKS */ +#endif /* USE_LOCKS */ /* CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. @@ -2916,180 +2824,164 @@ int malloc_corruption_error_count; /* default corruption action */ static void reset_on_error(mstate m); - #define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) - #define USAGE_ERROR_ACTION(m, p) +#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) +#define USAGE_ERROR_ACTION(m, p) -#else /* PROCEED_ON_ERROR */ +#else /* PROCEED_ON_ERROR */ - #ifndef CORRUPTION_ERROR_ACTION - #define CORRUPTION_ERROR_ACTION(m) ABORT - #endif /* CORRUPTION_ERROR_ACTION */ +#ifndef CORRUPTION_ERROR_ACTION +#define CORRUPTION_ERROR_ACTION(m) ABORT +#endif /* CORRUPTION_ERROR_ACTION */ - #ifndef USAGE_ERROR_ACTION - #define USAGE_ERROR_ACTION(m, p) ABORT - #endif /* USAGE_ERROR_ACTION */ +#ifndef USAGE_ERROR_ACTION +#define USAGE_ERROR_ACTION(m,p) ABORT +#endif /* USAGE_ERROR_ACTION */ + +#endif /* PROCEED_ON_ERROR */ -#endif /* PROCEED_ON_ERROR */ /* -------------------------- Debugging setup ---------------------------- */ -#if !DEBUG +#if ! DEBUG - #define check_free_chunk(M, P) - #define check_inuse_chunk(M, P) - #define check_malloced_chunk(M, P, N) - #define check_mmapped_chunk(M, P) - #define check_malloc_state(M) - #define check_top_chunk(M, P) +#define check_free_chunk(M,P) +#define check_inuse_chunk(M,P) +#define check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) +#define check_malloc_state(M) +#define check_top_chunk(M,P) -#else /* DEBUG */ - #define check_free_chunk(M, P) do_check_free_chunk(M, P) - #define check_inuse_chunk(M, P) do_check_inuse_chunk(M, P) - #define check_top_chunk(M, P) do_check_top_chunk(M, P) - #define check_malloced_chunk(M, P, N) do_check_malloced_chunk(M, P, N) - #define check_mmapped_chunk(M, P) do_check_mmapped_chunk(M, P) - #define check_malloc_state(M) do_check_malloc_state(M) +#else /* DEBUG */ +#define check_free_chunk(M,P) do_check_free_chunk(M,P) +#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) +#define check_top_chunk(M,P) do_check_top_chunk(M,P) +#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) +#define check_malloc_state(M) do_check_malloc_state(M) static void do_check_any_chunk(mstate m, mchunkptr p); static void do_check_top_chunk(mstate m, mchunkptr p); static void do_check_mmapped_chunk(mstate m, mchunkptr p); static void do_check_inuse_chunk(mstate m, mchunkptr p); static void do_check_free_chunk(mstate m, mchunkptr p); -static void do_check_malloced_chunk(mstate m, void *mem, size_t s); +static void do_check_malloced_chunk(mstate m, void* mem, size_t s); static void do_check_tree(mstate m, tchunkptr t); static void do_check_treebin(mstate m, bindex_t i); static void do_check_smallbin(mstate m, bindex_t i); static void do_check_malloc_state(mstate m); static int bin_find(mstate m, mchunkptr x); static size_t traverse_and_check(mstate m); -#endif /* DEBUG */ +#endif /* DEBUG */ /* ---------------------------- Indexing Bins ---------------------------- */ -#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) -#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT) -#define small_index2size(i) ((i) << SMALLBIN_SHIFT) -#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) +#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) +#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT) +#define small_index2size(i) ((i) << SMALLBIN_SHIFT) +#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) /* addressing by index. See above about smallbin repositioning */ -#define smallbin_at(M, i) ((sbinptr)((char *)&((M)->smallbins[(i) << 1]))) -#define treebin_at(M, i) (&((M)->treebins[i])) +#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) +#define treebin_at(M,i) (&((M)->treebins[i])) /* assign tree index for size S to variable I. Use x86 asm if possible */ #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - #define compute_tree_index(S, I) \ - { \ - \ - unsigned int X = S >> TREEBIN_SHIFT; \ - if (X == 0) \ - I = 0; \ - else if (X > 0xFFFF) \ - I = NTREEBINS - 1; \ - else { \ - \ - unsigned int K = (unsigned)sizeof(X) * __CHAR_BIT__ - 1 - \ - (unsigned)__builtin_clz(X); \ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT - 1)) & 1))); \ - \ - } \ - \ - } +#define compute_tree_index(S, I)\ +{\ + unsigned int X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} -#elif defined(__INTEL_COMPILER) - #define compute_tree_index(S, I) \ - { \ - \ - size_t X = S >> TREEBIN_SHIFT; \ - if (X == 0) \ - I = 0; \ - else if (X > 0xFFFF) \ - I = NTREEBINS - 1; \ - else { \ - \ - unsigned int K = _bit_scan_reverse(X); \ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT - 1)) & 1))); \ - \ - } \ - \ - } +#elif defined (__INTEL_COMPILER) +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K = _bit_scan_reverse (X); \ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} -#elif defined(_MSC_VER) && _MSC_VER >= 1300 - #define compute_tree_index(S, I) \ - { \ - \ - size_t X = S >> TREEBIN_SHIFT; \ - if (X == 0) \ - I = 0; \ - else if (X > 0xFFFF) \ - I = NTREEBINS - 1; \ - else { \ - \ - unsigned int K; \ - _BitScanReverse((DWORD *)&K, (DWORD)X); \ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT - 1)) & 1))); \ - \ - } \ - \ - } +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + _BitScanReverse((DWORD *) &K, (DWORD) X);\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} -#else /* GNUC */ - #define compute_tree_index(S, I) \ - { \ - \ - size_t X = S >> TREEBIN_SHIFT; \ - if (X == 0) \ - I = 0; \ - else if (X > 0xFFFF) \ - I = NTREEBINS - 1; \ - else { \ - \ - unsigned int Y = (unsigned int)X; \ - unsigned int N = ((Y - 0x100) >> 16) & 8; \ - unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4; \ - N += K; \ - N += K = (((Y <<= K) - 0x4000) >> 16) & 2; \ - K = 14 - N + ((Y <<= K) >> 15); \ - I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT - 1)) & 1)); \ - \ - } \ - \ - } -#endif /* GNUC */ +#else /* GNUC */ +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int Y = (unsigned int)X;\ + unsigned int N = ((Y - 0x100) >> 16) & 8;\ + unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ + N += K;\ + N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ + K = 14 - N + ((Y <<= K) >> 15);\ + I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ + }\ +} +#endif /* GNUC */ /* Bit representing maximum resolved size in a treebin at i */ #define bit_for_tree_index(i) \ - (i == NTREEBINS - 1) ? (SIZE_T_BITSIZE - 1) : (((i) >> 1) + TREEBIN_SHIFT - 2) + (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) /* Shift placing maximum resolved bit in a treebin at i as sign bit */ #define leftshift_for_tree_index(i) \ - ((i == NTREEBINS - 1) \ - ? 0 \ - : ((SIZE_T_BITSIZE - SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) + ((i == NTREEBINS-1)? 0 : \ + ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) /* The size of the smallest chunk held in bin with index i */ -#define minsize_for_tree_index(i) \ - ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ - (((size_t)((i)&SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) +#define minsize_for_tree_index(i) \ + ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ + (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) + /* ------------------------ Operations on bin maps ----------------------- */ /* bit corresponding to given index */ -#define idx2bit(i) ((binmap_t)(1) << (i)) +#define idx2bit(i) ((binmap_t)(1) << (i)) /* Mark/Clear bits with given index */ -#define mark_smallmap(M, i) ((M)->smallmap |= idx2bit(i)) -#define clear_smallmap(M, i) ((M)->smallmap &= ~idx2bit(i)) -#define smallmap_is_marked(M, i) ((M)->smallmap & idx2bit(i)) +#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) +#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) +#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) -#define mark_treemap(M, i) ((M)->treemap |= idx2bit(i)) -#define clear_treemap(M, i) ((M)->treemap &= ~idx2bit(i)) -#define treemap_is_marked(M, i) ((M)->treemap & idx2bit(i)) +#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) +#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) +#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) /* isolate the least set bit of a bitmap */ -#define least_bit(x) ((x) & -(x)) +#define least_bit(x) ((x) & -(x)) /* mask with all bits to left of least bit of x on */ -#define left_bits(x) ((x << 1) | -(x << 1)) +#define left_bits(x) ((x<<1) | -(x<<1)) /* mask with all bits to left of or equal to least bit of x on */ #define same_or_left_bits(x) ((x) | -(x)) @@ -3097,58 +2989,46 @@ static size_t traverse_and_check(mstate m); /* index corresponding to given bit. Use x86 asm if possible */ #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - #define compute_bit2idx(X, I) \ - { \ - \ - unsigned int J; \ - J = __builtin_ctz(X); \ - I = (bindex_t)J; \ - \ - } +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + J = __builtin_ctz(X); \ + I = (bindex_t)J;\ +} -#elif defined(__INTEL_COMPILER) - #define compute_bit2idx(X, I) \ - { \ - \ - unsigned int J; \ - J = _bit_scan_forward(X); \ - I = (bindex_t)J; \ - \ - } +#elif defined (__INTEL_COMPILER) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + J = _bit_scan_forward (X); \ + I = (bindex_t)J;\ +} -#elif defined(_MSC_VER) && _MSC_VER >= 1300 - #define compute_bit2idx(X, I) \ - { \ - \ - unsigned int J; \ - _BitScanForward((DWORD *)&J, X); \ - I = (bindex_t)J; \ - \ - } +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + _BitScanForward((DWORD *) &J, X);\ + I = (bindex_t)J;\ +} #elif USE_BUILTIN_FFS - #define compute_bit2idx(X, I) I = ffs(X) - 1 +#define compute_bit2idx(X, I) I = ffs(X)-1 #else - #define compute_bit2idx(X, I) \ - { \ - \ - unsigned int Y = X - 1; \ - unsigned int K = Y >> (16 - 4) & 16; \ - unsigned int N = K; \ - Y >>= K; \ - N += K = Y >> (8 - 3) & 8; \ - Y >>= K; \ - N += K = Y >> (4 - 2) & 4; \ - Y >>= K; \ - N += K = Y >> (2 - 1) & 2; \ - Y >>= K; \ - N += K = Y >> (1 - 0) & 1; \ - Y >>= K; \ - I = (bindex_t)(N + Y); \ - \ - } -#endif /* GNUC */ +#define compute_bit2idx(X, I)\ +{\ + unsigned int Y = X - 1;\ + unsigned int K = Y >> (16-4) & 16;\ + unsigned int N = K; Y >>= K;\ + N += K = Y >> (8-3) & 8; Y >>= K;\ + N += K = Y >> (4-2) & 4; Y >>= K;\ + N += K = Y >> (2-1) & 2; Y >>= K;\ + N += K = Y >> (1-0) & 1; Y >>= K;\ + I = (bindex_t)(N + Y);\ +} +#endif /* GNUC */ + /* ----------------------- Runtime Check Support ------------------------- */ @@ -3179,141 +3059,121 @@ static size_t traverse_and_check(mstate m); */ #if !INSECURE - /* Check if address a is at least as high as any from MORECORE or MMAP */ - #define ok_address(M, a) ((char *)(a) >= (M)->least_addr) - /* Check if address of next chunk n is higher than base chunk p */ - #define ok_next(p, n) ((char *)(p) < (char *)(n)) - /* Check if p has inuse status */ - #define ok_inuse(p) is_inuse(p) - /* Check if p has its pinuse bit on */ - #define ok_pinuse(p) pinuse(p) - -#else /* !INSECURE */ - #define ok_address(M, a) (1) - #define ok_next(b, n) (1) - #define ok_inuse(p) (1) - #define ok_pinuse(p) (1) -#endif /* !INSECURE */ +/* Check if address a is at least as high as any from MORECORE or MMAP */ +#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) +/* Check if address of next chunk n is higher than base chunk p */ +#define ok_next(p, n) ((char*)(p) < (char*)(n)) +/* Check if p has inuse status */ +#define ok_inuse(p) is_inuse(p) +/* Check if p has its pinuse bit on */ +#define ok_pinuse(p) pinuse(p) + +#else /* !INSECURE */ +#define ok_address(M, a) (1) +#define ok_next(b, n) (1) +#define ok_inuse(p) (1) +#define ok_pinuse(p) (1) +#endif /* !INSECURE */ #if (FOOTERS && !INSECURE) - /* Check if (alleged) mstate m has expected magic field */ - #define ok_magic(M) ((M)->magic == mparams.magic) -#else /* (FOOTERS && !INSECURE) */ - #define ok_magic(M) (1) -#endif /* (FOOTERS && !INSECURE) */ +/* Check if (alleged) mstate m has expected magic field */ +#define ok_magic(M) ((M)->magic == mparams.magic) +#else /* (FOOTERS && !INSECURE) */ +#define ok_magic(M) (1) +#endif /* (FOOTERS && !INSECURE) */ /* In gcc, use __builtin_expect to minimize impact of checks */ #if !INSECURE - #if defined(__GNUC__) && __GNUC__ >= 3 - #define RTCHECK(e) __builtin_expect(e, 1) - #else /* GNUC */ - #define RTCHECK(e) (e) - #endif /* GNUC */ -#else /* !INSECURE */ - #define RTCHECK(e) (1) -#endif /* !INSECURE */ +#if defined(__GNUC__) && __GNUC__ >= 3 +#define RTCHECK(e) __builtin_expect(e, 1) +#else /* GNUC */ +#define RTCHECK(e) (e) +#endif /* GNUC */ +#else /* !INSECURE */ +#define RTCHECK(e) (1) +#endif /* !INSECURE */ /* macros to set up inuse chunks with or without footers */ #if !FOOTERS - #define mark_inuse_foot(M, p, s) +#define mark_inuse_foot(M,p,s) - /* Macros for setting head/foot of non-mmapped chunks */ +/* Macros for setting head/foot of non-mmapped chunks */ - /* Set cinuse bit and pinuse bit of next chunk */ - #define set_inuse(M, p, s) \ - ((p)->head = (((p)->head & PINUSE_BIT) | s | CINUSE_BIT), \ - ((mchunkptr)(((char *)(p)) + (s)))->head |= PINUSE_BIT) +/* Set cinuse bit and pinuse bit of next chunk */ +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) - /* Set cinuse and pinuse of this chunk and pinuse of next chunk */ - #define set_inuse_and_pinuse(M, p, s) \ - ((p)->head = (s | PINUSE_BIT | CINUSE_BIT), \ - ((mchunkptr)(((char *)(p)) + (s)))->head |= PINUSE_BIT) +/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) - /* Set size, cinuse and pinuse bit of this chunk */ - #define set_size_and_pinuse_of_inuse_chunk(M, p, s) \ - ((p)->head = (s | PINUSE_BIT | CINUSE_BIT)) +/* Set size, cinuse and pinuse bit of this chunk */ +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) -#else /* FOOTERS */ +#else /* FOOTERS */ - /* Set foot of inuse chunk to be xor of mstate and seed */ - #define mark_inuse_foot(M, p, s) \ - (((mchunkptr)((char *)(p) + (s)))->prev_foot = \ - ((size_t)(M) ^ mparams.magic)) +/* Set foot of inuse chunk to be xor of mstate and seed */ +#define mark_inuse_foot(M,p,s)\ + (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) - #define get_mstate_for(p) \ - ((mstate)(((mchunkptr)((char *)(p) + (chunksize(p))))->prev_foot ^ \ - mparams.magic)) +#define get_mstate_for(p)\ + ((mstate)(((mchunkptr)((char*)(p) +\ + (chunksize(p))))->prev_foot ^ mparams.magic)) - #define set_inuse(M, p, s) \ - ((p)->head = (((p)->head & PINUSE_BIT) | s | CINUSE_BIT), \ - (((mchunkptr)(((char *)(p)) + (s)))->head |= PINUSE_BIT), \ - mark_inuse_foot(M, p, s)) +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ + mark_inuse_foot(M,p,s)) - #define set_inuse_and_pinuse(M, p, s) \ - ((p)->head = (s | PINUSE_BIT | CINUSE_BIT), \ - (((mchunkptr)(((char *)(p)) + (s)))->head |= PINUSE_BIT), \ - mark_inuse_foot(M, p, s)) +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ + mark_inuse_foot(M,p,s)) - #define set_size_and_pinuse_of_inuse_chunk(M, p, s) \ - ((p)->head = (s | PINUSE_BIT | CINUSE_BIT), mark_inuse_foot(M, p, s)) +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + mark_inuse_foot(M, p, s)) -#endif /* !FOOTERS */ +#endif /* !FOOTERS */ /* ---------------------------- setting mparams -------------------------- */ #if LOCK_AT_FORK -static void pre_fork(void) { - - ACQUIRE_LOCK(&(gm)->mutex); - -} - -static void post_fork_parent(void) { - - RELEASE_LOCK(&(gm)->mutex); - -} - -static void post_fork_child(void) { - - INITIAL_LOCK(&(gm)->mutex); - -} - -#endif /* LOCK_AT_FORK */ +static void pre_fork(void) { ACQUIRE_LOCK(&(gm)->mutex); } +static void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); } +static void post_fork_child(void) { INITIAL_LOCK(&(gm)->mutex); } +#endif /* LOCK_AT_FORK */ /* Initialize mparams */ static int init_mparams(void) { - #ifdef NEED_GLOBAL_LOCK_INIT - if (malloc_global_mutex_status <= 0) init_malloc_global_mutex(); + if (malloc_global_mutex_status <= 0) + init_malloc_global_mutex(); #endif ACQUIRE_MALLOC_GLOBAL_LOCK(); if (mparams.magic == 0) { - size_t magic; size_t psize; size_t gsize; #ifndef WIN32 psize = malloc_getpagesize; - gsize = ((DEFAULT_GRANULARITY != 0) ? DEFAULT_GRANULARITY : psize); -#else /* WIN32 */ + gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize); +#else /* WIN32 */ { - SYSTEM_INFO system_info; GetSystemInfo(&system_info); psize = system_info.dwPageSize; - gsize = - ((DEFAULT_GRANULARITY != 0) ? DEFAULT_GRANULARITY - : system_info.dwAllocationGranularity); - + gsize = ((DEFAULT_GRANULARITY != 0)? + DEFAULT_GRANULARITY : system_info.dwAllocationGranularity); } - -#endif /* WIN32 */ +#endif /* WIN32 */ /* Sanity-check configuration: size_t must be unsigned and as wide as pointer type. @@ -3321,23 +3181,24 @@ static int init_mparams(void) { alignment must be at least 8. Alignment, min chunk size, and page size must all be powers of 2. */ - if ((sizeof(size_t) != sizeof(char *)) || (MAX_SIZE_T < MIN_CHUNK_SIZE) || - (sizeof(int) < 4) || (MALLOC_ALIGNMENT < (size_t)8U) || - ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT - SIZE_T_ONE)) != 0) || - ((MCHUNK_SIZE & (MCHUNK_SIZE - SIZE_T_ONE)) != 0) || - ((gsize & (gsize - SIZE_T_ONE)) != 0) || - ((psize & (psize - SIZE_T_ONE)) != 0)) + if ((sizeof(size_t) != sizeof(char*)) || + (MAX_SIZE_T < MIN_CHUNK_SIZE) || + (sizeof(int) < 4) || + (MALLOC_ALIGNMENT < (size_t)8U) || + ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || + ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || + ((gsize & (gsize-SIZE_T_ONE)) != 0) || + ((psize & (psize-SIZE_T_ONE)) != 0)) ABORT; mparams.granularity = gsize; mparams.page_size = psize; mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; #if MORECORE_CONTIGUOUS - mparams.default_mflags = USE_LOCK_BIT | USE_MMAP_BIT; -#else /* MORECORE_CONTIGUOUS */ - mparams.default_mflags = - USE_LOCK_BIT | USE_MMAP_BIT | USE_NONCONTIGUOUS_BIT; -#endif /* MORECORE_CONTIGUOUS */ + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; +#else /* MORECORE_CONTIGUOUS */ + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; +#endif /* MORECORE_CONTIGUOUS */ #if !ONLY_MSPACES /* Set up lock for main malloc area */ @@ -3349,69 +3210,57 @@ static int init_mparams(void) { #endif { - #if USE_DEV_RANDOM - int fd; + int fd; unsigned char buf[sizeof(size_t)]; /* Try to use /dev/urandom, else fall back on using time */ if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && read(fd, buf, sizeof(buf)) == sizeof(buf)) { - - magic = *((size_t *)buf); + magic = *((size_t *) buf); close(fd); - - } else - -#endif /* USE_DEV_RANDOM */ + } + else +#endif /* USE_DEV_RANDOM */ #ifdef WIN32 - magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U); + magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U); #elif defined(LACKS_TIME_H) magic = (size_t)&magic ^ (size_t)0x55555555U; #else magic = (size_t)(time(0) ^ (size_t)0x55555555U); #endif - magic |= (size_t)8U; /* ensure nonzero */ - magic &= ~(size_t)7U; /* improve chances of fault for bad values */ + magic |= (size_t)8U; /* ensure nonzero */ + magic &= ~(size_t)7U; /* improve chances of fault for bad values */ /* Until memory modes commonly available, use volatile-write */ (*(volatile size_t *)(&(mparams.magic))) = magic; - } - } RELEASE_MALLOC_GLOBAL_LOCK(); return 1; - } /* support for mallopt */ static int change_mparam(int param_number, int value) { - size_t val; ensure_initialization(); - val = (value == -1) ? MAX_SIZE_T : (size_t)value; - switch (param_number) { - - case M_TRIM_THRESHOLD: - mparams.trim_threshold = val; - return 1; - case M_GRANULARITY: - if (val >= mparams.page_size && ((val & (val - 1)) == 0)) { - - mparams.granularity = val; - return 1; - - } else - - return 0; - case M_MMAP_THRESHOLD: - mparams.mmap_threshold = val; + val = (value == -1)? MAX_SIZE_T : (size_t)value; + switch(param_number) { + case M_TRIM_THRESHOLD: + mparams.trim_threshold = val; + return 1; + case M_GRANULARITY: + if (val >= mparams.page_size && ((val & (val-1)) == 0)) { + mparams.granularity = val; return 1; - default: + } + else return 0; - + case M_MMAP_THRESHOLD: + mparams.mmap_threshold = val; + return 1; + default: + return 0; } - } #if DEBUG @@ -3419,118 +3268,100 @@ static int change_mparam(int param_number, int value) { /* Check properties of any chunk, whether free, inuse, mmapped etc */ static void do_check_any_chunk(mstate m, mchunkptr p) { - assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); assert(ok_address(m, p)); - } /* Check properties of top chunk */ static void do_check_top_chunk(mstate m, mchunkptr p) { - - msegmentptr sp = segment_holding(m, (char *)p); - size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */ + msegmentptr sp = segment_holding(m, (char*)p); + size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */ assert(sp != 0); assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); assert(ok_address(m, p)); assert(sz == m->topsize); assert(sz > 0); - assert(sz == ((sp->base + sp->size) - (char *)p) - TOP_FOOT_SIZE); + assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); assert(pinuse(p)); assert(!pinuse(chunk_plus_offset(p, sz))); - } /* Check properties of (inuse) mmapped chunks */ static void do_check_mmapped_chunk(mstate m, mchunkptr p) { - - size_t sz = chunksize(p); + size_t sz = chunksize(p); size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD); assert(is_mmapped(p)); assert(use_mmap(m)); assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); assert(ok_address(m, p)); assert(!is_small(sz)); - assert((len & (mparams.page_size - SIZE_T_ONE)) == 0); + assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); - assert(chunk_plus_offset(p, sz + SIZE_T_SIZE)->head == 0); - + assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); } /* Check properties of inuse chunks */ static void do_check_inuse_chunk(mstate m, mchunkptr p) { - do_check_any_chunk(m, p); assert(is_inuse(p)); assert(next_pinuse(p)); /* If not pinuse and not mmapped, previous chunk has OK offset */ assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); - if (is_mmapped(p)) do_check_mmapped_chunk(m, p); - + if (is_mmapped(p)) + do_check_mmapped_chunk(m, p); } /* Check properties of free chunks */ static void do_check_free_chunk(mstate m, mchunkptr p) { - - size_t sz = chunksize(p); + size_t sz = chunksize(p); mchunkptr next = chunk_plus_offset(p, sz); do_check_any_chunk(m, p); assert(!is_inuse(p)); assert(!next_pinuse(p)); - assert(!is_mmapped(p)); + assert (!is_mmapped(p)); if (p != m->dv && p != m->top) { - if (sz >= MIN_CHUNK_SIZE) { - assert((sz & CHUNK_ALIGN_MASK) == 0); assert(is_aligned(chunk2mem(p))); assert(next->prev_foot == sz); assert(pinuse(p)); - assert(next == m->top || is_inuse(next)); + assert (next == m->top || is_inuse(next)); assert(p->fd->bk == p); assert(p->bk->fd == p); - - } else /* markers are always of size SIZE_T_SIZE */ - + } + else /* markers are always of size SIZE_T_SIZE */ assert(sz == SIZE_T_SIZE); - } - } /* Check properties of malloced chunks at the point they are malloced */ -static void do_check_malloced_chunk(mstate m, void *mem, size_t s) { - +static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { if (mem != 0) { - mchunkptr p = mem2chunk(mem); - size_t sz = p->head & ~INUSE_BITS; + size_t sz = p->head & ~INUSE_BITS; do_check_inuse_chunk(m, p); assert((sz & CHUNK_ALIGN_MASK) == 0); assert(sz >= MIN_CHUNK_SIZE); assert(sz >= s); /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); - } - } /* Check a tree and its subtrees. */ static void do_check_tree(mstate m, tchunkptr t) { - tchunkptr head = 0; tchunkptr u = t; - bindex_t tindex = t->index; - size_t tsize = chunksize(t); - bindex_t idx; + bindex_t tindex = t->index; + size_t tsize = chunksize(t); + bindex_t idx; compute_tree_index(tsize, idx); assert(tindex == idx); assert(tsize >= MIN_LARGE_SIZE); assert(tsize >= minsize_for_tree_index(idx)); - assert((idx == NTREEBINS - 1) || (tsize < minsize_for_tree_index((idx + 1)))); + assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); - do { /* traverse through chain of same-sized nodes */ + do { /* traverse through chain of same-sized nodes */ do_check_any_chunk(m, ((mchunkptr)u)); assert(u->index == tindex); assert(chunksize(u) == tsize); @@ -3539,72 +3370,56 @@ static void do_check_tree(mstate m, tchunkptr t) { assert(u->fd->bk == u); assert(u->bk->fd == u); if (u->parent == 0) { - assert(u->child[0] == 0); assert(u->child[1] == 0); - - } else { - - assert(head == 0); /* only one node on chain has parent */ + } + else { + assert(head == 0); /* only one node on chain has parent */ head = u; assert(u->parent != u); - assert(u->parent->child[0] == u || u->parent->child[1] == u || - *((tbinptr *)(u->parent)) == u); + assert (u->parent->child[0] == u || + u->parent->child[1] == u || + *((tbinptr*)(u->parent)) == u); if (u->child[0] != 0) { - assert(u->child[0]->parent == u); assert(u->child[0] != u); do_check_tree(m, u->child[0]); - } - if (u->child[1] != 0) { - assert(u->child[1]->parent == u); assert(u->child[1] != u); do_check_tree(m, u->child[1]); - } - if (u->child[0] != 0 && u->child[1] != 0) { - assert(chunksize(u->child[0]) < chunksize(u->child[1])); - } - } - u = u->fd; - } while (u != t); - assert(head != 0); - } /* Check all the chunks in a treebin. */ static void do_check_treebin(mstate m, bindex_t i) { - - tbinptr * tb = treebin_at(m, i); + tbinptr* tb = treebin_at(m, i); tchunkptr t = *tb; - int empty = (m->treemap & (1U << i)) == 0; - if (t == 0) assert(empty); - if (!empty) do_check_tree(m, t); - + int empty = (m->treemap & (1U << i)) == 0; + if (t == 0) + assert(empty); + if (!empty) + do_check_tree(m, t); } /* Check all the chunks in a smallbin. */ static void do_check_smallbin(mstate m, bindex_t i) { - - sbinptr b = smallbin_at(m, i); - mchunkptr p = b->bk; + sbinptr b = smallbin_at(m, i); + mchunkptr p = b->bk; unsigned int empty = (m->smallmap & (1U << i)) == 0; - if (p == b) assert(empty); + if (p == b) + assert(empty); if (!empty) { - for (; p != b; p = p->bk) { - - size_t size = chunksize(p); + size_t size = chunksize(p); mchunkptr q; /* each chunk claims to be free */ do_check_free_chunk(m, p); @@ -3613,249 +3428,185 @@ static void do_check_smallbin(mstate m, bindex_t i) { assert(p->bk == b || chunksize(p->bk) == chunksize(p)); /* chunk is followed by an inuse chunk */ q = next_chunk(p); - if (q->head != FENCEPOST_HEAD) do_check_inuse_chunk(m, q); - + if (q->head != FENCEPOST_HEAD) + do_check_inuse_chunk(m, q); } - } - } /* Find x in a bin. Used in other check functions. */ static int bin_find(mstate m, mchunkptr x) { - size_t size = chunksize(x); if (is_small(size)) { - bindex_t sidx = small_index(size); - sbinptr b = smallbin_at(m, sidx); + sbinptr b = smallbin_at(m, sidx); if (smallmap_is_marked(m, sidx)) { - mchunkptr p = b; do { - - if (p == x) return 1; - + if (p == x) + return 1; } while ((p = p->fd) != b); - } - - } else { - + } + else { bindex_t tidx; compute_tree_index(size, tidx); if (treemap_is_marked(m, tidx)) { - tchunkptr t = *treebin_at(m, tidx); - size_t sizebits = size << leftshift_for_tree_index(tidx); + size_t sizebits = size << leftshift_for_tree_index(tidx); while (t != 0 && chunksize(t) != size) { - - t = t->child[(sizebits >> (SIZE_T_BITSIZE - SIZE_T_ONE)) & 1]; + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; sizebits <<= 1; - } - if (t != 0) { - tchunkptr u = t; do { - - if (u == (tchunkptr)x) return 1; - + if (u == (tchunkptr)x) + return 1; } while ((u = u->fd) != t); - } - } - } - return 0; - } /* Traverse each chunk and check it; return total */ static size_t traverse_and_check(mstate m) { - size_t sum = 0; if (is_initialized(m)) { - msegmentptr s = &m->seg; sum += m->topsize + TOP_FOOT_SIZE; while (s != 0) { - mchunkptr q = align_as_chunk(s->base); mchunkptr lastq = 0; assert(pinuse(q)); - while (segment_holds(s, q) && q != m->top && q->head != FENCEPOST_HEAD) { - + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { sum += chunksize(q); if (is_inuse(q)) { - assert(!bin_find(m, q)); do_check_inuse_chunk(m, q); - - } else { - + } + else { assert(q == m->dv || bin_find(m, q)); - assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */ + assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */ do_check_free_chunk(m, q); - } - lastq = q; q = next_chunk(q); - } - s = s->next; - } - } - return sum; - } + /* Check all properties of malloc_state. */ static void do_check_malloc_state(mstate m) { - bindex_t i; - size_t total; + size_t total; /* check bins */ for (i = 0; i < NSMALLBINS; ++i) do_check_smallbin(m, i); for (i = 0; i < NTREEBINS; ++i) do_check_treebin(m, i); - if (m->dvsize != 0) { /* check dv chunk */ + if (m->dvsize != 0) { /* check dv chunk */ do_check_any_chunk(m, m->dv); assert(m->dvsize == chunksize(m->dv)); assert(m->dvsize >= MIN_CHUNK_SIZE); assert(bin_find(m, m->dv) == 0); - } - if (m->top != 0) { /* check top chunk */ + if (m->top != 0) { /* check top chunk */ do_check_top_chunk(m, m->top); /*assert(m->topsize == chunksize(m->top)); redundant */ assert(m->topsize > 0); assert(bin_find(m, m->top) == 0); - } total = traverse_and_check(m); assert(total <= m->footprint); assert(m->footprint <= m->max_footprint); - } - -#endif /* DEBUG */ +#endif /* DEBUG */ /* ----------------------------- statistics ------------------------------ */ #if !NO_MALLINFO static struct mallinfo internal_mallinfo(mstate m) { - - struct mallinfo nm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ensure_initialization(); if (!PREACTION(m)) { - check_malloc_state(m); if (is_initialized(m)) { - - size_t nfree = SIZE_T_ONE; /* top always free */ - size_t mfree = m->topsize + TOP_FOOT_SIZE; - size_t sum = mfree; + size_t nfree = SIZE_T_ONE; /* top always free */ + size_t mfree = m->topsize + TOP_FOOT_SIZE; + size_t sum = mfree; msegmentptr s = &m->seg; while (s != 0) { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && q != m->top && - q->head != FENCEPOST_HEAD) { - + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { size_t sz = chunksize(q); sum += sz; if (!is_inuse(q)) { - mfree += sz; ++nfree; - } - q = next_chunk(q); - } - s = s->next; - } - nm.arena = sum; - nm.ordblks = nfree; - nm.hblkhd = m->footprint - sum; - nm.usmblks = m->max_footprint; + nm.arena = sum; + nm.ordblks = nfree; + nm.hblkhd = m->footprint - sum; + nm.usmblks = m->max_footprint; nm.uordblks = m->footprint - mfree; nm.fordblks = mfree; nm.keepcost = m->topsize; - } POSTACTION(m); - } - return nm; - } - -#endif /* !NO_MALLINFO */ +#endif /* !NO_MALLINFO */ #if !NO_MALLOC_STATS static void internal_malloc_stats(mstate m) { - ensure_initialization(); if (!PREACTION(m)) { - size_t maxfp = 0; size_t fp = 0; size_t used = 0; check_malloc_state(m); if (is_initialized(m)) { - msegmentptr s = &m->seg; maxfp = m->max_footprint; fp = m->footprint; used = fp - (m->topsize + TOP_FOOT_SIZE); while (s != 0) { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && q != m->top && - q->head != FENCEPOST_HEAD) { - - if (!is_inuse(q)) used -= chunksize(q); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + if (!is_inuse(q)) + used -= chunksize(q); q = next_chunk(q); - } - s = s->next; - } - } - - POSTACTION(m); /* drop lock */ + POSTACTION(m); /* drop lock */ fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); - } - } - -#endif /* NO_MALLOC_STATS */ +#endif /* NO_MALLOC_STATS */ /* ----------------------- Operations on smallbins ----------------------- */ @@ -3867,181 +3618,134 @@ static void internal_malloc_stats(mstate m) { */ /* Link a free chunk into a smallbin */ -#define insert_small_chunk(M, P, S) \ - { \ - \ - bindex_t I = small_index(S); \ - mchunkptr B = smallbin_at(M, I); \ - mchunkptr F = B; \ - assert(S >= MIN_CHUNK_SIZE); \ - if (!smallmap_is_marked(M, I)) \ - mark_smallmap(M, I); \ - else if (RTCHECK(ok_address(M, B->fd))) \ - F = B->fd; \ - else { \ - \ - CORRUPTION_ERROR_ACTION(M); \ - \ - } \ - B->fd = P; \ - F->bk = P; \ - P->fd = F; \ - P->bk = B; \ - \ - } +#define insert_small_chunk(M, P, S) {\ + bindex_t I = small_index(S);\ + mchunkptr B = smallbin_at(M, I);\ + mchunkptr F = B;\ + assert(S >= MIN_CHUNK_SIZE);\ + if (!smallmap_is_marked(M, I))\ + mark_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, B->fd)))\ + F = B->fd;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + B->fd = P;\ + F->bk = P;\ + P->fd = F;\ + P->bk = B;\ +} /* Unlink a chunk from a smallbin */ -#define unlink_small_chunk(M, P, S) \ - { \ - \ - mchunkptr F = P->fd; \ - mchunkptr B = P->bk; \ - bindex_t I = small_index(S); \ - assert(P != B); \ - assert(P != F); \ - assert(chunksize(P) == small_index2size(I)); \ - if (RTCHECK(F == smallbin_at(M, I) || (ok_address(M, F) && F->bk == P))) { \ - \ - if (B == F) { \ - \ - clear_smallmap(M, I); \ - \ - } else if (RTCHECK(B == smallbin_at(M, I) || \ - \ - \ - (ok_address(M, B) && B->fd == P))) { \ - \ - F->bk = B; \ - B->fd = F; \ - \ - } else { \ - \ - CORRUPTION_ERROR_ACTION(M); \ - \ - } \ - \ - } else { \ - \ - CORRUPTION_ERROR_ACTION(M); \ - \ - } \ - \ - } +#define unlink_small_chunk(M, P, S) {\ + mchunkptr F = P->fd;\ + mchunkptr B = P->bk;\ + bindex_t I = small_index(S);\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \ + if (B == F) {\ + clear_smallmap(M, I);\ + }\ + else if (RTCHECK(B == smallbin_at(M,I) ||\ + (ok_address(M, B) && B->fd == P))) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} /* Unlink the first chunk from a smallbin */ -#define unlink_first_small_chunk(M, B, P, I) \ - { \ - \ - mchunkptr F = P->fd; \ - assert(P != B); \ - assert(P != F); \ - assert(chunksize(P) == small_index2size(I)); \ - if (B == F) { \ - \ - clear_smallmap(M, I); \ - \ - } else if (RTCHECK(ok_address(M, F) && F->bk == P)) { \ - \ - F->bk = B; \ - B->fd = F; \ - \ - } else { \ - \ - CORRUPTION_ERROR_ACTION(M); \ - \ - } \ - \ - } +#define unlink_first_small_chunk(M, B, P, I) {\ + mchunkptr F = P->fd;\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (B == F) {\ + clear_smallmap(M, I);\ + }\ + else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} /* Replace dv node, binning the old one */ /* Used only when dvsize known to be small */ -#define replace_dv(M, P, S) \ - { \ - \ - size_t DVS = M->dvsize; \ - assert(is_small(DVS)); \ - if (DVS != 0) { \ - \ - mchunkptr DV = M->dv; \ - insert_small_chunk(M, DV, DVS); \ - \ - } \ - M->dvsize = S; \ - M->dv = P; \ - \ - } +#define replace_dv(M, P, S) {\ + size_t DVS = M->dvsize;\ + assert(is_small(DVS));\ + if (DVS != 0) {\ + mchunkptr DV = M->dv;\ + insert_small_chunk(M, DV, DVS);\ + }\ + M->dvsize = S;\ + M->dv = P;\ +} /* ------------------------- Operations on trees ------------------------- */ /* Insert chunk into tree */ -#define insert_large_chunk(M, X, S) \ - { \ - \ - tbinptr *H; \ - bindex_t I; \ - compute_tree_index(S, I); \ - H = treebin_at(M, I); \ - X->index = I; \ - X->child[0] = X->child[1] = 0; \ - if (!treemap_is_marked(M, I)) { \ - \ - mark_treemap(M, I); \ - *H = X; \ - X->parent = (tchunkptr)H; \ - X->fd = X->bk = X; \ - \ - } else { \ - \ - tchunkptr T = *H; \ - size_t K = S << leftshift_for_tree_index(I); \ - for (;;) { \ - \ - if (chunksize(T) != S) { \ - \ - tchunkptr *C = \ - &(T->child[(K >> (SIZE_T_BITSIZE - SIZE_T_ONE)) & 1]); \ - K <<= 1; \ - if (*C != 0) \ - T = *C; \ - else if (RTCHECK(ok_address(M, C))) { \ - \ - *C = X; \ - X->parent = T; \ - X->fd = X->bk = X; \ - break; \ - \ - } else { \ - \ - CORRUPTION_ERROR_ACTION(M); \ - break; \ - \ - } \ - \ - } else { \ - \ - tchunkptr F = T->fd; \ - if (RTCHECK(ok_address(M, T) && ok_address(M, F))) { \ - \ - T->fd = F->bk = X; \ - X->fd = F; \ - X->bk = T; \ - X->parent = 0; \ - break; \ - \ - } else { \ - \ - CORRUPTION_ERROR_ACTION(M); \ - break; \ - \ - } \ - \ - } \ - \ - } \ - \ - } \ - \ - } +#define insert_large_chunk(M, X, S) {\ + tbinptr* H;\ + bindex_t I;\ + compute_tree_index(S, I);\ + H = treebin_at(M, I);\ + X->index = I;\ + X->child[0] = X->child[1] = 0;\ + if (!treemap_is_marked(M, I)) {\ + mark_treemap(M, I);\ + *H = X;\ + X->parent = (tchunkptr)H;\ + X->fd = X->bk = X;\ + }\ + else {\ + tchunkptr T = *H;\ + size_t K = S << leftshift_for_tree_index(I);\ + for (;;) {\ + if (chunksize(T) != S) {\ + tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ + K <<= 1;\ + if (*C != 0)\ + T = *C;\ + else if (RTCHECK(ok_address(M, C))) {\ + *C = X;\ + X->parent = T;\ + X->fd = X->bk = X;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + else {\ + tchunkptr F = T->fd;\ + if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ + T->fd = F->bk = X;\ + X->fd = F;\ + X->bk = T;\ + X->parent = 0;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + }\ + }\ +} /* Unlink steps: @@ -4060,149 +3764,104 @@ static void internal_malloc_stats(mstate m) { x's parent and children to x's replacement (or null if none). */ -#define unlink_large_chunk(M, X) \ - { \ - \ - tchunkptr XP = X->parent; \ - tchunkptr R; \ - if (X->bk != X) { \ - \ - tchunkptr F = X->fd; \ - R = X->bk; \ - if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) { \ - \ - F->bk = R; \ - R->fd = F; \ - \ - } else { \ - \ - CORRUPTION_ERROR_ACTION(M); \ - \ - } \ - \ - } else { \ - \ - tchunkptr *RP; \ - if (((R = *(RP = &(X->child[1]))) != 0) || \ - ((R = *(RP = &(X->child[0]))) != 0)) { \ - \ - tchunkptr *CP; \ - while ((*(CP = &(R->child[1])) != 0) || \ - (*(CP = &(R->child[0])) != 0)) { \ - \ - R = *(RP = CP); \ - \ - } \ - if (RTCHECK(ok_address(M, RP))) \ - *RP = 0; \ - else { \ - \ - CORRUPTION_ERROR_ACTION(M); \ - \ - } \ - \ - } \ - \ - } \ - if (XP != 0) { \ - \ - tbinptr *H = treebin_at(M, X->index); \ - if (X == *H) { \ - \ - if ((*H = R) == 0) clear_treemap(M, X->index); \ - \ - } else if (RTCHECK(ok_address(M, XP))) { \ - \ - if (XP->child[0] == X) \ - XP->child[0] = R; \ - else \ - XP->child[1] = R; \ - \ - } else \ - \ - \ - CORRUPTION_ERROR_ACTION(M); \ - if (R != 0) { \ - \ - if (RTCHECK(ok_address(M, R))) { \ - \ - tchunkptr C0, C1; \ - R->parent = XP; \ - if ((C0 = X->child[0]) != 0) { \ - \ - if (RTCHECK(ok_address(M, C0))) { \ - \ - R->child[0] = C0; \ - C0->parent = R; \ - \ - } else \ - \ - \ - CORRUPTION_ERROR_ACTION(M); \ - \ - } \ - if ((C1 = X->child[1]) != 0) { \ - \ - if (RTCHECK(ok_address(M, C1))) { \ - \ - R->child[1] = C1; \ - C1->parent = R; \ - \ - } else \ - \ - \ - CORRUPTION_ERROR_ACTION(M); \ - \ - } \ - \ - } else \ - \ - \ - CORRUPTION_ERROR_ACTION(M); \ - \ - } \ - \ - } \ - \ - } +#define unlink_large_chunk(M, X) {\ + tchunkptr XP = X->parent;\ + tchunkptr R;\ + if (X->bk != X) {\ + tchunkptr F = X->fd;\ + R = X->bk;\ + if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\ + F->bk = R;\ + R->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + tchunkptr* RP;\ + if (((R = *(RP = &(X->child[1]))) != 0) ||\ + ((R = *(RP = &(X->child[0]))) != 0)) {\ + tchunkptr* CP;\ + while ((*(CP = &(R->child[1])) != 0) ||\ + (*(CP = &(R->child[0])) != 0)) {\ + R = *(RP = CP);\ + }\ + if (RTCHECK(ok_address(M, RP)))\ + *RP = 0;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + }\ + if (XP != 0) {\ + tbinptr* H = treebin_at(M, X->index);\ + if (X == *H) {\ + if ((*H = R) == 0) \ + clear_treemap(M, X->index);\ + }\ + else if (RTCHECK(ok_address(M, XP))) {\ + if (XP->child[0] == X) \ + XP->child[0] = R;\ + else \ + XP->child[1] = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + if (R != 0) {\ + if (RTCHECK(ok_address(M, R))) {\ + tchunkptr C0, C1;\ + R->parent = XP;\ + if ((C0 = X->child[0]) != 0) {\ + if (RTCHECK(ok_address(M, C0))) {\ + R->child[0] = C0;\ + C0->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + if ((C1 = X->child[1]) != 0) {\ + if (RTCHECK(ok_address(M, C1))) {\ + R->child[1] = C1;\ + C1->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ +} /* Relays to large vs small bin operations */ -#define insert_chunk(M, P, S) \ - if (is_small(S)) insert_small_chunk(M, P, S) else { \ - \ - tchunkptr TP = (tchunkptr)(P); \ - insert_large_chunk(M, TP, S); \ - \ - } +#define insert_chunk(M, P, S)\ + if (is_small(S)) insert_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } + +#define unlink_chunk(M, P, S)\ + if (is_small(S)) unlink_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } -#define unlink_chunk(M, P, S) \ - if (is_small(S)) unlink_small_chunk(M, P, S) else { \ - \ - tchunkptr TP = (tchunkptr)(P); \ - unlink_large_chunk(M, TP); \ - \ - } /* Relays to internal calls to malloc/free from realloc, memalign etc */ #if ONLY_MSPACES - #define internal_malloc(m, b) mspace_malloc(m, b) - #define internal_free(m, mem) mspace_free(m, mem); -#else /* ONLY_MSPACES */ - #if MSPACES - #define internal_malloc(m, b) \ - ((m == gm) ? dlmalloc(b) : mspace_malloc(m, b)) - #define internal_free(m, mem) \ - if (m == gm) \ - dlfree(mem); \ - else \ - mspace_free(m, mem); - #else /* MSPACES */ - #define internal_malloc(m, b) dlmalloc(b) - #define internal_free(m, mem) dlfree(mem) - #endif /* MSPACES */ -#endif /* ONLY_MSPACES */ +#define internal_malloc(m, b) mspace_malloc(m, b) +#define internal_free(m, mem) mspace_free(m,mem); +#else /* ONLY_MSPACES */ +#if MSPACES +#define internal_malloc(m, b)\ + ((m == gm)? dlmalloc(b) : mspace_malloc(m, b)) +#define internal_free(m, mem)\ + if (m == gm) dlfree(mem); else mspace_free(m,mem); +#else /* MSPACES */ +#define internal_malloc(m, b) dlmalloc(b) +#define internal_free(m, mem) dlfree(mem) +#endif /* MSPACES */ +#endif /* ONLY_MSPACES */ /* ----------------------- Direct-mmapping chunks ----------------------- */ @@ -4215,93 +3874,80 @@ static void internal_malloc_stats(mstate m) { */ /* Malloc using mmap */ -static void *mmap_alloc(mstate m, size_t nb) { - +static void* mmap_alloc(mstate m, size_t nb) { size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); if (m->footprint_limit != 0) { - size_t fp = m->footprint + mmsize; - if (fp <= m->footprint || fp > m->footprint_limit) return 0; - + if (fp <= m->footprint || fp > m->footprint_limit) + return 0; } - - if (mmsize > nb) { /* Check for wrap around 0 */ - char *mm = (char *)(CALL_DIRECT_MMAP(mmsize)); + if (mmsize > nb) { /* Check for wrap around 0 */ + char* mm = (char*)(CALL_DIRECT_MMAP(mmsize)); if (mm != CMFAIL) { - - size_t offset = align_offset(chunk2mem(mm)); - size_t psize = mmsize - offset - MMAP_FOOT_PAD; + size_t offset = align_offset(chunk2mem(mm)); + size_t psize = mmsize - offset - MMAP_FOOT_PAD; mchunkptr p = (mchunkptr)(mm + offset); p->prev_foot = offset; p->head = psize; mark_inuse_foot(m, p, psize); chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(p, psize + SIZE_T_SIZE)->head = 0; + chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; - if (m->least_addr == 0 || mm < m->least_addr) m->least_addr = mm; + if (m->least_addr == 0 || mm < m->least_addr) + m->least_addr = mm; if ((m->footprint += mmsize) > m->max_footprint) m->max_footprint = m->footprint; assert(is_aligned(chunk2mem(p))); check_mmapped_chunk(m, p); return chunk2mem(p); - } - } - return 0; - } /* Realloc using mmap */ static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) { - size_t oldsize = chunksize(oldp); - (void)flags; /* placate people compiling -Wunused */ - if (is_small(nb)) /* Can't shrink mmap regions below small size */ + (void)flags; /* placate people compiling -Wunused */ + if (is_small(nb)) /* Can't shrink mmap regions below small size */ return 0; /* Keep old chunk if big enough but not too big */ if (oldsize >= nb + SIZE_T_SIZE && (oldsize - nb) <= (mparams.granularity << 1)) return oldp; else { - size_t offset = oldp->prev_foot; size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - char * cp = - (char *)CALL_MREMAP((char *)oldp - offset, oldmmsize, newmmsize, flags); + char* cp = (char*)CALL_MREMAP((char*)oldp - offset, + oldmmsize, newmmsize, flags); if (cp != CMFAIL) { - mchunkptr newp = (mchunkptr)(cp + offset); - size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; newp->head = psize; mark_inuse_foot(m, newp, psize); chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(newp, psize + SIZE_T_SIZE)->head = 0; + chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; - if (cp < m->least_addr) m->least_addr = cp; + if (cp < m->least_addr) + m->least_addr = cp; if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) m->max_footprint = m->footprint; check_mmapped_chunk(m, newp); return newp; - } - } - return 0; - } + /* -------------------------- mspace management -------------------------- */ /* Initialize top chunk and its size */ static void init_top(mstate m, mchunkptr p, size_t psize) { - /* Ensure alignment */ size_t offset = align_offset(chunk2mem(p)); - p = (mchunkptr)((char *)p + offset); + p = (mchunkptr)((char*)p + offset); psize -= offset; m->top = p; @@ -4309,29 +3955,23 @@ static void init_top(mstate m, mchunkptr p, size_t psize) { p->head = psize | PINUSE_BIT; /* set size of fake trailing chunk holding overhead space only once */ chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; - m->trim_check = mparams.trim_threshold; /* reset on each update */ - + m->trim_check = mparams.trim_threshold; /* reset on each update */ } /* Initialize bins for a new mstate that is otherwise zeroed out */ static void init_bins(mstate m) { - /* Establish circular links for smallbins */ bindex_t i; for (i = 0; i < NSMALLBINS; ++i) { - - sbinptr bin = smallbin_at(m, i); + sbinptr bin = smallbin_at(m,i); bin->fd = bin->bk = bin; - } - } #if PROCEED_ON_ERROR /* default corruption action */ static void reset_on_error(mstate m) { - int i; ++malloc_corruption_error_count; /* Reinitialize fields to forget about all memory */ @@ -4344,78 +3984,67 @@ static void reset_on_error(mstate m) { for (i = 0; i < NTREEBINS; ++i) *treebin_at(m, i) = 0; init_bins(m); - } - -#endif /* PROCEED_ON_ERROR */ +#endif /* PROCEED_ON_ERROR */ /* Allocate chunk and prepend remainder with chunk in successor base. */ -static void *prepend_alloc(mstate m, char *newbase, char *oldbase, size_t nb) { - +static void* prepend_alloc(mstate m, char* newbase, char* oldbase, + size_t nb) { mchunkptr p = align_as_chunk(newbase); mchunkptr oldfirst = align_as_chunk(oldbase); - size_t psize = (char *)oldfirst - (char *)p; + size_t psize = (char*)oldfirst - (char*)p; mchunkptr q = chunk_plus_offset(p, nb); - size_t qsize = psize - nb; + size_t qsize = psize - nb; set_size_and_pinuse_of_inuse_chunk(m, p, nb); - assert((char *)oldfirst > (char *)q); + assert((char*)oldfirst > (char*)q); assert(pinuse(oldfirst)); assert(qsize >= MIN_CHUNK_SIZE); /* consolidate remainder with first chunk of old base */ if (oldfirst == m->top) { - size_t tsize = m->topsize += qsize; m->top = q; q->head = tsize | PINUSE_BIT; check_top_chunk(m, q); - - } else if (oldfirst == m->dv) { - + } + else if (oldfirst == m->dv) { size_t dsize = m->dvsize += qsize; m->dv = q; set_size_and_pinuse_of_free_chunk(q, dsize); - - } else { - + } + else { if (!is_inuse(oldfirst)) { - size_t nsize = chunksize(oldfirst); unlink_chunk(m, oldfirst, nsize); oldfirst = chunk_plus_offset(oldfirst, nsize); qsize += nsize; - } - set_free_with_pinuse(q, qsize, oldfirst); insert_chunk(m, q, qsize); check_free_chunk(m, q); - } check_malloced_chunk(m, chunk2mem(p), nb); return chunk2mem(p); - } /* Add a segment to hold a new noncontiguous region */ -static void add_segment(mstate m, char *tbase, size_t tsize, flag_t mmapped) { - +static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { /* Determine locations and sizes of segment, fenceposts, old top */ - char * old_top = (char *)m->top; + char* old_top = (char*)m->top; msegmentptr oldsp = segment_holding(m, old_top); - char * old_end = oldsp->base + oldsp->size; - size_t ssize = pad_request(sizeof(struct malloc_segment)); - char * rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - size_t offset = align_offset(chunk2mem(rawsp)); - char * asp = rawsp + offset; - char * csp = (asp < (old_top + MIN_CHUNK_SIZE)) ? old_top : asp; - mchunkptr sp = (mchunkptr)csp; + char* old_end = oldsp->base + oldsp->size; + size_t ssize = pad_request(sizeof(struct malloc_segment)); + char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + size_t offset = align_offset(chunk2mem(rawsp)); + char* asp = rawsp + offset; + char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; + mchunkptr sp = (mchunkptr)csp; msegmentptr ss = (msegmentptr)(chunk2mem(sp)); - mchunkptr tnext = chunk_plus_offset(sp, ssize); - mchunkptr p = tnext; - int nfences = 0; + mchunkptr tnext = chunk_plus_offset(sp, ssize); + mchunkptr p = tnext; + int nfences = 0; /* reset top to new space */ init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); @@ -4423,7 +4052,7 @@ static void add_segment(mstate m, char *tbase, size_t tsize, flag_t mmapped) { /* Set up segment record */ assert(is_aligned(ss)); set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); - *ss = m->seg; /* Push current record */ + *ss = m->seg; /* Push current record */ m->seg.base = tbase; m->seg.size = tsize; m->seg.sflags = mmapped; @@ -4431,61 +4060,53 @@ static void add_segment(mstate m, char *tbase, size_t tsize, flag_t mmapped) { /* Insert trailing fenceposts */ for (;;) { - mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); p->head = FENCEPOST_HEAD; ++nfences; - if ((char *)(&(nextp->head)) < old_end) + if ((char*)(&(nextp->head)) < old_end) p = nextp; else break; - } - assert(nfences >= 2); /* Insert the rest of old top into a bin as an ordinary free chunk */ if (csp != old_top) { - mchunkptr q = (mchunkptr)old_top; - size_t psize = csp - old_top; + size_t psize = csp - old_top; mchunkptr tn = chunk_plus_offset(q, psize); set_free_with_pinuse(q, psize, tn); insert_chunk(m, q, psize); - } check_top_chunk(m, m->top); - } /* -------------------------- System allocation -------------------------- */ /* Get memory from system using MORECORE or MMAP */ -static void *sys_alloc(mstate m, size_t nb) { - - char * tbase = CMFAIL; +static void* sys_alloc(mstate m, size_t nb) { + char* tbase = CMFAIL; size_t tsize = 0; flag_t mmap_flag = 0; - size_t asize; /* allocation size */ + size_t asize; /* allocation size */ ensure_initialization(); /* Directly map large chunks, but only if already initialized */ if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) { - - void *mem = mmap_alloc(m, nb); - if (mem != 0) return mem; - + void* mem = mmap_alloc(m, nb); + if (mem != 0) + return mem; } asize = granularity_align(nb + SYS_ALLOC_PADDING); - if (asize <= nb) return 0; /* wraparound */ + if (asize <= nb) + return 0; /* wraparound */ if (m->footprint_limit != 0) { - size_t fp = m->footprint + asize; - if (fp <= m->footprint || fp > m->footprint_limit) return 0; - + if (fp <= m->footprint || fp > m->footprint_limit) + return 0; } /* @@ -4511,119 +4132,91 @@ static void *sys_alloc(mstate m, size_t nb) { */ if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { - - char * br = CMFAIL; - size_t ssize = asize; /* sbrk call size */ - msegmentptr ss = (m->top == 0) ? 0 : segment_holding(m, (char *)m->top); + char* br = CMFAIL; + size_t ssize = asize; /* sbrk call size */ + msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); ACQUIRE_MALLOC_GLOBAL_LOCK(); - if (ss == 0) { /* First time through or recovery */ - char *base = (char *)CALL_MORECORE(0); + if (ss == 0) { /* First time through or recovery */ + char* base = (char*)CALL_MORECORE(0); if (base != CMFAIL) { - size_t fp; /* Adjust to end on a page boundary */ if (!is_page_aligned(base)) ssize += (page_align((size_t)base) - (size_t)base); - fp = m->footprint + ssize; /* recheck limits */ + fp = m->footprint + ssize; /* recheck limits */ if (ssize > nb && ssize < HALF_MAX_SIZE_T && (m->footprint_limit == 0 || (fp > m->footprint && fp <= m->footprint_limit)) && - (br = (char *)(CALL_MORECORE(ssize))) == base) { - + (br = (char*)(CALL_MORECORE(ssize))) == base) { tbase = base; tsize = ssize; - } - } - - } else { - + } + else { /* Subtract out existing available top space from MORECORE request. */ ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING); /* Use mem here only if it did continuously extend old space */ if (ssize < HALF_MAX_SIZE_T && - (br = (char *)(CALL_MORECORE(ssize))) == ss->base + ss->size) { - + (br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) { tbase = br; tsize = ssize; - } - } - if (tbase == CMFAIL) { /* Cope with partial failure */ - if (br != CMFAIL) { /* Try to use/extend the space we did get */ - if (ssize < HALF_MAX_SIZE_T && ssize < nb + SYS_ALLOC_PADDING) { - + if (tbase == CMFAIL) { /* Cope with partial failure */ + if (br != CMFAIL) { /* Try to use/extend the space we did get */ + if (ssize < HALF_MAX_SIZE_T && + ssize < nb + SYS_ALLOC_PADDING) { size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize); if (esize < HALF_MAX_SIZE_T) { - - char *end = (char *)CALL_MORECORE(esize); + char* end = (char*)CALL_MORECORE(esize); if (end != CMFAIL) ssize += esize; - else { /* Can't use; try to release */ - (void)CALL_MORECORE(-ssize); + else { /* Can't use; try to release */ + (void) CALL_MORECORE(-ssize); br = CMFAIL; - } - } - } - } - - if (br != CMFAIL) { /* Use the space we did get */ + if (br != CMFAIL) { /* Use the space we did get */ tbase = br; tsize = ssize; - - } else - - disable_contiguous(m); /* Don't try contiguous path in the future */ - + } + else + disable_contiguous(m); /* Don't try contiguous path in the future */ } RELEASE_MALLOC_GLOBAL_LOCK(); - } - if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ - char *mp = (char *)(CALL_MMAP(asize)); + if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ + char* mp = (char*)(CALL_MMAP(asize)); if (mp != CMFAIL) { - tbase = mp; tsize = asize; mmap_flag = USE_MMAP_BIT; - } - } - if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ + if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ if (asize < HALF_MAX_SIZE_T) { - - char *br = CMFAIL; - char *end = CMFAIL; + char* br = CMFAIL; + char* end = CMFAIL; ACQUIRE_MALLOC_GLOBAL_LOCK(); - br = (char *)(CALL_MORECORE(asize)); - end = (char *)(CALL_MORECORE(0)); + br = (char*)(CALL_MORECORE(asize)); + end = (char*)(CALL_MORECORE(0)); RELEASE_MALLOC_GLOBAL_LOCK(); if (br != CMFAIL && end != CMFAIL && br < end) { - size_t ssize = end - br; if (ssize > nb + TOP_FOOT_SIZE) { - tbase = br; tsize = ssize; - } - } - } - } if (tbase != CMFAIL) { @@ -4631,8 +4224,9 @@ static void *sys_alloc(mstate m, size_t nb) { if ((m->footprint += tsize) > m->max_footprint) m->max_footprint = m->footprint; - if (!is_initialized(m)) { /* first-time initialization */ - if (m->least_addr == 0 || tbase < m->least_addr) m->least_addr = tbase; + if (!is_initialized(m)) { /* first-time initialization */ + if (m->least_addr == 0 || tbase < m->least_addr) + m->least_addr = tbase; m->seg.base = tbase; m->seg.size = tsize; m->seg.sflags = mmap_flag; @@ -4645,52 +4239,46 @@ static void *sys_alloc(mstate m, size_t nb) { else #endif { - /* Offset top by embedded malloc_state */ mchunkptr mn = next_chunk(mem2chunk(m)); - init_top(m, mn, (size_t)((tbase + tsize) - (char *)mn) - TOP_FOOT_SIZE); - + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); } - } else { - /* Try to merge with an existing segment */ msegmentptr sp = &m->seg; /* Only consider most recent segment if traversal suppressed */ while (sp != 0 && tbase != sp->base + sp->size) sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; - if (sp != 0 && !is_extern_segment(sp) && + if (sp != 0 && + !is_extern_segment(sp) && (sp->sflags & USE_MMAP_BIT) == mmap_flag && - segment_holds(sp, m->top)) { /* append */ + segment_holds(sp, m->top)) { /* append */ sp->size += tsize; init_top(m, m->top, m->topsize + tsize); - - } else { - - if (tbase < m->least_addr) m->least_addr = tbase; + } + else { + if (tbase < m->least_addr) + m->least_addr = tbase; sp = &m->seg; while (sp != 0 && sp->base != tbase + tsize) sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; - if (sp != 0 && !is_extern_segment(sp) && + if (sp != 0 && + !is_extern_segment(sp) && (sp->sflags & USE_MMAP_BIT) == mmap_flag) { - - char *oldbase = sp->base; + char* oldbase = sp->base; sp->base = tbase; sp->size += tsize; return prepend_alloc(m, tbase, oldbase, nb); - - } else - + } + else add_segment(m, tbase, tsize, mmap_flag); - } - } - if (nb < m->topsize) { /* Allocate from new or extended top space */ - size_t rsize = m->topsize -= nb; + if (nb < m->topsize) { /* Allocate from new or extended top space */ + size_t rsize = m->topsize -= nb; mchunkptr p = m->top; mchunkptr r = m->top = chunk_plus_offset(p, nb); r->head = rsize | PINUSE_BIT; @@ -4698,421 +4286,313 @@ static void *sys_alloc(mstate m, size_t nb) { check_top_chunk(m, m->top); check_malloced_chunk(m, chunk2mem(p), nb); return chunk2mem(p); - } - } MALLOC_FAILURE_ACTION; return 0; - } /* ----------------------- system deallocation -------------------------- */ /* Unmap and unlink any mmapped segments that don't contain used chunks */ static size_t release_unused_segments(mstate m) { - - size_t released = 0; - int nsegs = 0; + size_t released = 0; + int nsegs = 0; msegmentptr pred = &m->seg; msegmentptr sp = pred->next; while (sp != 0) { - - char * base = sp->base; - size_t size = sp->size; + char* base = sp->base; + size_t size = sp->size; msegmentptr next = sp->next; ++nsegs; if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { - mchunkptr p = align_as_chunk(base); - size_t psize = chunksize(p); + size_t psize = chunksize(p); /* Can unmap if first chunk holds entire segment and not pinned */ - if (!is_inuse(p) && (char *)p + psize >= base + size - TOP_FOOT_SIZE) { - + if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { tchunkptr tp = (tchunkptr)p; - assert(segment_holds(sp, (char *)sp)); + assert(segment_holds(sp, (char*)sp)); if (p == m->dv) { - m->dv = 0; m->dvsize = 0; - - } else { - + } + else { unlink_large_chunk(m, tp); - } - if (CALL_MUNMAP(base, size) == 0) { - released += size; m->footprint -= size; /* unlink obsoleted record */ sp = pred; sp->next = next; - - } else { /* back out if cannot unmap */ - + } + else { /* back out if cannot unmap */ insert_large_chunk(m, tp, psize); - } - } - } - - if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */ + if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */ break; pred = sp; sp = next; - } - /* Reset check counter */ - m->release_checks = (((size_t)nsegs > (size_t)MAX_RELEASE_CHECK_RATE) - ? (size_t)nsegs - : (size_t)MAX_RELEASE_CHECK_RATE); + m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)? + (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE); return released; - } static int sys_trim(mstate m, size_t pad) { - size_t released = 0; ensure_initialization(); if (pad < MAX_REQUEST && is_initialized(m)) { - - pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ if (m->topsize > pad) { - /* Shrink top space in granularity-size units, keeping at least one */ size_t unit = mparams.granularity; - size_t extra = - ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - SIZE_T_ONE) * unit; - msegmentptr sp = segment_holding(m, (char *)m->top); + size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - + SIZE_T_ONE) * unit; + msegmentptr sp = segment_holding(m, (char*)m->top); if (!is_extern_segment(sp)) { - if (is_mmapped_segment(sp)) { - - if (HAVE_MMAP && sp->size >= extra && - !has_segment_link(m, sp)) { /* can't shrink if pinned */ + if (HAVE_MMAP && + sp->size >= extra && + !has_segment_link(m, sp)) { /* can't shrink if pinned */ size_t newsize = sp->size - extra; - (void)newsize; /* placate people compiling -Wunused-variable */ + (void)newsize; /* placate people compiling -Wunused-variable */ /* Prefer mremap, fall back to munmap */ if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { - released = extra; - } - } - - } else if (HAVE_MORECORE) { - - if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ + } + else if (HAVE_MORECORE) { + if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; ACQUIRE_MALLOC_GLOBAL_LOCK(); { - /* Make sure end of memory is where we last set it. */ - char *old_br = (char *)(CALL_MORECORE(0)); + char* old_br = (char*)(CALL_MORECORE(0)); if (old_br == sp->base + sp->size) { - - char *rel_br = (char *)(CALL_MORECORE(-extra)); - char *new_br = (char *)(CALL_MORECORE(0)); + char* rel_br = (char*)(CALL_MORECORE(-extra)); + char* new_br = (char*)(CALL_MORECORE(0)); if (rel_br != CMFAIL && new_br < old_br) released = old_br - new_br; - } - } - RELEASE_MALLOC_GLOBAL_LOCK(); - } - } if (released != 0) { - sp->size -= released; m->footprint -= released; init_top(m, m->top, m->topsize - released); check_top_chunk(m, m->top); - } - } /* Unmap any unused mmapped segments */ - if (HAVE_MMAP) released += release_unused_segments(m); + if (HAVE_MMAP) + released += release_unused_segments(m); /* On failure, disable autotrim to avoid repeated failed future calls */ - if (released == 0 && m->topsize > m->trim_check) m->trim_check = MAX_SIZE_T; - + if (released == 0 && m->topsize > m->trim_check) + m->trim_check = MAX_SIZE_T; } - return (released != 0) ? 1 : 0; - + return (released != 0)? 1 : 0; } /* Consolidate and bin a chunk. Differs from exported versions of free mainly in that the chunk need not be marked as inuse. */ static void dispose_chunk(mstate m, mchunkptr p, size_t psize) { - mchunkptr next = chunk_plus_offset(p, psize); if (!pinuse(p)) { - mchunkptr prev; - size_t prevsize = p->prev_foot; + size_t prevsize = p->prev_foot; if (is_mmapped(p)) { - psize += prevsize + MMAP_FOOT_PAD; - if (CALL_MUNMAP((char *)p - prevsize, psize) == 0) m->footprint -= psize; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + m->footprint -= psize; return; - } - prev = chunk_minus_offset(p, prevsize); psize += prevsize; p = prev; - if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */ + if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */ if (p != m->dv) { - unlink_chunk(m, p, prevsize); - - } else if ((next->head & INUSE_BITS) == INUSE_BITS) { - + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { m->dvsize = psize; set_free_with_pinuse(p, psize, next); return; - } - - } else { - + } + else { CORRUPTION_ERROR_ACTION(m); return; - } - } - if (RTCHECK(ok_address(m, next))) { - - if (!cinuse(next)) { /* consolidate forward */ + if (!cinuse(next)) { /* consolidate forward */ if (next == m->top) { - size_t tsize = m->topsize += psize; m->top = p; p->head = tsize | PINUSE_BIT; if (p == m->dv) { - m->dv = 0; m->dvsize = 0; - } - return; - - } else if (next == m->dv) { - + } + else if (next == m->dv) { size_t dsize = m->dvsize += psize; m->dv = p; set_size_and_pinuse_of_free_chunk(p, dsize); return; - - } else { - + } + else { size_t nsize = chunksize(next); psize += nsize; unlink_chunk(m, next, nsize); set_size_and_pinuse_of_free_chunk(p, psize); if (p == m->dv) { - m->dvsize = psize; return; - } - } - - } else { - + } + else { set_free_with_pinuse(p, psize, next); - } - insert_chunk(m, p, psize); - - } else { - + } + else { CORRUPTION_ERROR_ACTION(m); - } - } /* ---------------------------- malloc --------------------------- */ /* allocate a large request from the best fitting chunk in a treebin */ -static void *tmalloc_large(mstate m, size_t nb) { - +static void* tmalloc_large(mstate m, size_t nb) { tchunkptr v = 0; - size_t rsize = -nb; /* Unsigned negation */ + size_t rsize = -nb; /* Unsigned negation */ tchunkptr t; - bindex_t idx; + bindex_t idx; compute_tree_index(nb, idx); if ((t = *treebin_at(m, idx)) != 0) { - /* Traverse tree for this bin looking for node with size == nb */ - size_t sizebits = nb << leftshift_for_tree_index(idx); - tchunkptr rst = 0; /* The deepest untaken right subtree */ + size_t sizebits = nb << leftshift_for_tree_index(idx); + tchunkptr rst = 0; /* The deepest untaken right subtree */ for (;;) { - tchunkptr rt; - size_t trem = chunksize(t) - nb; + size_t trem = chunksize(t) - nb; if (trem < rsize) { - v = t; - if ((rsize = trem) == 0) break; - + if ((rsize = trem) == 0) + break; } - rt = t->child[1]; - t = t->child[(sizebits >> (SIZE_T_BITSIZE - SIZE_T_ONE)) & 1]; - if (rt != 0 && rt != t) rst = rt; + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + if (rt != 0 && rt != t) + rst = rt; if (t == 0) { - - t = rst; /* set t to least subtree holding sizes > nb */ + t = rst; /* set t to least subtree holding sizes > nb */ break; - } - sizebits <<= 1; - } - } - - if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ + if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; if (leftbits != 0) { - bindex_t i; binmap_t leastbit = least_bit(leftbits); compute_bit2idx(leastbit, i); t = *treebin_at(m, i); - } - } - while (t != 0) { /* find smallest of tree or subtree */ + while (t != 0) { /* find smallest of tree or subtree */ size_t trem = chunksize(t) - nb; if (trem < rsize) { - rsize = trem; v = t; - } - t = leftmost_child(t); - } /* If dv is a better fit, return 0 so malloc will use it */ if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { - - if (RTCHECK(ok_address(m, v))) { /* split */ + if (RTCHECK(ok_address(m, v))) { /* split */ mchunkptr r = chunk_plus_offset(v, nb); assert(chunksize(v) == rsize + nb); if (RTCHECK(ok_next(v, r))) { - unlink_large_chunk(m, v); if (rsize < MIN_CHUNK_SIZE) set_inuse_and_pinuse(m, v, (rsize + nb)); else { - set_size_and_pinuse_of_inuse_chunk(m, v, nb); set_size_and_pinuse_of_free_chunk(r, rsize); insert_chunk(m, r, rsize); - } - return chunk2mem(v); - } - } - CORRUPTION_ERROR_ACTION(m); - } - return 0; - } /* allocate a small request from the best fitting chunk in a treebin */ -static void *tmalloc_small(mstate m, size_t nb) { - +static void* tmalloc_small(mstate m, size_t nb) { tchunkptr t, v; - size_t rsize; - bindex_t i; - binmap_t leastbit = least_bit(m->treemap); + size_t rsize; + bindex_t i; + binmap_t leastbit = least_bit(m->treemap); compute_bit2idx(leastbit, i); v = t = *treebin_at(m, i); rsize = chunksize(t) - nb; while ((t = leftmost_child(t)) != 0) { - size_t trem = chunksize(t) - nb; if (trem < rsize) { - rsize = trem; v = t; - } - } if (RTCHECK(ok_address(m, v))) { - mchunkptr r = chunk_plus_offset(v, nb); assert(chunksize(v) == rsize + nb); if (RTCHECK(ok_next(v, r))) { - unlink_large_chunk(m, v); if (rsize < MIN_CHUNK_SIZE) set_inuse_and_pinuse(m, v, (rsize + nb)); else { - set_size_and_pinuse_of_inuse_chunk(m, v, nb); set_size_and_pinuse_of_free_chunk(r, rsize); replace_dv(m, r, rsize); - } - return chunk2mem(v); - } - } CORRUPTION_ERROR_ACTION(m); return 0; - } #if !ONLY_MSPACES -void *dlmalloc(size_t bytes) { - +void* dlmalloc(size_t bytes) { /* Basic algorithm: If a small request (< 256 bytes minus per-chunk overhead): @@ -5136,25 +4616,23 @@ void *dlmalloc(size_t bytes) { The ugly goto's here ensure that postaction occurs along all paths. */ - #if USE_LOCKS - ensure_initialization(); /* initialize in sys_alloc if not using locks */ - #endif +#if USE_LOCKS + ensure_initialization(); /* initialize in sys_alloc if not using locks */ +#endif if (!PREACTION(gm)) { - - void * mem; + void* mem; size_t nb; if (bytes <= MAX_SMALL_REQUEST) { - bindex_t idx; binmap_t smallbits; - nb = (bytes < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(bytes); + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); idx = small_index(nb); smallbits = gm->smallmap >> idx; - if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ mchunkptr b, p; - idx += ~smallbits & 1; /* Uses next bin if idx empty */ + idx += ~smallbits & 1; /* Uses next bin if idx empty */ b = smallbin_at(gm, idx); p = b->fd; assert(chunksize(p) == small_index2size(idx)); @@ -5163,17 +4641,15 @@ void *dlmalloc(size_t bytes) { mem = chunk2mem(p); check_malloced_chunk(gm, mem, nb); goto postaction; - } else if (nb > gm->dvsize) { - - if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ mchunkptr b, p, r; - size_t rsize; - bindex_t i; - binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); - binmap_t leastbit = least_bit(leftbits); + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); compute_bit2idx(leastbit, i); b = smallbin_at(gm, i); p = b->fd; @@ -5184,71 +4660,54 @@ void *dlmalloc(size_t bytes) { if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) set_inuse_and_pinuse(gm, p, small_index2size(i)); else { - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); r = chunk_plus_offset(p, nb); set_size_and_pinuse_of_free_chunk(r, rsize); replace_dv(gm, r, rsize); - } - mem = chunk2mem(p); check_malloced_chunk(gm, mem, nb); goto postaction; - } else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { - check_malloced_chunk(gm, mem, nb); goto postaction; - } - } - - } else if (bytes >= MAX_REQUEST) - + } + else if (bytes >= MAX_REQUEST) nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ else { - nb = pad_request(bytes); if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { - check_malloced_chunk(gm, mem, nb); goto postaction; - } - } if (nb <= gm->dvsize) { - - size_t rsize = gm->dvsize - nb; + size_t rsize = gm->dvsize - nb; mchunkptr p = gm->dv; - if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ mchunkptr r = gm->dv = chunk_plus_offset(p, nb); gm->dvsize = rsize; set_size_and_pinuse_of_free_chunk(r, rsize); set_size_and_pinuse_of_inuse_chunk(gm, p, nb); - - } else { /* exhaust dv */ - + } + else { /* exhaust dv */ size_t dvs = gm->dvsize; gm->dvsize = 0; gm->dv = 0; set_inuse_and_pinuse(gm, p, dvs); - } - mem = chunk2mem(p); check_malloced_chunk(gm, mem, nb); goto postaction; - } - else if (nb < gm->topsize) { /* Split top */ - size_t rsize = gm->topsize -= nb; + else if (nb < gm->topsize) { /* Split top */ + size_t rsize = gm->topsize -= nb; mchunkptr p = gm->top; mchunkptr r = gm->top = chunk_plus_offset(p, nb); r->head = rsize | PINUSE_BIT; @@ -5257,7 +4716,6 @@ void *dlmalloc(size_t bytes) { check_top_chunk(gm, gm->top); check_malloced_chunk(gm, mem, nb); goto postaction; - } mem = sys_alloc(gm, nb); @@ -5265,17 +4723,14 @@ void *dlmalloc(size_t bytes) { postaction: POSTACTION(gm); return mem; - } return 0; - } /* ---------------------------- free --------------------------- */ -void dlfree(void *mem) { - +void dlfree(void* mem) { /* Consolidate freed chunks with preceeding or succeeding bordering free chunks, if they exist, and then place in a bin. Intermixed @@ -5283,216 +4738,164 @@ void dlfree(void *mem) { */ if (mem != 0) { - - mchunkptr p = mem2chunk(mem); - #if FOOTERS + mchunkptr p = mem2chunk(mem); +#if FOOTERS mstate fm = get_mstate_for(p); if (!ok_magic(fm)) { - USAGE_ERROR_ACTION(fm, p); return; - } - - #else /* FOOTERS */ - #define fm gm - #endif /* FOOTERS */ +#else /* FOOTERS */ +#define fm gm +#endif /* FOOTERS */ if (!PREACTION(fm)) { - check_inuse_chunk(fm, p); if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) { - - size_t psize = chunksize(p); + size_t psize = chunksize(p); mchunkptr next = chunk_plus_offset(p, psize); if (!pinuse(p)) { - size_t prevsize = p->prev_foot; if (is_mmapped(p)) { - psize += prevsize + MMAP_FOOT_PAD; - if (CALL_MUNMAP((char *)p - prevsize, psize) == 0) + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) fm->footprint -= psize; goto postaction; - - } else { - + } + else { mchunkptr prev = chunk_minus_offset(p, prevsize); psize += prevsize; p = prev; - if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ if (p != fm->dv) { - unlink_chunk(fm, p, prevsize); - - } else if ((next->head & INUSE_BITS) == INUSE_BITS) { - + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { fm->dvsize = psize; set_free_with_pinuse(p, psize, next); goto postaction; - } - - } else - + } + else goto erroraction; - } - } if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { - - if (!cinuse(next)) { /* consolidate forward */ + if (!cinuse(next)) { /* consolidate forward */ if (next == fm->top) { - size_t tsize = fm->topsize += psize; fm->top = p; p->head = tsize | PINUSE_BIT; if (p == fm->dv) { - fm->dv = 0; fm->dvsize = 0; - } - - if (should_trim(fm, tsize)) sys_trim(fm, 0); + if (should_trim(fm, tsize)) + sys_trim(fm, 0); goto postaction; - - } else if (next == fm->dv) { - + } + else if (next == fm->dv) { size_t dsize = fm->dvsize += psize; fm->dv = p; set_size_and_pinuse_of_free_chunk(p, dsize); goto postaction; - - } else { - + } + else { size_t nsize = chunksize(next); psize += nsize; unlink_chunk(fm, next, nsize); set_size_and_pinuse_of_free_chunk(p, psize); if (p == fm->dv) { - fm->dvsize = psize; goto postaction; - } - } - - } else - + } + else set_free_with_pinuse(p, psize, next); if (is_small(psize)) { - insert_small_chunk(fm, p, psize); check_free_chunk(fm, p); - - } else { - + } + else { tchunkptr tp = (tchunkptr)p; insert_large_chunk(fm, tp, psize); check_free_chunk(fm, p); - if (--fm->release_checks == 0) release_unused_segments(fm); - + if (--fm->release_checks == 0) + release_unused_segments(fm); } - goto postaction; - } - } - erroraction: USAGE_ERROR_ACTION(fm, p); postaction: POSTACTION(fm); - } - } - - #if !FOOTERS - #undef fm - #endif /* FOOTERS */ - +#if !FOOTERS +#undef fm +#endif /* FOOTERS */ } -void *dlcalloc(size_t n_elements, size_t elem_size) { - - void * mem; +void* dlcalloc(size_t n_elements, size_t elem_size) { + void* mem; size_t req = 0; if (n_elements != 0) { - req = n_elements * elem_size; if (((n_elements | elem_size) & ~(size_t)0xffff) && (req / n_elements != elem_size)) - req = MAX_SIZE_T; /* force downstream failure on overflow */ - + req = MAX_SIZE_T; /* force downstream failure on overflow */ } - mem = dlmalloc(req); if (mem != 0 && calloc_must_clear(mem2chunk(mem))) __builtin_memset(mem, 0, req); return mem; - } -#endif /* !ONLY_MSPACES */ +#endif /* !ONLY_MSPACES */ /* ------------ Internal support for realloc, memalign, etc -------------- */ /* Try to realloc; only in-place unless can_move true */ static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb, int can_move) { - mchunkptr newp = 0; - size_t oldsize = chunksize(p); + size_t oldsize = chunksize(p); mchunkptr next = chunk_plus_offset(p, oldsize); - if (RTCHECK(ok_address(m, p) && ok_inuse(p) && ok_next(p, next) && - ok_pinuse(next))) { - + if (RTCHECK(ok_address(m, p) && ok_inuse(p) && + ok_next(p, next) && ok_pinuse(next))) { if (is_mmapped(p)) { - newp = mmap_resize(m, p, nb, can_move); - - } else if (oldsize >= nb) { /* already big enough */ - + } + else if (oldsize >= nb) { /* already big enough */ size_t rsize = oldsize - nb; - if (rsize >= MIN_CHUNK_SIZE) { /* split off remainder */ + if (rsize >= MIN_CHUNK_SIZE) { /* split off remainder */ mchunkptr r = chunk_plus_offset(p, nb); set_inuse(m, p, nb); set_inuse(m, r, rsize); dispose_chunk(m, r, rsize); - } - newp = p; - - } else if (next == m->top) { /* extend into top */ - + } + else if (next == m->top) { /* extend into top */ if (oldsize + m->topsize > nb) { - - size_t newsize = oldsize + m->topsize; - size_t newtopsize = newsize - nb; + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; mchunkptr newtop = chunk_plus_offset(p, nb); set_inuse(m, p, nb); - newtop->head = newtopsize | PINUSE_BIT; + newtop->head = newtopsize |PINUSE_BIT; m->top = newtop; m->topsize = newtopsize; newp = p; - } - - } else if (next == m->dv) { /* extend into dv */ - + } + else if (next == m->dv) { /* extend into dv */ size_t dvs = m->dvsize; if (oldsize + dvs >= nb) { - size_t dsize = oldsize + dvs - nb; if (dsize >= MIN_CHUNK_SIZE) { - mchunkptr r = chunk_plus_offset(p, nb); mchunkptr n = chunk_plus_offset(r, dsize); set_inuse(m, p, nb); @@ -5500,87 +4903,64 @@ static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb, clear_pinuse(n); m->dvsize = dsize; m->dv = r; - - } else { /* exhaust dv */ - + } + else { /* exhaust dv */ size_t newsize = oldsize + dvs; set_inuse(m, p, newsize); m->dvsize = 0; m->dv = 0; - } - newp = p; - } - - } else if (!cinuse(next)) { /* extend into next free chunk */ - + } + else if (!cinuse(next)) { /* extend into next free chunk */ size_t nextsize = chunksize(next); if (oldsize + nextsize >= nb) { - size_t rsize = oldsize + nextsize - nb; unlink_chunk(m, next, nextsize); if (rsize < MIN_CHUNK_SIZE) { - size_t newsize = oldsize + nextsize; set_inuse(m, p, newsize); - - } else { - + } + else { mchunkptr r = chunk_plus_offset(p, nb); set_inuse(m, p, nb); set_inuse(m, r, rsize); dispose_chunk(m, r, rsize); - } - newp = p; - } - } - - } else { - + } + else { USAGE_ERROR_ACTION(m, chunk2mem(p)); - } - return newp; - } -static void *internal_memalign(mstate m, size_t alignment, size_t bytes) { - - void *mem = 0; - if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ +static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { + void* mem = 0; + if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ alignment = MIN_CHUNK_SIZE; - if ((alignment & (alignment - SIZE_T_ONE)) != 0) { /* Ensure a power of 2 */ + if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ size_t a = MALLOC_ALIGNMENT << 1; - while (a < alignment) - a <<= 1; + while (a < alignment) a <<= 1; alignment = a; - } - if (bytes >= MAX_REQUEST - alignment) { - - if (m != 0) { /* Test isn't needed but avoids compiler warning */ + if (m != 0) { /* Test isn't needed but avoids compiler warning */ MALLOC_FAILURE_ACTION; - } - - } else { - + } + else { size_t nb = request2size(bytes); size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; mem = internal_malloc(m, req); if (mem != 0) { - mchunkptr p = mem2chunk(mem); - if (PREACTION(m)) return 0; - if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */ + if (PREACTION(m)) + return 0; + if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */ /* Find an aligned spot inside chunk. Since we need to give back leading space in a chunk of at least MIN_CHUNK_SIZE, if @@ -5589,59 +4969,47 @@ static void *internal_memalign(mstate m, size_t alignment, size_t bytes) { We've allocated enough total room so that this is always possible. */ - char * br = (char *)mem2chunk((size_t)( - ((size_t)((char *)mem + alignment - SIZE_T_ONE)) & -alignment)); - char * pos = ((size_t)(br - (char *)(p)) >= MIN_CHUNK_SIZE) - ? br - : br + alignment; + char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment - + SIZE_T_ONE)) & + -alignment)); + char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? + br : br+alignment; mchunkptr newp = (mchunkptr)pos; - size_t leadsize = pos - (char *)(p); - size_t newsize = chunksize(p) - leadsize; + size_t leadsize = pos - (char*)(p); + size_t newsize = chunksize(p) - leadsize; - if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ + if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ newp->prev_foot = p->prev_foot + leadsize; newp->head = newsize; - - } else { /* Otherwise, give back leader, use the rest */ - + } + else { /* Otherwise, give back leader, use the rest */ set_inuse(m, newp, newsize); set_inuse(m, p, leadsize); dispose_chunk(m, p, leadsize); - } - p = newp; - } /* Give back spare room at the end */ if (!is_mmapped(p)) { - size_t size = chunksize(p); if (size > nb + MIN_CHUNK_SIZE) { - - size_t remainder_size = size - nb; + size_t remainder_size = size - nb; mchunkptr remainder = chunk_plus_offset(p, nb); set_inuse(m, p, nb); set_inuse(m, remainder, remainder_size); dispose_chunk(m, remainder, remainder_size); - } - } mem = chunk2mem(p); - assert(chunksize(p) >= nb); + assert (chunksize(p) >= nb); assert(((size_t)mem & (alignment - 1)) == 0); check_inuse_chunk(m, p); POSTACTION(m); - } - } - return mem; - } /* @@ -5651,50 +5019,50 @@ static void *internal_memalign(mstate m, size_t alignment, size_t bytes) { bit 0 set if all elements are same size (using sizes[0]) bit 1 set if elements should be zeroed */ -static void **ialloc(mstate m, size_t n_elements, size_t *sizes, int opts, - void *chunks[]) { - - size_t element_size; /* chunksize of each element, if all same */ - size_t contents_size; /* total size of elements */ - size_t array_size; /* request size of pointer array */ - void * mem; /* malloced aggregate space */ - mchunkptr p; /* corresponding chunk */ - size_t remainder_size; /* remaining bytes while splitting */ - void ** marray; /* either "chunks" or malloced ptr array */ - mchunkptr array_chunk; /* chunk for malloced ptr array */ - flag_t was_enabled; /* to disable mmap */ +static void** ialloc(mstate m, + size_t n_elements, + size_t* sizes, + int opts, + void* chunks[]) { + + size_t element_size; /* chunksize of each element, if all same */ + size_t contents_size; /* total size of elements */ + size_t array_size; /* request size of pointer array */ + void* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + void** marray; /* either "chunks" or malloced ptr array */ + mchunkptr array_chunk; /* chunk for malloced ptr array */ + flag_t was_enabled; /* to disable mmap */ size_t size; size_t i; ensure_initialization(); /* compute array length, if needed */ if (chunks != 0) { - - if (n_elements == 0) return chunks; /* nothing to do */ + if (n_elements == 0) + return chunks; /* nothing to do */ marray = chunks; array_size = 0; - - } else { - + } + else { /* if empty req, must still return chunk representing empty array */ - if (n_elements == 0) return (void **)internal_malloc(m, 0); + if (n_elements == 0) + return (void**)internal_malloc(m, 0); marray = 0; - array_size = request2size(n_elements * (sizeof(void *))); - + array_size = request2size(n_elements * (sizeof(void*))); } /* compute total element size */ - if (opts & 0x1) { /* all-same-size */ + if (opts & 0x1) { /* all-same-size */ element_size = request2size(*sizes); contents_size = n_elements * element_size; - - } else { /* add up all the sizes */ - + } + else { /* add up all the sizes */ element_size = 0; contents_size = 0; for (i = 0; i != n_elements; ++i) contents_size += request2size(sizes[i]); - } size = contents_size + array_size; @@ -5707,8 +5075,10 @@ static void **ialloc(mstate m, size_t n_elements, size_t *sizes, int opts, was_enabled = use_mmap(m); disable_mmap(m); mem = internal_malloc(m, size - CHUNK_OVERHEAD); - if (was_enabled) enable_mmap(m); - if (mem == 0) return 0; + if (was_enabled) + enable_mmap(m); + if (mem == 0) + return 0; if (PREACTION(m)) return 0; p = mem2chunk(mem); @@ -5716,30 +5086,24 @@ static void **ialloc(mstate m, size_t n_elements, size_t *sizes, int opts, assert(!is_mmapped(p)); - if (opts & 0x2) { /* optionally clear the elements */ - __builtin_memset((size_t *)mem, 0, - remainder_size - SIZE_T_SIZE - array_size); - + if (opts & 0x2) { /* optionally clear the elements */ + __builtin_memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); } /* If not provided, allocate the pointer array as final part of chunk */ if (marray == 0) { - - size_t array_chunk_size; + size_t array_chunk_size; array_chunk = chunk_plus_offset(p, contents_size); array_chunk_size = remainder_size - contents_size; - marray = (void **)(chunk2mem(array_chunk)); + marray = (void**) (chunk2mem(array_chunk)); set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); remainder_size = contents_size; - } /* split out elements */ - for (i = 0;; ++i) { - + for (i = 0; ; ++i) { marray[i] = chunk2mem(p); - if (i != n_elements - 1) { - + if (i != n_elements-1) { if (element_size != 0) size = element_size; else @@ -5747,42 +5111,31 @@ static void **ialloc(mstate m, size_t n_elements, size_t *sizes, int opts, remainder_size -= size; set_size_and_pinuse_of_inuse_chunk(m, p, size); p = chunk_plus_offset(p, size); - - } else { /* the final element absorbs any overallocation slop */ - + } + else { /* the final element absorbs any overallocation slop */ set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); break; - } - } #if DEBUG if (marray != chunks) { - /* final element must have exactly exhausted chunk */ if (element_size != 0) { - assert(remainder_size == element_size); - - } else { - + } + else { assert(remainder_size == request2size(sizes[i])); - } - check_inuse_chunk(m, mem2chunk(marray)); - } - for (i = 0; i != n_elements; ++i) check_inuse_chunk(m, mem2chunk(marray[i])); -#endif /* DEBUG */ +#endif /* DEBUG */ POSTACTION(m); return marray; - } /* Try to free all pointers in the given array. @@ -5792,431 +5145,316 @@ static void **ialloc(mstate m, size_t n_elements, size_t *sizes, int opts, chunks before freeing, which will occur often if allocated with ialloc or the array is sorted. */ -static size_t internal_bulk_free(mstate m, void *array[], size_t nelem) { - +static size_t internal_bulk_free(mstate m, void* array[], size_t nelem) { size_t unfreed = 0; if (!PREACTION(m)) { - - void **a; - void **fence = &(array[nelem]); + void** a; + void** fence = &(array[nelem]); for (a = array; a != fence; ++a) { - - void *mem = *a; + void* mem = *a; if (mem != 0) { - mchunkptr p = mem2chunk(mem); - size_t psize = chunksize(p); + size_t psize = chunksize(p); #if FOOTERS if (get_mstate_for(p) != m) { - ++unfreed; continue; - } - #endif check_inuse_chunk(m, p); *a = 0; if (RTCHECK(ok_address(m, p) && ok_inuse(p))) { - - void ** b = a + 1; /* try to merge with next chunk */ + void ** b = a + 1; /* try to merge with next chunk */ mchunkptr next = next_chunk(p); if (b != fence && *b == chunk2mem(next)) { - size_t newsize = chunksize(next) + psize; set_inuse(m, p, newsize); *b = chunk2mem(p); - - } else - + } + else dispose_chunk(m, p, psize); - - } else { - + } + else { CORRUPTION_ERROR_ACTION(m); break; - } - } - } - - if (should_trim(m, m->topsize)) sys_trim(m, 0); + if (should_trim(m, m->topsize)) + sys_trim(m, 0); POSTACTION(m); - } - return unfreed; - } /* Traversal */ #if MALLOC_INSPECT_ALL static void internal_inspect_all(mstate m, - void (*handler)(void *start, void *end, - size_t used_bytes, - void * callback_arg), - void *arg) { - + void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg) { if (is_initialized(m)) { - - mchunkptr top = m->top; + mchunkptr top = m->top; msegmentptr s; for (s = &m->seg; s != 0; s = s->next) { - mchunkptr q = align_as_chunk(s->base); while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) { - mchunkptr next = next_chunk(q); - size_t sz = chunksize(q); - size_t used; - void * start; + size_t sz = chunksize(q); + size_t used; + void* start; if (is_inuse(q)) { - - used = sz - CHUNK_OVERHEAD; /* must not be mmapped */ + used = sz - CHUNK_OVERHEAD; /* must not be mmapped */ start = chunk2mem(q); - - } else { - + } + else { used = 0; - if (is_small(sz)) { /* offset by possible bookkeeping */ - start = (void *)((char *)q + sizeof(struct malloc_chunk)); - - } else { - - start = (void *)((char *)q + sizeof(struct malloc_tree_chunk)); - + if (is_small(sz)) { /* offset by possible bookkeeping */ + start = (void*)((char*)q + sizeof(struct malloc_chunk)); + } + else { + start = (void*)((char*)q + sizeof(struct malloc_tree_chunk)); } - } - - if (start < (void *)next) /* skip if all space is bookkeeping */ + if (start < (void*)next) /* skip if all space is bookkeeping */ handler(start, next, used, arg); - if (q == top) break; + if (q == top) + break; q = next; - } - } - } - } - -#endif /* MALLOC_INSPECT_ALL */ +#endif /* MALLOC_INSPECT_ALL */ /* ------------------ Exported realloc, memalign, etc -------------------- */ #if !ONLY_MSPACES -void *dlrealloc(void *oldmem, size_t bytes) { - - void *mem = 0; +void* dlrealloc(void* oldmem, size_t bytes) { + void* mem = 0; if (oldmem == 0) { - mem = dlmalloc(bytes); - - } else if (bytes >= MAX_REQUEST) { - + } + else if (bytes >= MAX_REQUEST) { MALLOC_FAILURE_ACTION; - } - - #ifdef REALLOC_ZERO_BYTES_FREES +#ifdef REALLOC_ZERO_BYTES_FREES else if (bytes == 0) { - dlfree(oldmem); - } - - #endif /* REALLOC_ZERO_BYTES_FREES */ +#endif /* REALLOC_ZERO_BYTES_FREES */ else { - - size_t nb = request2size(bytes); + size_t nb = request2size(bytes); mchunkptr oldp = mem2chunk(oldmem); - #if !FOOTERS +#if ! FOOTERS mstate m = gm; - #else /* FOOTERS */ +#else /* FOOTERS */ mstate m = get_mstate_for(oldp); if (!ok_magic(m)) { - USAGE_ERROR_ACTION(m, oldmem); return 0; - } - - #endif /* FOOTERS */ +#endif /* FOOTERS */ if (!PREACTION(m)) { - mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1); POSTACTION(m); if (newp != 0) { - check_inuse_chunk(m, newp); mem = chunk2mem(newp); - - } else { - + } + else { mem = internal_malloc(m, bytes); if (mem != 0) { - size_t oc = chunksize(oldp) - overhead_for(oldp); - __builtin_memcpy(mem, oldmem, (oc < bytes) ? oc : bytes); + __builtin_memcpy(mem, oldmem, (oc < bytes)? oc : bytes); internal_free(m, oldmem); - } - } - } - } - return mem; - } -void *dlrealloc_in_place(void *oldmem, size_t bytes) { - - void *mem = 0; +void* dlrealloc_in_place(void* oldmem, size_t bytes) { + void* mem = 0; if (oldmem != 0) { - if (bytes >= MAX_REQUEST) { - MALLOC_FAILURE_ACTION; - - } else { - - size_t nb = request2size(bytes); + } + else { + size_t nb = request2size(bytes); mchunkptr oldp = mem2chunk(oldmem); - #if !FOOTERS +#if ! FOOTERS mstate m = gm; - #else /* FOOTERS */ +#else /* FOOTERS */ mstate m = get_mstate_for(oldp); if (!ok_magic(m)) { - USAGE_ERROR_ACTION(m, oldmem); return 0; - } - - #endif /* FOOTERS */ +#endif /* FOOTERS */ if (!PREACTION(m)) { - mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0); POSTACTION(m); if (newp == oldp) { - check_inuse_chunk(m, newp); mem = oldmem; - } - } - } - } - return mem; - } -void *dlmemalign(size_t alignment, size_t bytes) { - - if (alignment <= MALLOC_ALIGNMENT) { return dlmalloc(bytes); } +void* dlmemalign(size_t alignment, size_t bytes) { + if (alignment <= MALLOC_ALIGNMENT) { + return dlmalloc(bytes); + } return internal_memalign(gm, alignment, bytes); - } -int dlposix_memalign(void **pp, size_t alignment, size_t bytes) { - - void *mem = 0; +int dlposix_memalign(void** pp, size_t alignment, size_t bytes) { + void* mem = 0; if (alignment == MALLOC_ALIGNMENT) mem = dlmalloc(bytes); else { - - size_t d = alignment / sizeof(void *); - size_t r = alignment % sizeof(void *); - if (r != 0 || d == 0 || (d & (d - SIZE_T_ONE)) != 0) + size_t d = alignment / sizeof(void*); + size_t r = alignment % sizeof(void*); + if (r != 0 || d == 0 || (d & (d-SIZE_T_ONE)) != 0) return EINVAL; else if (bytes <= MAX_REQUEST - alignment) { - - if (alignment < MIN_CHUNK_SIZE) alignment = MIN_CHUNK_SIZE; + if (alignment < MIN_CHUNK_SIZE) + alignment = MIN_CHUNK_SIZE; mem = internal_memalign(gm, alignment, bytes); - } - } - if (mem == 0) return ENOMEM; else { - *pp = mem; return 0; - } - } -void *dlvalloc(size_t bytes) { - +void* dlvalloc(size_t bytes) { size_t pagesz; ensure_initialization(); pagesz = mparams.page_size; return dlmemalign(pagesz, bytes); - } -void *dlpvalloc(size_t bytes) { - +void* dlpvalloc(size_t bytes) { size_t pagesz; ensure_initialization(); pagesz = mparams.page_size; - return dlmemalign(pagesz, - (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); - + return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); } -void **dlindependent_calloc(size_t n_elements, size_t elem_size, - void *chunks[]) { - - size_t sz = elem_size; /* serves as 1-element array */ +void** dlindependent_calloc(size_t n_elements, size_t elem_size, + void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ return ialloc(gm, n_elements, &sz, 3, chunks); - } -void **dlindependent_comalloc(size_t n_elements, size_t sizes[], - void *chunks[]) { - +void** dlindependent_comalloc(size_t n_elements, size_t sizes[], + void* chunks[]) { return ialloc(gm, n_elements, sizes, 0, chunks); - } -size_t dlbulk_free(void *array[], size_t nelem) { - +size_t dlbulk_free(void* array[], size_t nelem) { return internal_bulk_free(gm, array, nelem); - } - #if MALLOC_INSPECT_ALL -void dlmalloc_inspect_all(void (*handler)(void *start, void *end, - size_t used_bytes, - void * callback_arg), - void *arg) { - +#if MALLOC_INSPECT_ALL +void dlmalloc_inspect_all(void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg) { ensure_initialization(); if (!PREACTION(gm)) { - internal_inspect_all(gm, handler, arg); POSTACTION(gm); - } - } - - #endif /* MALLOC_INSPECT_ALL */ +#endif /* MALLOC_INSPECT_ALL */ int dlmalloc_trim(size_t pad) { - int result = 0; ensure_initialization(); if (!PREACTION(gm)) { - result = sys_trim(gm, pad); POSTACTION(gm); - } - return result; - } size_t dlmalloc_footprint(void) { - return gm->footprint; - } size_t dlmalloc_max_footprint(void) { - return gm->max_footprint; - } size_t dlmalloc_footprint_limit(void) { - size_t maf = gm->footprint_limit; return maf == 0 ? MAX_SIZE_T : maf; - } size_t dlmalloc_set_footprint_limit(size_t bytes) { - - size_t result; /* invert sense of 0 */ - if (bytes == 0) result = granularity_align(1); /* Use minimal size */ + size_t result; /* invert sense of 0 */ + if (bytes == 0) + result = granularity_align(1); /* Use minimal size */ if (bytes == MAX_SIZE_T) - result = 0; /* disable */ + result = 0; /* disable */ else result = granularity_align(bytes); return gm->footprint_limit = result; - } - #if !NO_MALLINFO +#if !NO_MALLINFO struct mallinfo dlmallinfo(void) { - return internal_mallinfo(gm); - } +#endif /* NO_MALLINFO */ - #endif /* NO_MALLINFO */ - - #if !NO_MALLOC_STATS +#if !NO_MALLOC_STATS void dlmalloc_stats() { - internal_malloc_stats(gm); - } - - #endif /* NO_MALLOC_STATS */ +#endif /* NO_MALLOC_STATS */ int dlmallopt(int param_number, int value) { - return change_mparam(param_number, value); - } -size_t dlmalloc_usable_size(void *mem) { - +size_t dlmalloc_usable_size(void* mem) { if (mem != 0) { - mchunkptr p = mem2chunk(mem); - if (is_inuse(p)) return chunksize(p) - overhead_for(p); - + if (is_inuse(p)) + return chunksize(p) - overhead_for(p); } - return 0; - } -#endif /* !ONLY_MSPACES */ +#endif /* !ONLY_MSPACES */ /* ----------------------------- user mspaces ---------------------------- */ #if MSPACES -static mstate init_user_mstate(char *tbase, size_t tsize) { - - size_t msize = pad_request(sizeof(struct malloc_state)); +static mstate init_user_mstate(char* tbase, size_t tsize) { + size_t msize = pad_request(sizeof(struct malloc_state)); mchunkptr mn; mchunkptr msp = align_as_chunk(tbase); - mstate m = (mstate)(chunk2mem(msp)); + mstate m = (mstate)(chunk2mem(msp)); __builtin_memset(m, 0, msize); (void)INITIAL_LOCK(&m->mutex); - msp->head = (msize | INUSE_BITS); + msp->head = (msize|INUSE_BITS); m->seg.base = m->least_addr = tbase; m->seg.size = m->footprint = m->max_footprint = tsize; m->magic = mparams.magic; @@ -6227,111 +5465,82 @@ static mstate init_user_mstate(char *tbase, size_t tsize) { disable_contiguous(m); init_bins(m); mn = next_chunk(mem2chunk(m)); - init_top(m, mn, (size_t)((tbase + tsize) - (char *)mn) - TOP_FOOT_SIZE); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); check_top_chunk(m, m->top); return m; - } mspace create_mspace(size_t capacity, int locked) { - mstate m = 0; size_t msize; ensure_initialization(); msize = pad_request(sizeof(struct malloc_state)); - if (capacity < (size_t) - (msize + TOP_FOOT_SIZE + mparams.page_size)) { - - size_t rs = ((capacity == 0) ? mparams.granularity - : (capacity + TOP_FOOT_SIZE + msize)); + if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + size_t rs = ((capacity == 0)? mparams.granularity : + (capacity + TOP_FOOT_SIZE + msize)); size_t tsize = granularity_align(rs); - char * tbase = (char *)(CALL_MMAP(tsize)); + char* tbase = (char*)(CALL_MMAP(tsize)); if (tbase != CMFAIL) { - m = init_user_mstate(tbase, tsize); m->seg.sflags = USE_MMAP_BIT; set_lock(m, locked); - } - } - return (mspace)m; - } -mspace create_mspace_with_base(void *base, size_t capacity, int locked) { - +mspace create_mspace_with_base(void* base, size_t capacity, int locked) { mstate m = 0; size_t msize; ensure_initialization(); msize = pad_request(sizeof(struct malloc_state)); if (capacity > msize + TOP_FOOT_SIZE && - capacity < (size_t) - (msize + TOP_FOOT_SIZE + mparams.page_size)) { - - m = init_user_mstate((char *)base, capacity); + capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + m = init_user_mstate((char*)base, capacity); m->seg.sflags = EXTERN_BIT; set_lock(m, locked); - } - return (mspace)m; - } int mspace_track_large_chunks(mspace msp, int enable) { - - int ret = 0; + int ret = 0; mstate ms = (mstate)msp; if (!PREACTION(ms)) { - - if (!use_mmap(ms)) { ret = 1; } + if (!use_mmap(ms)) { + ret = 1; + } if (!enable) { - enable_mmap(ms); - } else { - disable_mmap(ms); - } - POSTACTION(ms); - } - return ret; - } size_t destroy_mspace(mspace msp) { - size_t freed = 0; mstate ms = (mstate)msp; if (ok_magic(ms)) { - msegmentptr sp = &ms->seg; - (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */ + (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */ while (sp != 0) { - - char * base = sp->base; + char* base = sp->base; size_t size = sp->size; flag_t flag = sp->sflags; - (void)base; /* placate people compiling -Wunused-variable */ + (void)base; /* placate people compiling -Wunused-variable */ sp = sp->next; if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) && CALL_MUNMAP(base, size) == 0) freed += size; - } - - } else { - - USAGE_ERROR_ACTION(ms, ms); - } - + else { + USAGE_ERROR_ACTION(ms,ms); + } return freed; - } /* @@ -6339,31 +5548,25 @@ size_t destroy_mspace(mspace msp) { versions. This is not so nice but better than the alternatives. */ -void *mspace_malloc(mspace msp, size_t bytes) { - +void* mspace_malloc(mspace msp, size_t bytes) { mstate ms = (mstate)msp; if (!ok_magic(ms)) { - - USAGE_ERROR_ACTION(ms, ms); + USAGE_ERROR_ACTION(ms,ms); return 0; - } - if (!PREACTION(ms)) { - - void * mem; + void* mem; size_t nb; if (bytes <= MAX_SMALL_REQUEST) { - bindex_t idx; binmap_t smallbits; - nb = (bytes < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(bytes); + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); idx = small_index(nb); smallbits = ms->smallmap >> idx; - if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ mchunkptr b, p; - idx += ~smallbits & 1; /* Uses next bin if idx empty */ + idx += ~smallbits & 1; /* Uses next bin if idx empty */ b = smallbin_at(ms, idx); p = b->fd; assert(chunksize(p) == small_index2size(idx)); @@ -6372,17 +5575,15 @@ void *mspace_malloc(mspace msp, size_t bytes) { mem = chunk2mem(p); check_malloced_chunk(ms, mem, nb); goto postaction; - } else if (nb > ms->dvsize) { - - if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ mchunkptr b, p, r; - size_t rsize; - bindex_t i; - binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); - binmap_t leastbit = least_bit(leftbits); + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); compute_bit2idx(leastbit, i); b = smallbin_at(ms, i); p = b->fd; @@ -6393,71 +5594,54 @@ void *mspace_malloc(mspace msp, size_t bytes) { if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) set_inuse_and_pinuse(ms, p, small_index2size(i)); else { - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); r = chunk_plus_offset(p, nb); set_size_and_pinuse_of_free_chunk(r, rsize); replace_dv(ms, r, rsize); - } - mem = chunk2mem(p); check_malloced_chunk(ms, mem, nb); goto postaction; - } else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { - check_malloced_chunk(ms, mem, nb); goto postaction; - } - } - - } else if (bytes >= MAX_REQUEST) - + } + else if (bytes >= MAX_REQUEST) nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ else { - nb = pad_request(bytes); if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { - check_malloced_chunk(ms, mem, nb); goto postaction; - } - } if (nb <= ms->dvsize) { - - size_t rsize = ms->dvsize - nb; + size_t rsize = ms->dvsize - nb; mchunkptr p = ms->dv; - if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ mchunkptr r = ms->dv = chunk_plus_offset(p, nb); ms->dvsize = rsize; set_size_and_pinuse_of_free_chunk(r, rsize); set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - - } else { /* exhaust dv */ - + } + else { /* exhaust dv */ size_t dvs = ms->dvsize; ms->dvsize = 0; ms->dv = 0; set_inuse_and_pinuse(ms, p, dvs); - } - mem = chunk2mem(p); check_malloced_chunk(ms, mem, nb); goto postaction; - } - else if (nb < ms->topsize) { /* Split top */ - size_t rsize = ms->topsize -= nb; + else if (nb < ms->topsize) { /* Split top */ + size_t rsize = ms->topsize -= nb; mchunkptr p = ms->top; mchunkptr r = ms->top = chunk_plus_offset(p, nb); r->head = rsize | PINUSE_BIT; @@ -6466,7 +5650,6 @@ void *mspace_malloc(mspace msp, size_t bytes) { check_top_chunk(ms, ms->top); check_malloced_chunk(ms, mem, nb); goto postaction; - } mem = sys_alloc(ms, nb); @@ -6474,519 +5657,372 @@ void *mspace_malloc(mspace msp, size_t bytes) { postaction: POSTACTION(ms); return mem; - } return 0; - } -void mspace_free(mspace msp, void *mem) { - +void mspace_free(mspace msp, void* mem) { if (mem != 0) { - - mchunkptr p = mem2chunk(mem); - #if FOOTERS + mchunkptr p = mem2chunk(mem); +#if FOOTERS mstate fm = get_mstate_for(p); - (void)msp; /* placate people compiling -Wunused */ - #else /* FOOTERS */ + (void)msp; /* placate people compiling -Wunused */ +#else /* FOOTERS */ mstate fm = (mstate)msp; - #endif /* FOOTERS */ +#endif /* FOOTERS */ if (!ok_magic(fm)) { - USAGE_ERROR_ACTION(fm, p); return; - } - if (!PREACTION(fm)) { - check_inuse_chunk(fm, p); if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) { - - size_t psize = chunksize(p); + size_t psize = chunksize(p); mchunkptr next = chunk_plus_offset(p, psize); if (!pinuse(p)) { - size_t prevsize = p->prev_foot; if (is_mmapped(p)) { - psize += prevsize + MMAP_FOOT_PAD; - if (CALL_MUNMAP((char *)p - prevsize, psize) == 0) + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) fm->footprint -= psize; goto postaction; - - } else { - + } + else { mchunkptr prev = chunk_minus_offset(p, prevsize); psize += prevsize; p = prev; - if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ if (p != fm->dv) { - unlink_chunk(fm, p, prevsize); - - } else if ((next->head & INUSE_BITS) == INUSE_BITS) { - + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { fm->dvsize = psize; set_free_with_pinuse(p, psize, next); goto postaction; - } - - } else - + } + else goto erroraction; - } - } if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { - - if (!cinuse(next)) { /* consolidate forward */ + if (!cinuse(next)) { /* consolidate forward */ if (next == fm->top) { - size_t tsize = fm->topsize += psize; fm->top = p; p->head = tsize | PINUSE_BIT; if (p == fm->dv) { - fm->dv = 0; fm->dvsize = 0; - } - - if (should_trim(fm, tsize)) sys_trim(fm, 0); + if (should_trim(fm, tsize)) + sys_trim(fm, 0); goto postaction; - - } else if (next == fm->dv) { - + } + else if (next == fm->dv) { size_t dsize = fm->dvsize += psize; fm->dv = p; set_size_and_pinuse_of_free_chunk(p, dsize); goto postaction; - - } else { - + } + else { size_t nsize = chunksize(next); psize += nsize; unlink_chunk(fm, next, nsize); set_size_and_pinuse_of_free_chunk(p, psize); if (p == fm->dv) { - fm->dvsize = psize; goto postaction; - } - } - - } else - + } + else set_free_with_pinuse(p, psize, next); if (is_small(psize)) { - insert_small_chunk(fm, p, psize); check_free_chunk(fm, p); - - } else { - + } + else { tchunkptr tp = (tchunkptr)p; insert_large_chunk(fm, tp, psize); check_free_chunk(fm, p); - if (--fm->release_checks == 0) release_unused_segments(fm); - + if (--fm->release_checks == 0) + release_unused_segments(fm); } - goto postaction; - } - } - erroraction: USAGE_ERROR_ACTION(fm, p); postaction: POSTACTION(fm); - } - } - } -void *mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { - - void * mem; +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { + void* mem; size_t req = 0; mstate ms = (mstate)msp; if (!ok_magic(ms)) { - - USAGE_ERROR_ACTION(ms, ms); + USAGE_ERROR_ACTION(ms,ms); return 0; - } - if (n_elements != 0) { - req = n_elements * elem_size; if (((n_elements | elem_size) & ~(size_t)0xffff) && (req / n_elements != elem_size)) - req = MAX_SIZE_T; /* force downstream failure on overflow */ - + req = MAX_SIZE_T; /* force downstream failure on overflow */ } - mem = internal_malloc(ms, req); if (mem != 0 && calloc_must_clear(mem2chunk(mem))) __builtin_memset(mem, 0, req); return mem; - } -void *mspace_realloc(mspace msp, void *oldmem, size_t bytes) { - - void *mem = 0; +void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { + void* mem = 0; if (oldmem == 0) { - mem = mspace_malloc(msp, bytes); - - } else if (bytes >= MAX_REQUEST) { - + } + else if (bytes >= MAX_REQUEST) { MALLOC_FAILURE_ACTION; - } - - #ifdef REALLOC_ZERO_BYTES_FREES +#ifdef REALLOC_ZERO_BYTES_FREES else if (bytes == 0) { - mspace_free(msp, oldmem); - } - - #endif /* REALLOC_ZERO_BYTES_FREES */ +#endif /* REALLOC_ZERO_BYTES_FREES */ else { - - size_t nb = request2size(bytes); + size_t nb = request2size(bytes); mchunkptr oldp = mem2chunk(oldmem); - #if !FOOTERS +#if ! FOOTERS mstate m = (mstate)msp; - #else /* FOOTERS */ +#else /* FOOTERS */ mstate m = get_mstate_for(oldp); if (!ok_magic(m)) { - USAGE_ERROR_ACTION(m, oldmem); return 0; - } - - #endif /* FOOTERS */ +#endif /* FOOTERS */ if (!PREACTION(m)) { - mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1); POSTACTION(m); if (newp != 0) { - check_inuse_chunk(m, newp); mem = chunk2mem(newp); - - } else { - + } + else { mem = mspace_malloc(m, bytes); if (mem != 0) { - size_t oc = chunksize(oldp) - overhead_for(oldp); - __builtin_memcpy(mem, oldmem, (oc < bytes) ? oc : bytes); + __builtin_memcpy(mem, oldmem, (oc < bytes)? oc : bytes); mspace_free(m, oldmem); - } - } - } - } - return mem; - } -void *mspace_realloc_in_place(mspace msp, void *oldmem, size_t bytes) { - - void *mem = 0; +void* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes) { + void* mem = 0; if (oldmem != 0) { - if (bytes >= MAX_REQUEST) { - MALLOC_FAILURE_ACTION; - - } else { - - size_t nb = request2size(bytes); + } + else { + size_t nb = request2size(bytes); mchunkptr oldp = mem2chunk(oldmem); - #if !FOOTERS +#if ! FOOTERS mstate m = (mstate)msp; - #else /* FOOTERS */ +#else /* FOOTERS */ mstate m = get_mstate_for(oldp); - (void)msp; /* placate people compiling -Wunused */ + (void)msp; /* placate people compiling -Wunused */ if (!ok_magic(m)) { - USAGE_ERROR_ACTION(m, oldmem); return 0; - } - - #endif /* FOOTERS */ +#endif /* FOOTERS */ if (!PREACTION(m)) { - mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0); POSTACTION(m); if (newp == oldp) { - check_inuse_chunk(m, newp); mem = oldmem; - } - } - } - } - return mem; - } -void *mspace_memalign(mspace msp, size_t alignment, size_t bytes) { - +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { mstate ms = (mstate)msp; if (!ok_magic(ms)) { - - USAGE_ERROR_ACTION(ms, ms); + USAGE_ERROR_ACTION(ms,ms); return 0; - } - - if (alignment <= MALLOC_ALIGNMENT) return mspace_malloc(msp, bytes); + if (alignment <= MALLOC_ALIGNMENT) + return mspace_malloc(msp, bytes); return internal_memalign(ms, alignment, bytes); - } -void **mspace_independent_calloc(mspace msp, size_t n_elements, - size_t elem_size, void *chunks[]) { - - size_t sz = elem_size; /* serves as 1-element array */ +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ mstate ms = (mstate)msp; if (!ok_magic(ms)) { - - USAGE_ERROR_ACTION(ms, ms); + USAGE_ERROR_ACTION(ms,ms); return 0; - } - return ialloc(ms, n_elements, &sz, 3, chunks); - } -void **mspace_independent_comalloc(mspace msp, size_t n_elements, - size_t sizes[], void *chunks[]) { - +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]) { mstate ms = (mstate)msp; if (!ok_magic(ms)) { - - USAGE_ERROR_ACTION(ms, ms); + USAGE_ERROR_ACTION(ms,ms); return 0; - } - return ialloc(ms, n_elements, sizes, 0, chunks); - } -size_t mspace_bulk_free(mspace msp, void *array[], size_t nelem) { - +size_t mspace_bulk_free(mspace msp, void* array[], size_t nelem) { return internal_bulk_free((mstate)msp, array, nelem); - } - #if MALLOC_INSPECT_ALL +#if MALLOC_INSPECT_ALL void mspace_inspect_all(mspace msp, - void (*handler)(void *start, void *end, - size_t used_bytes, void *callback_arg), - void *arg) { - + void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg) { mstate ms = (mstate)msp; if (ok_magic(ms)) { - if (!PREACTION(ms)) { - internal_inspect_all(ms, handler, arg); POSTACTION(ms); - } - - } else { - - USAGE_ERROR_ACTION(ms, ms); - } - + else { + USAGE_ERROR_ACTION(ms,ms); + } } - - #endif /* MALLOC_INSPECT_ALL */ +#endif /* MALLOC_INSPECT_ALL */ int mspace_trim(mspace msp, size_t pad) { - - int result = 0; + int result = 0; mstate ms = (mstate)msp; if (ok_magic(ms)) { - if (!PREACTION(ms)) { - result = sys_trim(ms, pad); POSTACTION(ms); - } - - } else { - - USAGE_ERROR_ACTION(ms, ms); - } - + else { + USAGE_ERROR_ACTION(ms,ms); + } return result; - } - #if !NO_MALLOC_STATS +#if !NO_MALLOC_STATS void mspace_malloc_stats(mspace msp) { - mstate ms = (mstate)msp; if (ok_magic(ms)) { - internal_malloc_stats(ms); - - } else { - - USAGE_ERROR_ACTION(ms, ms); - } - + else { + USAGE_ERROR_ACTION(ms,ms); + } } - - #endif /* NO_MALLOC_STATS */ +#endif /* NO_MALLOC_STATS */ size_t mspace_footprint(mspace msp) { - size_t result = 0; mstate ms = (mstate)msp; if (ok_magic(ms)) { - result = ms->footprint; - - } else { - - USAGE_ERROR_ACTION(ms, ms); - } - + else { + USAGE_ERROR_ACTION(ms,ms); + } return result; - } size_t mspace_max_footprint(mspace msp) { - size_t result = 0; mstate ms = (mstate)msp; if (ok_magic(ms)) { - result = ms->max_footprint; - - } else { - - USAGE_ERROR_ACTION(ms, ms); - } - + else { + USAGE_ERROR_ACTION(ms,ms); + } return result; - } size_t mspace_footprint_limit(mspace msp) { - size_t result = 0; mstate ms = (mstate)msp; if (ok_magic(ms)) { - size_t maf = ms->footprint_limit; result = (maf == 0) ? MAX_SIZE_T : maf; - - } else { - - USAGE_ERROR_ACTION(ms, ms); - } - + else { + USAGE_ERROR_ACTION(ms,ms); + } return result; - } size_t mspace_set_footprint_limit(mspace msp, size_t bytes) { - size_t result = 0; mstate ms = (mstate)msp; if (ok_magic(ms)) { - - if (bytes == 0) result = granularity_align(1); /* Use minimal size */ + if (bytes == 0) + result = granularity_align(1); /* Use minimal size */ if (bytes == MAX_SIZE_T) - result = 0; /* disable */ + result = 0; /* disable */ else result = granularity_align(bytes); ms->footprint_limit = result; - - } else { - - USAGE_ERROR_ACTION(ms, ms); - } - + else { + USAGE_ERROR_ACTION(ms,ms); + } return result; - } - #if !NO_MALLINFO +#if !NO_MALLINFO struct mallinfo mspace_mallinfo(mspace msp) { - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { USAGE_ERROR_ACTION(ms, ms); } + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } return internal_mallinfo(ms); - } +#endif /* NO_MALLINFO */ - #endif /* NO_MALLINFO */ - -size_t mspace_usable_size(const void *mem) { - +size_t mspace_usable_size(const void* mem) { if (mem != 0) { - mchunkptr p = mem2chunk(mem); - if (is_inuse(p)) return chunksize(p) - overhead_for(p); - + if (is_inuse(p)) + return chunksize(p) - overhead_for(p); } - return 0; - } int mspace_mallopt(int param_number, int value) { - return change_mparam(param_number, value); - } -#endif /* MSPACES */ +#endif /* MSPACES */ + /* -------------------- Alternative MORECORE functions ------------------- */ @@ -7031,48 +6067,35 @@ int mspace_mallopt(int param_number, int value) { void *osMoreCore(int size) { - void *ptr = 0; static void *sbrk_top = 0; if (size > 0) { - if (size < MINIMUM_MORECORE_SIZE) size = MINIMUM_MORECORE_SIZE; if (CurrentExecutionLevel() == kTaskLevel) ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); if (ptr == 0) { - return (void *) MFAIL; - } - // save ptrs so they can be freed during cleanup our_os_pools[next_os_pool] = ptr; next_os_pool++; ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); sbrk_top = (char *) ptr + size; return ptr; - } - else if (size < 0) { - // we don't currently support shrink behavior return (void *) MFAIL; - } - else { - return sbrk_top; - } - } // cleanup any allocated memory pools @@ -7080,22 +6103,19 @@ int mspace_mallopt(int param_number, int value) { void osCleanupMem(void) { - void **ptr; for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) if (*ptr) { - PoolDeallocate(*ptr); *ptr = 0; - } - } */ + /* ----------------------------------------------------------------------- History: v2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea @@ -7315,3 +6335,4 @@ History: */ +#endif // __GLIBC__ diff --git a/qemu_mode/libqasan/malloc.c b/qemu_mode/libqasan/malloc.c index f8237826..54c1096a 100644 --- a/qemu_mode/libqasan/malloc.c +++ b/qemu_mode/libqasan/malloc.c @@ -24,6 +24,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #include "libqasan.h" +#include #include #include #include @@ -50,9 +51,9 @@ typedef struct { struct chunk_begin { size_t requested_size; - void * aligned_orig; // NULL if not aligned - struct chunk_begin *next; - struct chunk_begin *prev; + void* aligned_orig; // NULL if not aligned + struct chunk_begin* next; + struct chunk_begin* prev; char redzone[REDZONE_SIZE]; }; @@ -65,30 +66,47 @@ struct chunk_struct { }; +#ifdef __GLIBC__ + +void* (*__lq_libc_malloc)(size_t); +void (*__lq_libc_free)(void*); +#define backend_malloc __lq_libc_malloc +#define backend_free __lq_libc_free + +#define TMP_ZONE_SIZE 4096 +static int __tmp_alloc_zone_idx; +static unsigned char __tmp_alloc_zone[TMP_ZONE_SIZE]; + +#else + // From dlmalloc.c -void *dlmalloc(size_t); -void dlfree(void *); +void* dlmalloc(size_t); +void dlfree(void*); +#define backend_malloc dlmalloc +#define backend_free dlfree + +#endif int __libqasan_malloc_initialized; -static struct chunk_begin *quarantine_top; -static struct chunk_begin *quarantine_end; +static struct chunk_begin* quarantine_top; +static struct chunk_begin* quarantine_end; static size_t quarantine_bytes; #ifdef __BIONIC__ -static pthread_mutex_t quarantine_lock; - #define LOCK_TRY pthread_mutex_trylock - #define LOCK_INIT pthread_mutex_init - #define LOCK_UNLOCK pthread_mutex_unlock +static pthread_mutex_t quarantine_lock; +#define LOCK_TRY pthread_mutex_trylock +#define LOCK_INIT pthread_mutex_init +#define LOCK_UNLOCK pthread_mutex_unlock #else -static pthread_spinlock_t quarantine_lock; - #define LOCK_TRY pthread_spin_trylock - #define LOCK_INIT pthread_spin_init - #define LOCK_UNLOCK pthread_spin_unlock +static pthread_spinlock_t quarantine_lock; +#define LOCK_TRY pthread_spin_trylock +#define LOCK_INIT pthread_spin_init +#define LOCK_UNLOCK pthread_spin_unlock #endif // need qasan disabled -static int quanratine_push(struct chunk_begin *ck) { +static int quanratine_push(struct chunk_begin* ck) { if (ck->requested_size >= QUARANTINE_MAX_BYTES) return 0; @@ -96,15 +114,15 @@ static int quanratine_push(struct chunk_begin *ck) { while (ck->requested_size + quarantine_bytes >= QUARANTINE_MAX_BYTES) { - struct chunk_begin *tmp = quarantine_end; + struct chunk_begin* tmp = quarantine_end; quarantine_end = tmp->prev; quarantine_bytes -= tmp->requested_size; if (tmp->aligned_orig) - dlfree(tmp->aligned_orig); + backend_free(tmp->aligned_orig); else - dlfree(tmp); + backend_free(tmp); } @@ -122,6 +140,11 @@ void __libqasan_init_malloc(void) { if (__libqasan_malloc_initialized) return; +#ifdef __GLIBC__ + __lq_libc_malloc = dlsym(RTLD_NEXT, "malloc"); + __lq_libc_free = dlsym(RTLD_NEXT, "free"); +#endif + LOCK_INIT(&quarantine_lock, PTHREAD_PROCESS_PRIVATE); __libqasan_malloc_initialized = 1; @@ -131,24 +154,38 @@ void __libqasan_init_malloc(void) { } -size_t __libqasan_malloc_usable_size(void *ptr) { +size_t __libqasan_malloc_usable_size(void* ptr) { - char *p = ptr; + char* p = ptr; p -= sizeof(struct chunk_begin); - return ((struct chunk_begin *)p)->requested_size; + return ((struct chunk_begin*)p)->requested_size; } -void *__libqasan_malloc(size_t size) { +void* __libqasan_malloc(size_t size) { - if (!__libqasan_malloc_initialized) { __libqasan_init_malloc(); } + if (!__libqasan_malloc_initialized) { + + __libqasan_init_malloc(); - if (!__libqasan_malloc_initialized) __libqasan_init_malloc(); +#ifdef __GLIBC__ + void* r = &__tmp_alloc_zone[__tmp_alloc_zone_idx]; + + if (size & (ALLOC_ALIGN_SIZE - 1)) + __tmp_alloc_zone_idx += + (size & ~(ALLOC_ALIGN_SIZE - 1)) + ALLOC_ALIGN_SIZE; + else + __tmp_alloc_zone_idx += size; + + return r; +#endif + + } int state = QASAN_SWAP(QASAN_DISABLED); // disable qasan for this thread - struct chunk_begin *p = dlmalloc(sizeof(struct chunk_struct) + size); + struct chunk_begin* p = backend_malloc(sizeof(struct chunk_struct) + size); QASAN_SWAP(state); @@ -160,14 +197,14 @@ void *__libqasan_malloc(size_t size) { p->aligned_orig = NULL; p->next = p->prev = NULL; - QASAN_ALLOC(&p[1], (char *)&p[1] + size); + QASAN_ALLOC(&p[1], (char*)&p[1] + size); QASAN_POISON(p->redzone, REDZONE_SIZE, ASAN_HEAP_LEFT_RZ); if (size & (ALLOC_ALIGN_SIZE - 1)) - QASAN_POISON((char *)&p[1] + size, + QASAN_POISON((char*)&p[1] + size, (size & ~(ALLOC_ALIGN_SIZE - 1)) + 8 - size + REDZONE_SIZE, ASAN_HEAP_RIGHT_RZ); else - QASAN_POISON((char *)&p[1] + size, REDZONE_SIZE, ASAN_HEAP_RIGHT_RZ); + QASAN_POISON((char*)&p[1] + size, REDZONE_SIZE, ASAN_HEAP_RIGHT_RZ); __builtin_memset(&p[1], 0xff, size); @@ -175,11 +212,17 @@ void *__libqasan_malloc(size_t size) { } -void __libqasan_free(void *ptr) { +void __libqasan_free(void* ptr) { if (!ptr) return; + +#ifdef __GLIBC__ + if (ptr >= (void*)__tmp_alloc_zone && + ptr < ((void*)__tmp_alloc_zone + TMP_ZONE_SIZE)) + return; +#endif - struct chunk_begin *p = ptr; + struct chunk_begin* p = ptr; p -= 1; size_t n = p->requested_size; @@ -190,9 +233,9 @@ void __libqasan_free(void *ptr) { if (!quanratine_push(p)) { if (p->aligned_orig) - dlfree(p->aligned_orig); + backend_free(p->aligned_orig); else - dlfree(p); + backend_free(p); } @@ -206,11 +249,21 @@ void __libqasan_free(void *ptr) { } -void *__libqasan_calloc(size_t nmemb, size_t size) { +void* __libqasan_calloc(size_t nmemb, size_t size) { size *= nmemb; - char *p = __libqasan_malloc(size); +#ifdef __GLIBC__ + if (!__libqasan_malloc_initialized) { + + void* r = &__tmp_alloc_zone[__tmp_alloc_zone_idx]; + __tmp_alloc_zone_idx += size; + return r; + + } +#endif + + char* p = __libqasan_malloc(size); if (!p) return NULL; __builtin_memset(p, 0, size); @@ -219,14 +272,14 @@ void *__libqasan_calloc(size_t nmemb, size_t size) { } -void *__libqasan_realloc(void *ptr, size_t size) { +void* __libqasan_realloc(void* ptr, size_t size) { - char *p = __libqasan_malloc(size); + char* p = __libqasan_malloc(size); if (!p) return NULL; if (!ptr) return p; - size_t n = ((struct chunk_begin *)ptr)[-1].requested_size; + size_t n = ((struct chunk_begin*)ptr)[-1].requested_size; if (size < n) n = size; __builtin_memcpy(p, ptr, n); @@ -236,9 +289,9 @@ void *__libqasan_realloc(void *ptr, size_t size) { } -int __libqasan_posix_memalign(void **ptr, size_t align, size_t len) { +int __libqasan_posix_memalign(void** ptr, size_t align, size_t len) { - if ((align % 2) || (align % sizeof(void *))) return EINVAL; + if ((align % 2) || (align % sizeof(void*))) return EINVAL; if (len == 0) { *ptr = NULL; @@ -252,7 +305,7 @@ int __libqasan_posix_memalign(void **ptr, size_t align, size_t len) { int state = QASAN_SWAP(QASAN_DISABLED); // disable qasan for this thread - char *orig = dlmalloc(sizeof(struct chunk_struct) + size); + char* orig = backend_malloc(sizeof(struct chunk_struct) + size); QASAN_SWAP(state); @@ -260,10 +313,10 @@ int __libqasan_posix_memalign(void **ptr, size_t align, size_t len) { QASAN_UNPOISON(orig, sizeof(struct chunk_struct) + size); - char *data = orig + sizeof(struct chunk_begin); + char* data = orig + sizeof(struct chunk_begin); data += align - ((uintptr_t)data % align); - struct chunk_begin *p = (struct chunk_begin *)data - 1; + struct chunk_begin* p = (struct chunk_begin*)data - 1; p->requested_size = len; p->aligned_orig = orig; @@ -286,9 +339,9 @@ int __libqasan_posix_memalign(void **ptr, size_t align, size_t len) { } -void *__libqasan_memalign(size_t align, size_t len) { +void* __libqasan_memalign(size_t align, size_t len) { - void *ret = NULL; + void* ret = NULL; __libqasan_posix_memalign(&ret, align, len); @@ -296,9 +349,9 @@ void *__libqasan_memalign(size_t align, size_t len) { } -void *__libqasan_aligned_alloc(size_t align, size_t len) { +void* __libqasan_aligned_alloc(size_t align, size_t len) { - void *ret = NULL; + void* ret = NULL; if ((len % align)) return NULL; diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index 6ab6bf28..47722f64 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit 6ab6bf28decb3e36eee43ffbd4a3bfd052dbbb50 +Subproject commit 47722f64e4c1662bad97dc25f3e4cc63959ff5f3 -- cgit 1.4.1 From 223bd70f1f1530a0b8331e3deee0de2b20ae061b Mon Sep 17 00:00:00 2001 From: hexcoder Date: Thu, 11 Feb 2021 20:08:28 +0100 Subject: typo --- docs/env_variables.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index ab56c178..886669ad 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -517,7 +517,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings: - With `AFL_USE_QASAN` you can enable QEMU AddressSanitizer for dynamically linked binaries. - - With `AFL_QEMU_FORCE_DFL` you force QEMU to ignore the registered singal + - With `AFL_QEMU_FORCE_DFL` you force QEMU to ignore the registered signal handlers of the target. ## 6) Settings for afl-cmin -- cgit 1.4.1 From 9bd1e19d7f004b4da6a610b07e59f99d66bb7ec2 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 13 Feb 2021 22:43:56 +0100 Subject: added AFL_IGNORE_UNKNOWN_ENVS --- docs/Changelog.md | 3 ++- docs/env_variables.md | 5 ++++- include/envs.h | 1 + instrumentation/SanitizerCoveragePCGUARD.so.cc | 2 +- src/afl-cc.c | 1 + src/afl-common.c | 4 ++-- src/afl-fuzz.c | 1 + src/afl-showmap.c | 5 +++-- 8 files changed, 15 insertions(+), 7 deletions(-) (limited to 'docs/env_variables.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 895ab845..71ef4c2c 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -61,7 +61,8 @@ sending a mail to . - Added a new example harness to compare python, c, and rust bindings - afl-cmin and afl-showmap now support the -f option - changed default: no memory limit for afl-cmin and afl-cmin.bash - - warn on any _AFL and __AFL env vars + - warn on any _AFL and __AFL env vars. + - set AFL_IGNORE_UNKNOWN_ENVS to not warn on unknown AFL_... env vars. - added dummy Makefile to instrumentation/ - Updated utils/afl_frida to be 5% faster, 7% on x86_x64 - Added AFL_KILL_SIGNAL env variable (thanks @v-p-b) diff --git a/docs/env_variables.md b/docs/env_variables.md index 886669ad..f7745247 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -5,6 +5,10 @@ users or for some types of custom fuzzing setups. See [README.md](README.md) for the general instruction manual. + Note that most tools will warn on any unknown AFL environment variables. + This is for warning on typos that can happen. If you want to disable this + check then set the `AFL_IGNORE_UNKNOWN_ENVS` environment variable. + ## 1) Settings for all compilers Starting with afl++ 3.0 there is only one compiler: afl-cc @@ -18,7 +22,6 @@ To select the different instrumentation modes this can be done by `MODE` can be one of `LTO` (afl-clang-lto*), `LLVM` (afl-clang-fast*), `GCC_PLUGIN` (afl-g*-fast) or `GCC` (afl-gcc/afl-g++). - Because (with the exception of the --afl-MODE command line option) the compile-time tools do not accept afl specific command-line options, they make fairly broad use of environmental variables instead: diff --git a/include/envs.h b/include/envs.h index 210b34a6..4313e053 100644 --- a/include/envs.h +++ b/include/envs.h @@ -61,6 +61,7 @@ static char *afl_environment_variables[] = { "AFL_FORKSRV_INIT_TMOUT", "AFL_HARDEN", "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES", + "AFL_IGNORE_UNKNOWN_ENVS", "AFL_IMPORT_FIRST", "AFL_INST_LIBS", "AFL_INST_RATIO", diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 80c8f917..9b1351b0 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -1138,7 +1138,7 @@ void ModuleSanitizerCoverage::InjectTraceForGep( IRBuilder<> IRB(GEP); for (Use &Idx : GEP->indices()) if (!isa(Idx) && Idx->getType()->isIntegerTy()) - IRB.CreateCall(SanCovTraceGepFunction, + IRB.CreateCall(SanCovTraceGepFunction, {IRB.CreateIntCast(Idx, IntptrTy, true)}); } diff --git a/src/afl-cc.c b/src/afl-cc.c index 9d88f262..d41f79a2 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1587,6 +1587,7 @@ int main(int argc, char **argv, char **envp) { "libtokencap.so)\n" " AFL_PATH: path to instrumenting pass and runtime " "(afl-compiler-rt.*o)\n" + " AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n" " AFL_INST_RATIO: percentage of branches to instrument\n" " AFL_QUIET: suppress verbose output\n" " AFL_HARDEN: adds code hardening to catch memory bugs\n" diff --git a/src/afl-common.c b/src/afl-common.c index 1cc7f462..589aac71 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -523,7 +523,7 @@ void check_environment_vars(char **envp) { if (be_quiet) { return; } int index = 0, issue_detected = 0; - char *env, *val; + char *env, *val, *ignore = getenv("AFL_IGNORE_UNKNOWN_ENVS"); while ((env = envp[index++]) != NULL) { if (strncmp(env, "ALF_", 4) == 0 || strncmp(env, "_ALF", 4) == 0 || @@ -582,7 +582,7 @@ void check_environment_vars(char **envp) { } - if (match == 0) { + if (match == 0 && !ignore) { WARNF("Mistyped AFL environment variable: %s", env); issue_detected = 1; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index e4139857..e0ac8840 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -198,6 +198,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n" "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n" "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n" + "AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n" "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n" "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 0d2c5ceb..b40527d3 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1168,8 +1168,9 @@ int main(int argc, char **argv_orig, char **envp) { } - stdin_file = at_file ? strdup(at_file) : (char *) - alloc_printf("%s/.afl-showmap-temp-%u", use_dir, (u32)getpid()); + stdin_file = at_file ? strdup(at_file) + : (char *)alloc_printf("%s/.afl-showmap-temp-%u", + use_dir, (u32)getpid()); unlink(stdin_file); atexit(at_exit_handler); fsrv->out_file = stdin_file; -- cgit 1.4.1 From dd2fd8027454acaa5c12beea6f7b721fc8794715 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 15 Feb 2021 12:40:10 +0100 Subject: doc updates --- README.md | 5 +++-- docs/env_variables.md | 1 + qemu_mode/libqasan/README.md | 23 ++++++++++++++++------- qemu_mode/qemuafl | 2 +- 4 files changed, 21 insertions(+), 10 deletions(-) (limited to 'docs/env_variables.md') diff --git a/README.md b/README.md index 0778026c..00095390 100644 --- a/README.md +++ b/README.md @@ -751,6 +751,8 @@ campaigns as these are much shorter runnings. * for CMPLOG targets, 60% for `-l 2`, 40% for `-l 3` 4. Do *not* run any `-M` modes, just running `-S` modes is better for CI fuzzing. + `-M` enables deterministic fuzzing, old queue handling etc. which is good for + a fuzzing campaign but not good for short CI runs. ## Fuzzing binary-only targets @@ -788,8 +790,7 @@ If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for your binary, then you can use afl-fuzz normally and it will have twice the speed compared to qemu_mode (but slower than persistent mode). Note that several other binary rewriters exist, all with their advantages and -caveats. As rewriting a binary is much faster than Qemu this is a highly -recommended approach! +caveats. ### Unicorn diff --git a/docs/env_variables.md b/docs/env_variables.md index f7745247..f6ed12d0 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -451,6 +451,7 @@ checks or alter some of the more exotic semantics of the tool: `banner` corresponds to the name of the fuzzer provided through `-M/-S`. `afl_version` corresponds to the currently running afl version (e.g `++3.0c`). Default (empty/non present) will add no tags to the metrics. + See [rpc_statsd.md](rpc_statsd.md) for more information. - Setting `AFL_CRASH_EXITCODE` sets the exit code afl treats as crash. For example, if `AFL_CRASH_EXITCODE='-1'` is set, each input resulting diff --git a/qemu_mode/libqasan/README.md b/qemu_mode/libqasan/README.md index 83fb2442..4a241233 100644 --- a/qemu_mode/libqasan/README.md +++ b/qemu_mode/libqasan/README.md @@ -4,16 +4,25 @@ This library is the injected runtime used by QEMU AddressSanitizer (QASan). The original repository is [here](https://github.com/andreafioraldi/qasan). -The version embedded in qemuafl is an updated version of just the usermode part and this runtime is injected via LD_PRELOAD (so works just for dynamically linked binaries). +The version embedded in qemuafl is an updated version of just the usermode part +and this runtime is injected via LD_PRELOAD (so works just for dynamically +linked binaries). -The usage is super simple, just set the env var `AFL_USE_QASAN=1` when fuzzing in qemu mode (-Q). afl-fuzz will automatically set AFL_PRELOAD to load this library and enable the QASan instrumentation in afl-qemu-trace. +The usage is super simple, just set the env var `AFL_USE_QASAN=1` when fuzzing +in qemu mode (-Q). afl-fuzz will automatically set AFL_PRELOAD to load this +library and enable the QASan instrumentation in afl-qemu-trace. -For debugging purposes, we still suggest to run the original QASan as the stacktrace support for ARM (just a debug feature, it does not affect the bug finding capabilities during fuzzing) is WIP. +For debugging purposes, we still suggest to run the original QASan as the +stacktrace support for ARM (just a debug feature, it does not affect the bug +finding capabilities during fuzzing) is WIP. -### When I should use QASan? +### When should I use QASan? -If your target binary is PIC x86_64, you should also give a try to [retrowrite](https://github.com/HexHive/retrowrite) for static rewriting. +If your target binary is PIC x86_64, you should also give a try to +[retrowrite](https://github.com/HexHive/retrowrite) for static rewriting. -If it fails, or if your binary is for another architecture, or you want to use persistent and snapshot mode, AFL++ QASan mode is what you want/have to use. +If it fails, or if your binary is for another architecture, or you want to use +persistent and snapshot mode, AFL++ QASan mode is what you want/have to use. -Note that the overhead of libdislocator when combined with QEMU mode is much lower but it can catch less bugs. This is a short blanket, take your choice. +Note that the overhead of libdislocator when combined with QEMU mode is much +lower but it can catch less bugs. This is a short blanket, take your choice. diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index 213f3b27..9a258d5b 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit 213f3b27dd099ef352181c48cd75c0f20a73e3f0 +Subproject commit 9a258d5b7a38c045a6e385fcfcf80a746a60e557 -- cgit 1.4.1 From 47f2650a32470172a32c4ebd446003cb8a4b80e8 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 9 Mar 2021 16:53:56 +0100 Subject: add AFL_NOOPT --- README.md | 17 +++++++++++++---- docs/env_variables.md | 11 +++++++++++ include/envs.h | 4 +++- src/afl-cc.c | 21 +++++++++++++++++++-- src/afl-common.c | 1 + 5 files changed, 47 insertions(+), 7 deletions(-) (limited to 'docs/env_variables.md') diff --git a/README.md b/README.md index 6b11fee4..d4e39566 100644 --- a/README.md +++ b/README.md @@ -399,10 +399,19 @@ How to do this is described below. Then build the target. (Usually with `make`) -**NOTE**: sometimes configure and build systems are fickle and do not like -stderr output (and think this means a test failure) - which is something -afl++ like to do to show statistics. It is recommended to disable them via -`export AFL_QUIET=1`. +**NOTES** + +1. sometimes configure and build systems are fickle and do not like + stderr output (and think this means a test failure) - which is something + afl++ like to do to show statistics. It is recommended to disable them via + `export AFL_QUIET=1`. + +2. sometimes configure and build systems error on warnings - these should be + disabled (e.g. `--disable-werror` for some configure scripts` + +3. in case the configure/build system complains about afl++'s compiler and + aborts then set `export AFL_NOOPT=1` which will then just behave like the + real compiler. This option has to be unset again before building the target! ##### configure diff --git a/docs/env_variables.md b/docs/env_variables.md index f6ed12d0..a20f1e42 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -26,6 +26,17 @@ Because (with the exception of the --afl-MODE command line option) the compile-time tools do not accept afl specific command-line options, they make fairly broad use of environmental variables instead: + - Some build/configure scripts break with afl++ compilers. To be able to + pass them, do: +``` + export CC=afl-cc + export CXX=afl-c++ + export AFL_NOOPT=1 + ./configure --disable-shared --disabler-werror + unset AFL_NOOPT + make +``` + - Most afl tools do not print any output if stdout/stderr are redirected. If you want to get the output into a file then set the `AFL_DEBUG` environment variable. diff --git a/include/envs.h b/include/envs.h index e8595ef7..37748a56 100644 --- a/include/envs.h +++ b/include/envs.h @@ -119,10 +119,12 @@ static char *afl_environment_variables[] = { "AFL_NO_PYTHON", "AFL_UNTRACER_FILE", "AFL_LLVM_USE_TRACE_PC", - "AFL_NO_X86", // not really an env but we dont want to warn on it "AFL_MAP_SIZE", "AFL_MAPSIZE", "AFL_MAX_DET_EXTRAS", + "AFL_NO_X86", // not really an env but we dont want to warn on it + "AFL_NOOPT", + "AFL_PASSTHROUGH", "AFL_PATH", "AFL_PERFORMANCE_FILE", "AFL_PRELOAD", diff --git a/src/afl-cc.c b/src/afl-cc.c index bb136fb9..8f9bb397 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1025,7 +1025,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { int main(int argc, char **argv, char **envp) { - int i; + int i, passthrough = 0; char *callname = argv[0], *ptr = NULL; if (getenv("AFL_DEBUG")) { @@ -1045,6 +1045,13 @@ int main(int argc, char **argv, char **envp) { } + if (getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) { + + passthrough = 1; + if (!debug) { be_quiet = 1; } + + } + if ((ptr = strrchr(callname, '/')) != NULL) callname = ptr + 1; argvnull = (u8 *)argv[0]; check_environment_vars(envp); @@ -1665,6 +1672,7 @@ int main(int argc, char **argv, char **envp) { " AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n" " AFL_NO_BUILTIN: no builtins for string compare functions (for " "libtokencap.so)\n" + " AFL_NOOP: behave lik a normal compiler (to pass configure tests)\n" " AFL_PATH: path to instrumenting pass and runtime " "(afl-compiler-rt.*o)\n" " AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n" @@ -1977,7 +1985,16 @@ int main(int argc, char **argv, char **envp) { } - execvp(cc_params[0], (char **)cc_params); + if (passthrough) { + + argv[0] = cc_params[0]; + execvp(cc_params[0], (char **)argv); + + } else { + + execvp(cc_params[0], (char **)cc_params); + + } FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); diff --git a/src/afl-common.c b/src/afl-common.c index a306fe5e..68f82a5e 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -682,6 +682,7 @@ void check_environment_vars(char **envp) { env[strlen(afl_environment_variables[i])] == '=') { match = 1; + if ((val = getenv(afl_environment_variables[i])) && !*val) { WARNF( -- cgit 1.4.1 From d4fb7f8b4015297e1c74b28d671eba058cfb6366 Mon Sep 17 00:00:00 2001 From: realmadsci <71108352+realmadsci@users.noreply.github.com> Date: Fri, 12 Mar 2021 15:53:42 -0500 Subject: Add AFL_QEMU_CUSTOM_BIN environment flag In QEMU mode (-Q), setting AFL_QEMU_CUSTOM_BIN cause afl-fuzz to skip prepending afl-qemu-trace to your command line. Use this if you wish to use a custom afl-qemu-trace or if you need to modify the afl-qemu-trace arguments. --- docs/env_variables.md | 4 ++++ include/envs.h | 1 + src/afl-common.c | 7 +++++++ src/afl-fuzz-init.c | 1 + 4 files changed, 13 insertions(+) (limited to 'docs/env_variables.md') diff --git a/docs/env_variables.md b/docs/env_variables.md index a20f1e42..c6ad0aa4 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -393,6 +393,10 @@ checks or alter some of the more exotic semantics of the tool: - In QEMU mode (-Q), `AFL_PATH` will be searched for afl-qemu-trace. + - In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` cause afl-fuzz to skip + prepending `afl-qemu-trace` to your command line. Use this if you wish to use a + custom afl-qemu-trace or if you need to modify the afl-qemu-trace arguments. + - Setting `AFL_CYCLE_SCHEDULES` will switch to a different schedule everytime a cycle is finished. diff --git a/include/envs.h b/include/envs.h index 4d4d6b0e..e92bee2a 100644 --- a/include/envs.h +++ b/include/envs.h @@ -130,6 +130,7 @@ static char *afl_environment_variables[] = { "AFL_PERFORMANCE_FILE", "AFL_PRELOAD", "AFL_PYTHON_MODULE", + "AFL_QEMU_CUSTOM_BIN", "AFL_QEMU_COMPCOV", "AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS", diff --git a/src/afl-common.c b/src/afl-common.c index 9f6eb564..58fbf765 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -149,6 +149,13 @@ void argv_cpy_free(char **argv) { char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { + if (unlikely(getenv("AFL_QEMU_CUSTOM_BIN"))) { + WARNF( + "AFL_QEMU_CUSTOM_BIN is enabled. " + "You must run your target under afl-qemu-trace on your own!"); + return argv; + } + if (!unlikely(own_loc)) { FATAL("BUG: param own_loc is NULL"); } u8 *tmp, *cp = NULL, *rsl, *own_copy; diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index ca2f75f1..82c1799e 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2592,6 +2592,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { } if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode || + (afl->fsrv.qemu_mode && getenv("AFL_QEMU_CUSTOM_BIN")) || afl->non_instrumented_mode) { return; -- cgit 1.4.1