diff options
78 files changed, 1601 insertions, 688 deletions
diff --git a/Android.bp b/Android.bp index 2c2114b2..5d6f0433 100644 --- a/Android.bp +++ b/Android.bp @@ -1,7 +1,16 @@ cc_defaults { name: "afl-defaults", + sanitize: { + never: true, + }, + + local_include_dirs: [ + "include", + "instrumentation", + ], cflags: [ + "-flto=full", "-funroll-loops", "-Wno-pointer-sign", "-Wno-pointer-arith", @@ -10,16 +19,22 @@ cc_defaults { "-Wno-unused-function", "-Wno-format", "-Wno-user-defined-warnings", - "-DUSE_TRACE_PC=1", + "-DAFL_LLVM_USE_TRACE_PC=1", "-DBIN_PATH=\"out/host/linux-x86/bin\"", "-DDOC_PATH=\"out/host/linux-x86/shared/doc/afl\"", "-D__USE_GNU", + "-D__aarch64__", + "-DDEBUG_BUILD", + "-U_FORTIFY_SOURCE", + "-ggdb3", + "-g", + "-O0", + "-fno-omit-frame-pointer", ], } cc_binary { name: "afl-fuzz", - static_executable: true, host_supported: true, defaults: [ @@ -27,7 +42,11 @@ cc_binary { ], srcs: [ - "afl-fuzz.c", + "src/afl-fuzz*.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", + "src/afl-performance.c", ], } @@ -41,7 +60,10 @@ cc_binary { ], srcs: [ - "afl-showmap.c", + "src/afl-showmap.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", ], } @@ -55,7 +77,11 @@ cc_binary { ], srcs: [ - "afl-tmin.c", + "src/afl-tmin.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-forkserver.c", + "src/afl-performance.c", ], } @@ -69,7 +95,10 @@ cc_binary { ], srcs: [ - "afl-analyze.c", + "src/afl-analyze.c", + "src/afl-common.c", + "src/afl-sharedmem.c", + "src/afl-performance.c", ], } @@ -83,12 +112,13 @@ cc_binary { ], srcs: [ - "afl-gotcpu.c", + "src/afl-gotcpu.c", + "src/afl-common.c", ], } cc_binary_host { - name: "afl-clang-fast", + name: "afl-cc", static_executable: true, defaults: [ @@ -98,44 +128,144 @@ cc_binary_host { cflags: [ "-D__ANDROID__", "-DAFL_PATH=\"out/host/linux-x86/lib64\"", + "-DAFL_CLANG_FLTO=\"-flto=full\"", + "-DUSE_BINDIR=1", + "-DLLVM_BINDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin\"", + "-DLLVM_LIBDIR=\"prebuilts/clang/host/linux-x86/clang-r383902b/lib64\"", + "-DCLANGPP_BIN=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/clang++\"", + "-DAFL_REAL_LD=\"prebuilts/clang/host/linux-x86/clang-r383902b/bin/ld.lld\"", + "-DLLVM_LTO=1", + "-DLLVM_MAJOR=11", + "-DLLVM_MINOR=2", ], srcs: [ "src/afl-cc.c", + "src/afl-common.c", + ], + + symlinks: [ + "afl-clang-fast", + "afl-clang-fast++", ], } -cc_binary_host { - name: "afl-clang-fast++", - static_executable: true, +cc_library_static { + name: "afl-llvm-rt", + compile_multilib: "both", + vendor_available: true, + host_supported: true, + recovery_available: true, + sdk_version: "9", - defaults: [ - "afl-defaults", + apex_available: [ + "com.android.adbd", + "com.android.appsearch", + "com.android.art", + "com.android.bluetooth.updatable", + "com.android.cellbroadcast", + "com.android.conscrypt", + "com.android.extservices", + "com.android.cronet", + "com.android.neuralnetworks", + "com.android.media", + "com.android.media.swcodec", + "com.android.mediaprovider", + "com.android.permission", + "com.android.runtime", + "com.android.resolv", + "com.android.tethering", + "com.android.wifi", + "com.android.sdkext", + "com.android.os.statsd", + "//any", ], - cflags: [ - "-D__ANDROID__", - "-DAFL_PATH=\"out/host/linux-x86/lib64\"", + defaults: [ + "afl-defaults", ], srcs: [ - "src/afl-cc.c", + "instrumentation/afl-compiler-rt.o.c", ], } -cc_library_static { - name: "afl-llvm-rt", - compile_multilib: "both", +cc_library_headers { + name: "libafl_headers", vendor_available: true, host_supported: true, - recovery_available: true, - sdk_version: "9", + + export_include_dirs: [ + "include", + ], +} + +cc_prebuilt_library_static { + name: "libfrida-gum", + compile_multilib: "64", + strip: { + none: true, + }, + + srcs: [ + "utils/afl_frida/android/libfrida-gum.a", + ], + + export_include_dirs: [ + "utils/afl_frida/android", + ], +} + +cc_library_shared { + name: "libtestinstr", + + srcs: [ + "utils/afl_frida/libtestinstr.c", + ], + + cflags: [ + "-O0", + "-fPIC", + ], +} + +cc_binary { + name: "afl-frida", + compile_multilib: "64", defaults: [ "afl-defaults", ], + cflags: [ + "-g", + "-O0", + "-Wno-format", + "-Wno-pointer-sign", + "-fpermissive", + "-fPIC", + ], + + static_libs: [ + "afl-llvm-rt", + "libfrida-gum", + ], + + shared_libs: [ + "libdl", + "liblog", + ], + srcs: [ - "instrumentation/afl-llvm-rt.o.c", + "utils/afl_frida/afl-frida.c", + ], + + local_include_dirs: [ + "utils/afl_frida", + "utils/afl_frida/android", ], } + +subdirs = [ + "custom_mutators", +] diff --git a/Android.mk b/Android.mk deleted file mode 120000 index 33ceb8f0..00000000 --- a/Android.mk +++ /dev/null @@ -1 +0,0 @@ -Makefile \ No newline at end of file diff --git a/README.md b/README.md index 4aeb0699..ce48f336 100644 --- a/README.md +++ b/README.md @@ -505,10 +505,6 @@ more useful. If you just use one CPU for fuzzing, then you are fuzzing just for fun and not seriously :-) -Pro tip: load the [afl++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM) -before the start of afl-fuzz as this improves performance by a x2 speed increase -(less if you use a persistent mode harness)! - #### a) Running afl-fuzz Before you do even a test run of afl-fuzz execute `sudo afl-system-config` (on @@ -591,13 +587,17 @@ For every secondary fuzzer there should be a variation, e.g.: All other secondaries should be used like this: * A third to a half with the MOpt mutator enabled: `-L 0` * run with a different power schedule, available are: - `explore (default), fast, coe, lin, quad, exploit, mmopt, rare, seek` + `fast (default), explore, coe, lin, quad, exploit, mmopt, rare, seek` which you can set with e.g. `-p seek` +Also it is recommended to set `export AFL_IMPORT_FIRST=1` to load testcases +from other fuzzers in the campaign first. + You can also use different fuzzers. If you are using afl spinoffs or afl conforming fuzzers, then just use the same -o directory and give it a unique `-S` name. Examples are: + * [Eclipser](https://github.com/SoftSec-KAIST/Eclipser/) * [Untracer](https://github.com/FoRTE-Research/UnTracer-AFL) * [AFLsmart](https://github.com/aflsmart/aflsmart) * [FairFuzz](https://github.com/carolemieux/afl-rb) @@ -607,7 +607,7 @@ Examples are: A long list can be found at [https://github.com/Microsvuln/Awesome-AFL](https://github.com/Microsvuln/Awesome-AFL) However you can also sync afl++ with honggfuzz, libfuzzer with -entropic, etc. -Just show the main fuzzer (-M) with the `-F` option where the queue +Just show the main fuzzer (-M) with the `-F` option where the queue/work directory of a different fuzzer is, e.g. `-F /src/target/honggfuzz`. #### c) The status of the fuzz campaign @@ -672,7 +672,6 @@ switch or honggfuzz. * Use [persistent mode](instrumentation/README.persistent_mode.md) (x2-x20 speed increase) * 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) - * Linux: Use the [afl++ snapshot module](https://github.com/AFLplusplus/AFL-Snapshot-LKM) (x2 speed increase) * Linux: 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) * Linux: Running on an `ext2` filesystem with `noatime` mount option will be a bit faster than on any other journaling filesystem * Use your cores! [3.b) Using multiple cores/threads](#b-using-multiple-coresthreads) @@ -1108,7 +1107,7 @@ without feedback, bug reports, or patches from: Khaled Yakdan Kuang-che Wu Josephine Calliotte Konrad Welc Thomas Rooijakkers David Carlier - Ruben ten Hove + Ruben ten Hove Joey Jiao ``` Thank you! 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 <out_dir>/.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/afl-system-config b/afl-system-config index 7031544c..456cccac 100755 --- a/afl-system-config +++ b/afl-system-config @@ -58,6 +58,11 @@ if [ "$PLATFORM" = "OpenBSD" ] ; then echo 'System security features cannot be disabled on OpenBSD.' DONE=1 fi +if [ "$PLATFORM" = "DragonFly" ] ; then + echo + echo 'System security features cannot be disabled on DragonFly.' + DONE=1 +fi if [ "$PLATFORM" = "NetBSD" ] ; then { #echo It is recommended to enable unprivileged users to set cpu affinity @@ -79,5 +84,14 @@ if [ "$PLATFORM" = "Darwin" ] ; then fi DONE=1 fi +if [ "$PLATFORM" = "Haiku" ] ; then + SETTINGS=~/config/settings/system/debug_server/settings + [ -r ${SETTINGS} ] && grep -qE "default_action\s+kill" ${SETTINGS} && { echo "Nothing to do"; } || { \ + echo We change the debug_server default_action from user to silenty kill; \ + [ ! -r ${SETTINGS} ] && echo "default_action kill" >${SETTINGS} || { mv ${SETTINGS} s.tmp; sed -e "s/default_action\s\s*user/default_action kill/" s.tmp > ${SETTINGS}; rm s.tmp; }; \ + echo Settings applied.; \ + } + DONE=1 +fi test -z "$DONE" && echo Error: Unknown platform: $PLATFORM exit 0 diff --git a/afl-wine-trace b/afl-wine-trace index 8853a757..63ff896b 100755 --- a/afl-wine-trace +++ b/afl-wine-trace @@ -28,9 +28,9 @@ if not os.getenv("AFL_INST_LIBS"): os.environ["AFL_CODE_END"] = "0x%x" % (pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.BaseOfCode + pe.OPTIONAL_HEADER.SizeOfCode) if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"] or pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]: - os.environ["LD_PRELOAD"] = os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so") + os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction64.so") + ",WINEARCH=win64" else: - os.environ["LD_PRELOAD"] = os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so") + os.environ["QEMU_SET_ENV"] = "LD_PRELOAD=" + os.path.join(my_dir, "qemu_mode/unsigaction/unsigaction32.so") + ",WINEARCH=win32" if os.getenv("WINECOV_QEMU_PATH"): qemu_path = os.getenv("WINECOV_QEMU_PATH") diff --git a/custom_mutators/Android.bp b/custom_mutators/Android.bp new file mode 100644 index 00000000..89abc3e9 --- /dev/null +++ b/custom_mutators/Android.bp @@ -0,0 +1,115 @@ +cc_library_shared { + name: "libfuzzer-mutator", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-funroll-loops", + "-fPIC", + "-fpermissive", + "-std=c++11", + ], + + srcs: [ + "libfuzzer/FuzzerCrossOver.cpp", + "libfuzzer/FuzzerDataFlowTrace.cpp", + "libfuzzer/FuzzerDriver.cpp", + "libfuzzer/FuzzerExtFunctionsDlsym.cpp", + "libfuzzer/FuzzerExtFunctionsWeak.cpp", + "libfuzzer/FuzzerExtFunctionsWindows.cpp", + "libfuzzer/FuzzerExtraCounters.cpp", + "libfuzzer/FuzzerFork.cpp", + "libfuzzer/FuzzerIO.cpp", + "libfuzzer/FuzzerIOPosix.cpp", + "libfuzzer/FuzzerIOWindows.cpp", + "libfuzzer/FuzzerLoop.cpp", + "libfuzzer/FuzzerMerge.cpp", + "libfuzzer/FuzzerMutate.cpp", + "libfuzzer/FuzzerSHA1.cpp", + "libfuzzer/FuzzerTracePC.cpp", + "libfuzzer/FuzzerUtil.cpp", + "libfuzzer/FuzzerUtilDarwin.cpp", + "libfuzzer/FuzzerUtilFuchsia.cpp", + "libfuzzer/FuzzerUtilLinux.cpp", + "libfuzzer/FuzzerUtilPosix.cpp", + "libfuzzer/FuzzerUtilWindows.cpp", + "libfuzzer/libfuzzer.cpp", + ], + + header_libs: [ + "libafl_headers", + ], +} + +/*cc_library_shared { + name: "honggfuzz-mutator", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-funroll-loops", + "-fPIC", + "-Wl,-Bsymbolic", + ], + + srcs: [ + "honggfuzz/honggfuzz.c", + "honggfuzz/mangle.c", +// "../src/afl-perfomance.c", + ], + + header_libs: [ + "libafl_headers", + ], +}*/ + +cc_library_shared { + name: "radamsa-mutator", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-funroll-loops", + "-fPIC", + ], + + srcs: [ + "radamsa/libradamsa.c", + "radamsa/radamsa-mutator.c", + ], + + header_libs: [ + "libafl_headers", + ], +} + +cc_library_shared { + name: "symcc-mutator", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-funroll-loops", + "-fPIC", + ], + + srcs: [ + "symcc/symcc.c", + ], + + header_libs: [ + "libafl_headers", + ], +} + +subdirs = [ + "libprotobuf-mutator-example", +] diff --git a/custom_mutators/honggfuzz/mangle.c b/custom_mutators/honggfuzz/mangle.c index c2988319..9c3d1ed4 100644 --- a/custom_mutators/honggfuzz/mangle.c +++ b/custom_mutators/honggfuzz/mangle.c @@ -995,7 +995,7 @@ void mangle_mangleContent(run_t *run, int speed_factor) { } - uint64_t changesCnt = run->global->mutate.mutationsPerRun; + uint64_t changesCnt; if (speed_factor < 5) { diff --git a/custom_mutators/libfuzzer/FuzzerDataFlowTrace.cpp b/custom_mutators/libfuzzer/FuzzerDataFlowTrace.cpp index 797a52a7..489665f7 100644 --- a/custom_mutators/libfuzzer/FuzzerDataFlowTrace.cpp +++ b/custom_mutators/libfuzzer/FuzzerDataFlowTrace.cpp @@ -246,7 +246,7 @@ bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction, } - if (!NumFunctions || FocusFuncIdx == SIZE_MAX || Files.size() <= 1) + if (FocusFuncIdx == SIZE_MAX || Files.size() <= 1) return false; // Read traces. @@ -259,8 +259,8 @@ bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction, if (!CorporaHashes.count(Name)) continue; // not in the corpus. NumTraceFiles++; // Printf("=== %s\n", Name.c_str()); - std::ifstream IF(SF.File); - while (std::getline(IF, L, '\n')) { + std::ifstream IF2(SF.File); + while (std::getline(IF2, L, '\n')) { size_t FunctionNum = 0; std::string DFTString; @@ -314,8 +314,8 @@ int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath, // we then request tags in [0,Size/2) and [Size/2, Size), and so on. // Function number => DFT. auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File))); - std::unordered_map<size_t, Vector<uint8_t>> DFTMap; - std::unordered_set<std::string> Cov; +// std::unordered_map<size_t, Vector<uint8_t>> DFTMap; +// std::unordered_set<std::string> Cov; Command Cmd; Cmd.addArgument(DFTBinary); Cmd.addArgument(F.File); diff --git a/custom_mutators/libfuzzer/FuzzerDefs.h b/custom_mutators/libfuzzer/FuzzerDefs.h index 1a2752af..3952ac51 100644 --- a/custom_mutators/libfuzzer/FuzzerDefs.h +++ b/custom_mutators/libfuzzer/FuzzerDefs.h @@ -46,7 +46,7 @@ template<typename T> fuzzer_allocator() = default; template<class U> - fuzzer_allocator(const fuzzer_allocator<U>&) {} + explicit fuzzer_allocator(const fuzzer_allocator<U>&) {} template<class Other> struct rebind { typedef fuzzer_allocator<Other> other; }; diff --git a/custom_mutators/libfuzzer/FuzzerDictionary.h b/custom_mutators/libfuzzer/FuzzerDictionary.h index 301c5d9a..ddd2d2f1 100644 --- a/custom_mutators/libfuzzer/FuzzerDictionary.h +++ b/custom_mutators/libfuzzer/FuzzerDictionary.h @@ -49,7 +49,7 @@ typedef FixedWord<64> Word; class DictionaryEntry { public: DictionaryEntry() {} - DictionaryEntry(Word W) : W(W) {} + explicit DictionaryEntry(Word W) : W(W) {} DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {} const Word &GetW() const { return W; } @@ -92,7 +92,7 @@ class Dictionary { assert(Idx < Size); return DE[Idx]; } - void push_back(DictionaryEntry DE) { + void push_back(const DictionaryEntry &DE) { if (Size < kMaxDictSize) this->DE[Size++] = DE; } diff --git a/custom_mutators/libfuzzer/FuzzerRandom.h b/custom_mutators/libfuzzer/FuzzerRandom.h index 659283ee..7b1e1b1d 100644 --- a/custom_mutators/libfuzzer/FuzzerRandom.h +++ b/custom_mutators/libfuzzer/FuzzerRandom.h @@ -16,7 +16,7 @@ namespace fuzzer { class Random : public std::minstd_rand { public: - Random(unsigned int seed) : std::minstd_rand(seed) {} + explicit Random(unsigned int seed) : std::minstd_rand(seed) {} result_type operator()() { return this->std::minstd_rand::operator()(); } size_t Rand() { return this->operator()(); } size_t RandBool() { return Rand() % 2; } diff --git a/custom_mutators/libfuzzer/FuzzerTracePC.h b/custom_mutators/libfuzzer/FuzzerTracePC.h index 4601300c..a58fdf8d 100644 --- a/custom_mutators/libfuzzer/FuzzerTracePC.h +++ b/custom_mutators/libfuzzer/FuzzerTracePC.h @@ -145,10 +145,10 @@ private: }; Region *Regions; size_t NumRegions; - uint8_t *Start() { return Regions[0].Start; } - uint8_t *Stop() { return Regions[NumRegions - 1].Stop; } - size_t Size() { return Stop() - Start(); } - size_t Idx(uint8_t *P) { + uint8_t *Start() const { return Regions[0].Start; } + uint8_t *Stop() const { return Regions[NumRegions - 1].Stop; } + size_t Size() const { return Stop() - Start(); } + size_t Idx(uint8_t *P) const { assert(P >= Start() && P < Stop()); return P - Start(); } diff --git a/custom_mutators/libprotobuf-mutator-example/Android.bp b/custom_mutators/libprotobuf-mutator-example/Android.bp new file mode 100644 index 00000000..01f1c23e --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/Android.bp @@ -0,0 +1,32 @@ +cc_library_shared { + name: "libprotobuf-mutator-example-afl", + vendor_available: true, + host_supported: true, + + cflags: [ + "-g", + "-O0", + "-fPIC", + "-Wall", + ], + + srcs: [ + "lpm_aflpp_custom_mutator_input.cc", + "test.proto", + ], + + shared_libs: [ + "libprotobuf-cpp-full", + "libprotobuf-mutator", + ], +} + +cc_binary { + name: "libprotobuf-mutator-vuln", + vendor_available: true, + host_supported: true, + + srcs: [ + "vuln.c", + ], +} diff --git a/custom_mutators/libprotobuf-mutator-example/README.md b/custom_mutators/libprotobuf-mutator-example/README.md new file mode 100644 index 00000000..5a844c00 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/README.md @@ -0,0 +1 @@ +Ported from [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/5_libprotobuf_aflpp_custom_mutator_input](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/5_libprotobuf_aflpp_custom_mutator_input) diff --git a/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.cc b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.cc new file mode 100644 index 00000000..e0273849 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.cc @@ -0,0 +1,118 @@ +#include "lpm_aflpp_custom_mutator_input.h" +#include <iostream> +#include <sstream> +#include <fstream> + +using std::cin; +using std::cout; +using std::endl; + +std::string ProtoToData(const TEST &test_proto) { + std::stringstream all; + const auto &aa = test_proto.a(); + const auto &bb = test_proto.b(); + all.write((const char*)&aa, sizeof(aa)); + if(bb.size() != 0) { + all.write(bb.c_str(), bb.size()); + } + + std::string res = all.str(); + if (bb.size() != 0 && res.size() != 0) { + // set PROTO_FUZZER_DUMP_PATH env to dump the serialized protobuf + if (const char *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) { + std::ofstream of(dump_path); + of.write(res.data(), res.size()); + } + } + return res; +} + +/** + * 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. + */ +extern "C" MyMutator *afl_custom_init(void *afl, unsigned int seed) { + MyMutator *mutator = new MyMutator(); + + mutator->RegisterPostProcessor( + TEST::descriptor(), + [](google::protobuf::Message* message, unsigned int seed) { + // libprotobuf-mutator's built-in mutator is kind of....crappy :P + // Even a dumb fuzz like `TEST.a = rand();` is better in this case... Q_Q + // We register a post processor to apply our dumb fuzz + + TEST *t = static_cast<TEST *>(message); + t->set_a(rand()); + }); + + srand(seed); + return mutator; +} + +/** + * Perform custom mutations on a given input + * + * @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. + */ +extern "C" size_t afl_custom_fuzz(MyMutator *mutator, // return value from afl_custom_init + uint8_t *buf, size_t buf_size, // input data to be mutated + uint8_t **out_buf, // output buffer + uint8_t *add_buf, size_t add_buf_size, // add_buf can be NULL + size_t max_size) { + // This function can be named either "afl_custom_fuzz" or "afl_custom_mutator" + // A simple test shows that "buf" will be the content of the current test case + // "add_buf" will be the next test case ( from AFL++'s input queue ) + + TEST input; + // parse input data to TEST + // Notice that input data should be a serialized protobuf data + // Check ./in/ii and test_protobuf_serializer for more detail + bool parse_ok = input.ParseFromArray(buf, buf_size); + if(!parse_ok) { + // Invalid serialize protobuf data. Don't mutate. + // Return a dummy buffer. Also mutated_size = 0 + static uint8_t *dummy = new uint8_t[10]; // dummy buffer with no data + *out_buf = dummy; + return 0; + } + // mutate the protobuf + mutator->Mutate(&input, max_size); + + // Convert protobuf to raw data + const TEST *p = &input; + std::string s = ProtoToData(*p); + // Copy to a new buffer ( mutated_out ) + size_t mutated_size = s.size() <= max_size ? s.size() : max_size; // check if raw data's size is larger than max_size + uint8_t *mutated_out = new uint8_t[mutated_size+1]; + memcpy(mutated_out, s.c_str(), mutated_size); // copy the mutated data + // Assign the mutated data and return mutated_size + *out_buf = mutated_out; + return mutated_size; +} + +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +extern "C" void afl_custom_deinit(void *data) { + // Honestly I don't know what to do with this... + return; +} + diff --git a/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.h b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.h new file mode 100644 index 00000000..ebd3ca65 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/lpm_aflpp_custom_mutator_input.h @@ -0,0 +1,5 @@ +#include <src/mutator.h> +#include "test.pb.h" + +class MyMutator : public protobuf_mutator::Mutator { +}; diff --git a/custom_mutators/libprotobuf-mutator-example/test.proto b/custom_mutators/libprotobuf-mutator-example/test.proto new file mode 100644 index 00000000..e2256c6e --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/test.proto @@ -0,0 +1,7 @@ +syntax = "proto2"; + +message TEST { + required uint32 a = 1; + required string b = 2; +} + diff --git a/custom_mutators/libprotobuf-mutator-example/vuln.c b/custom_mutators/libprotobuf-mutator-example/vuln.c new file mode 100644 index 00000000..8ffb7080 --- /dev/null +++ b/custom_mutators/libprotobuf-mutator-example/vuln.c @@ -0,0 +1,17 @@ +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <stdlib.h> +#include <unistd.h> + +int main(int argc, char *argv[]) +{ + char str[100]={}; + read(0, str, 100); + int *ptr = NULL; + if( str[0] == '\x02' || str[0] == '\xe8') { + *ptr = 123; + } + return 0; +} + diff --git a/docs/Changelog.md b/docs/Changelog.md index 71846535..60f09ca5 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,17 +9,24 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to <afl-users+subscribe@googlegroups.com>. -### Version ++3.01a (release) +### Version ++3.01a (dev) - Mac OS ARM64 support + - New selective instrumentation option with __AFL_COVERAGE_... commands + to be placed in the source code. + Check out instrumentation/README.instrument_list.md - afl-fuzz - 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 + after every queue entry as this can take very long time otherwise + - better detection if a target needs a large shared map - switched to a faster RNG - added hghwng's patch for faster trace map analysis - afl-cc - allow instrumenting LLVMFuzzerTestOneInput - fixed endless loop for allow/blocklist lines starting with a comment (thanks to Zherya for reporting) + - cmplog/redqueen now also tracks floats/doubles - added AFL_LLVM_INSTRUMENT option NATIVE for native clang pc-guard support (less performant than our own), GCC for old afl-gcc and CLANG for old afl-clang @@ -28,7 +35,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. 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/docs/power_schedules.md b/docs/power_schedules.md index 06fefa12..493f9609 100644 --- a/docs/power_schedules.md +++ b/docs/power_schedules.md @@ -13,8 +13,8 @@ We find that AFL's exploitation-based constant schedule assigns **too much energ | AFL flag | Power Schedule | | ------------- | -------------------------- | -| `-p explore` (default)|  | -| `-p fast` | =\\min\\left(\\frac{\\alpha(i)}{\\beta}\\cdot\\frac{2^{s(i)}}{f(i)},M\\right)) | +| `-p explore` |  | +| `-p fast` (default)| =\\min\\left(\\frac{\\alpha(i)}{\\beta}\\cdot\\frac{2^{s(i)}}{f(i)},M\\right)) | | `-p coe` |  | | `-p quad` |  | | `-p lin` |  | diff --git a/docs/status_screen.md b/docs/status_screen.md index 0cede6ff..0329d960 100644 --- a/docs/status_screen.md +++ b/docs/status_screen.md @@ -29,13 +29,18 @@ With that out of the way, let's talk about what's actually on the screen... ### The status bar +``` +american fuzzy lop ++3.01a (default) [fast] {0} +``` + The top line shows you which mode afl-fuzz is running in (normal: "american fuzy lop", crash exploration mode: "peruvian rabbit mode") and the version of afl++. Next to the version is the banner, which, if not set with -T by hand, will either show the binary name being fuzzed, or the -M/-S main/secondary name for parallel fuzzing. -Finally, the last item is the power schedule mode being run (default: explore). +Second to last is the power schedule mode being run (default: fast). +Finally, the last item is the CPU id. ### Process timing diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 0bf0aebe..6342c8b6 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -37,10 +37,6 @@ #define _FILE_OFFSET_BITS 64 #endif -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif - #include "config.h" #include "types.h" #include "debug.h" @@ -381,7 +377,7 @@ typedef struct afl_env_vars { *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, - *afl_testcache_entries; + *afl_testcache_entries, *afl_kill_signal; } afl_env_vars_t; @@ -573,7 +569,7 @@ typedef struct afl_state { u8 stage_name_buf[STAGE_BUF_SIZE]; /* reused stagename buf with len 64 */ - s32 stage_cur, stage_max; /* Stage progression */ + u32 stage_cur, stage_max; /* Stage progression */ s32 splicing_with; /* Splicing with which test case? */ u32 main_node_id, main_node_max; /* Main instance job splitting */ @@ -590,9 +586,9 @@ typedef struct afl_state { u32 rand_cnt; /* Random number counter */ -/* unsigned long rand_seed[3]; would also work */ + /* unsigned long rand_seed[3]; would also work */ AFL_RAND_RETURN rand_seed[3]; - s64 init_seed; + s64 init_seed; u64 total_cal_us, /* Total calibration time (us) */ total_cal_cycles; /* Total calibration cycles */ @@ -645,10 +641,10 @@ typedef struct afl_state { unsigned long long int last_avg_exec_update; u32 last_avg_execs; - float last_avg_execs_saved; + double last_avg_execs_saved; /* foreign sync */ -#define FOREIGN_SYNCS_MAX 32 +#define FOREIGN_SYNCS_MAX 32U u8 foreign_sync_cnt; struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX]; diff --git a/include/android-ashmem.h b/include/android-ashmem.h index 41d4d2da..6939e06d 100644 --- a/include/android-ashmem.h +++ b/include/android-ashmem.h @@ -1,112 +1,81 @@ -/* - american fuzzy lop++ - android shared memory compatibility layer - ---------------------------------------------------------------- - - Originally written by Michal Zalewski - - Now maintained by Marc Heuse <mh@mh-sec.de>, - Heiko Eißfeldt <heiko.eissfeldt@hexco.de>, - Andrea Fioraldi <andreafioraldi@gmail.com>, - Dominik Maier <mail@dmnk.co> - - Copyright 2016, 2017 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - This header re-defines the shared memory routines used by AFL++ - using the Andoid API. - - */ - +#ifdef __ANDROID__ #ifndef _ANDROID_ASHMEM_H #define _ANDROID_ASHMEM_H -#ifdef __ANDROID__ - - #include <fcntl.h> - #include <linux/shm.h> - #include <linux/ashmem.h> - #include <sys/ioctl.h> - #include <sys/mman.h> - - #if __ANDROID_API__ >= 26 - #define shmat bionic_shmat - #define shmctl bionic_shmctl - #define shmdt bionic_shmdt - #define shmget bionic_shmget - #endif - - #include <sys/shm.h> - #undef shmat - #undef shmctl - #undef shmdt - #undef shmget - #include <stdio.h> +#include <fcntl.h> +#include <linux/ashmem.h> +#include <sys/ioctl.h> +#include <sys/mman.h> - #define ASHMEM_DEVICE "/dev/ashmem" +#if __ANDROID_API__ >= 26 +#define shmat bionic_shmat +#define shmctl bionic_shmctl +#define shmdt bionic_shmdt +#define shmget bionic_shmget +#endif +#include <sys/shm.h> +#undef shmat +#undef shmctl +#undef shmdt +#undef shmget +#include <stdio.h> -static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { +#define ASHMEM_DEVICE "/dev/ashmem" +int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { int ret = 0; if (__cmd == IPC_RMID) { - - int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); - struct ashmem_pin pin = {0, (unsigned int)length}; + int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); + struct ashmem_pin pin = {0, length}; ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); close(__shmid); - } return ret; - } -static inline int shmget(key_t __key, size_t __size, int __shmflg) { - - (void)__shmflg; - int fd, ret; +int shmget(key_t __key, size_t __size, int __shmflg) { + (void) __shmflg; + int fd, ret; char ourkey[11]; fd = open(ASHMEM_DEVICE, O_RDWR); - if (fd < 0) return fd; + if (fd < 0) + return fd; sprintf(ourkey, "%d", __key); ret = ioctl(fd, ASHMEM_SET_NAME, ourkey); - if (ret < 0) goto error; + if (ret < 0) + goto error; ret = ioctl(fd, ASHMEM_SET_SIZE, __size); - if (ret < 0) goto error; + if (ret < 0) + goto error; return fd; error: close(fd); return ret; - } -static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { - - (void)__shmflg; - int size; +void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { + (void) __shmflg; + int size; void *ptr; size = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); - if (size < 0) { return NULL; } + if (size < 0) { + return NULL; + } ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, __shmid, 0); - if (ptr == MAP_FAILED) { return NULL; } + if (ptr == MAP_FAILED) { + return NULL; + } return ptr; - } -#endif /* __ANDROID__ */ - -#endif - +#endif /* !_ANDROID_ASHMEM_H */ +#endif /* !__ANDROID__ */ diff --git a/include/common.h b/include/common.h index 125c3abf..9490ec5f 100644 --- a/include/common.h +++ b/include/common.h @@ -56,6 +56,11 @@ extern u8 *doc_path; /* path to documentation dir */ u8 *find_binary(u8 *fname); +/* Parses the kill signal environment variable, FATALs on error. + If the env is not set, sets the env to default_signal for the signal handlers + and returns the default_signal. */ +int parse_afl_kill_signal_env(u8 *afl_kill_signal_env, int default_signal); + /* Read a bitmap from file fname to memory This is for the -B option again. */ diff --git a/include/config.h b/include/config.h index e8a49270..973bbcbb 100644 --- a/include/config.h +++ b/include/config.h @@ -80,11 +80,11 @@ /* Default timeout for fuzzed code (milliseconds). This is the upper bound, also used for detecting hangs; the actual value is auto-scaled: */ -#define EXEC_TIMEOUT 1000 +#define EXEC_TIMEOUT 1000U /* Timeout rounding factor when auto-scaling (milliseconds): */ -#define EXEC_TM_ROUND 20 +#define EXEC_TM_ROUND 20U /* 64bit arch MACRO */ #if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__)) @@ -93,48 +93,48 @@ /* Default memory limit for child process (MB) 0 = disabled : */ -#define MEM_LIMIT 0 +#define MEM_LIMIT 0U /* Default memory limit when running in QEMU mode (MB) 0 = disabled : */ -#define MEM_LIMIT_QEMU 0 +#define MEM_LIMIT_QEMU 0U /* Default memory limit when running in Unicorn mode (MB) 0 = disabled : */ -#define MEM_LIMIT_UNICORN 0 +#define MEM_LIMIT_UNICORN 0U /* Number of calibration cycles per every new test case (and for test cases that show variable behavior): */ -#define CAL_CYCLES 8 -#define CAL_CYCLES_LONG 40 +#define CAL_CYCLES 8U +#define CAL_CYCLES_LONG 40U /* Number of subsequent timeouts before abandoning an input file: */ -#define TMOUT_LIMIT 250 +#define TMOUT_LIMIT 250U /* Maximum number of unique hangs or crashes to record: */ -#define KEEP_UNIQUE_HANG 500 -#define KEEP_UNIQUE_CRASH 5000 +#define KEEP_UNIQUE_HANG 500U +#define KEEP_UNIQUE_CRASH 5000U /* Baseline number of random tweaks during a single 'havoc' stage: */ -#define HAVOC_CYCLES 256 -#define HAVOC_CYCLES_INIT 1024 +#define HAVOC_CYCLES 256U +#define HAVOC_CYCLES_INIT 1024U /* Maximum multiplier for the above (should be a power of two, beware of 32-bit int overflows): */ -#define HAVOC_MAX_MULT 64 -#define HAVOC_MAX_MULT_MOPT 64 +#define HAVOC_MAX_MULT 64U +#define HAVOC_MAX_MULT_MOPT 64U /* Absolute minimum number of havoc cycles (after all adjustments): */ -#define HAVOC_MIN 12 +#define HAVOC_MIN 12U /* Power Schedule Divisor */ -#define POWER_BETA 1 +#define POWER_BETA 1U #define MAX_FACTOR (POWER_BETA * 32) /* Maximum stacking for havoc-stage tweaks. The actual value is calculated @@ -146,19 +146,19 @@ In other words, the default (n = 4) produces 2, 4, 8, 16 stacked tweaks: */ -#define HAVOC_STACK_POW2 4 +#define HAVOC_STACK_POW2 4U /* Caps on block sizes for cloning and deletion operations. Each of these ranges has a 33% probability of getting picked, except for the first two cycles where smaller blocks are favored: */ -#define HAVOC_BLK_SMALL 32 -#define HAVOC_BLK_MEDIUM 128 -#define HAVOC_BLK_LARGE 1500 +#define HAVOC_BLK_SMALL 32U +#define HAVOC_BLK_MEDIUM 128U +#define HAVOC_BLK_LARGE 1500U /* Extra-large blocks, selected very rarely (<5% of the time): */ -#define HAVOC_BLK_XL 32768 +#define HAVOC_BLK_XL 32768U /* Probabilities of skipping non-favored entries in the queue, expressed as percentages: */ @@ -186,9 +186,11 @@ #define TRIM_START_STEPS 16 #define TRIM_END_STEPS 1024 -/* Maximum size of input file, in bytes (keep under 100MB): */ +/* Maximum size of input file, in bytes (keep under 100MB, default 1MB): + (note that if this value is changed, several areas in afl-cc.c, afl-fuzz.c + and afl-fuzz-state.c have to be changed as well! */ -#define MAX_FILE (1 * 1024 * 1024) +#define MAX_FILE (1 * 1024 * 1024U) /* The same, for the test case minimizer: */ @@ -380,7 +382,7 @@ after changing this - otherwise, SEGVs may ensue. */ #define MAP_SIZE_POW2 16 -#define MAP_SIZE (1 << MAP_SIZE_POW2) +#define MAP_SIZE (1U << MAP_SIZE_POW2) /* Maximum allocator request size (keep well under INT_MAX): */ diff --git a/include/debug.h b/include/debug.h index 7f4a6be1..ef5b195b 100644 --- a/include/debug.h +++ b/include/debug.h @@ -295,7 +295,7 @@ static inline const char *colorfilter(const char *x) { \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ "\n[-] PROGRAM ABORT : " cRST x); \ - SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __func__, \ + SAYF(cLRD "\n Location : " cRST "%s(), %s:%d\n\n", __func__, \ __FILE__, __LINE__); \ exit(1); \ \ @@ -308,7 +308,7 @@ static inline const char *colorfilter(const char *x) { \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ "\n[-] PROGRAM ABORT : " cRST x); \ - SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __func__, \ + SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%d\n\n", __func__, \ __FILE__, __LINE__); \ abort(); \ \ @@ -322,7 +322,7 @@ static inline const char *colorfilter(const char *x) { fflush(stdout); \ SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ "\n[-] SYSTEM ERROR : " cRST x); \ - SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __func__, \ + SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%d\n", __func__, \ __FILE__, __LINE__); \ SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \ exit(1); \ diff --git a/include/envs.h b/include/envs.h index e4e49c4d..97367fae 100644 --- a/include/envs.h +++ b/include/envs.h @@ -61,6 +61,7 @@ static char *afl_environment_variables[] = { "AFL_IMPORT_FIRST", "AFL_INST_LIBS", "AFL_INST_RATIO", + "AFL_KILL_SIGNAL", "AFL_KEEP_TRACES", "AFL_KEEP_ASSEMBLY", "AFL_LD_HARD_FAIL", diff --git a/include/forkserver.h b/include/forkserver.h index 8e029266..3019e289 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -99,6 +99,8 @@ typedef struct afl_forkserver { void (*add_extra_func)(void *afl_ptr, u8 *mem, u32 len); + u8 kill_signal; + } afl_forkserver_t; typedef enum fsrv_run_result { diff --git a/include/types.h b/include/types.h index 39f599a0..3e3bc953 100644 --- a/include/types.h +++ b/include/types.h @@ -50,7 +50,7 @@ typedef uint32_t u32; #define FS_OPT_SHDMEM_FUZZ 0x01000000 #define FS_OPT_OLD_AFLPP_WORKAROUND 0x0f000000 // FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22 -#define FS_OPT_MAX_MAPSIZE ((0x00fffffe >> 1) + 1) +#define FS_OPT_MAX_MAPSIZE ((0x00fffffeU >> 1) + 1) #define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1) #define FS_OPT_SET_MAPSIZE(x) \ (x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1)) diff --git a/instrumentation/LLVMInsTrim.so.cc b/instrumentation/LLVMInsTrim.so.cc index 6b3231e6..235ee30f 100644 --- a/instrumentation/LLVMInsTrim.so.cc +++ b/instrumentation/LLVMInsTrim.so.cc @@ -200,7 +200,7 @@ struct InsTrim : public ModulePass { LoadInst * PrevCtx = NULL; // for CTX sensitive coverage if (ctx_str) -#ifdef __ANDROID__ +#if defined(__ANDROID__) || defined(__HAIKU__) AFLContext = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx"); #else @@ -211,7 +211,7 @@ struct InsTrim : public ModulePass { #ifdef AFL_HAVE_VECTOR_INTRINSICS if (ngram_size) - #ifdef __ANDROID__ + #if defined(__ANDROID__) || defined(__HAIKU__) AFLPrevLoc = new GlobalVariable( M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, /* Initializer */ nullptr, "__afl_prev_loc"); @@ -224,7 +224,7 @@ struct InsTrim : public ModulePass { #endif else #endif -#ifdef __ANDROID__ +#if defined(__ANDROID__) || defined(__HAIKU__) AFLPrevLoc = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); #else @@ -407,10 +407,10 @@ struct InsTrim : public ModulePass { // does the function have calls? and is any of the calls larger than // one basic block? has_calls = 0; - for (auto &BB : F) { + for (auto &BB2 : F) { if (has_calls) break; - for (auto &IN : BB) { + for (auto &IN : BB2) { CallInst *callInst = nullptr; if ((callInst = dyn_cast<CallInst>(&IN))) { @@ -454,7 +454,7 @@ struct InsTrim : public ModulePass { auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin()); DenseMap<BasicBlock *, unsigned> PredMap; - for (auto PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) { + for (PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) { BasicBlock *PBB = *PI; auto It = PredMap.insert({PBB, genLabel()}); @@ -568,7 +568,7 @@ struct InsTrim : public ModulePass { getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); - OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n", total_instr, + OKF("Instrumented %d locations (%llu, %llu) (%s mode)\n", total_instr, total_rs, total_hs, modeline); } diff --git a/instrumentation/MarkNodes.cc b/instrumentation/MarkNodes.cc index 20a7df35..b77466d9 100644 --- a/instrumentation/MarkNodes.cc +++ b/instrumentation/MarkNodes.cc @@ -332,11 +332,11 @@ bool Indistinguish(uint32_t node1, uint32_t node2) { void MakeUniq(uint32_t now) { - bool StopFlag = false; if (Marked.find(now) == Marked.end()) { for (uint32_t pred1 : t_Pred[now]) { + bool StopFlag = false; for (uint32_t pred2 : t_Pred[now]) { if (pred1 == pred2) continue; diff --git a/instrumentation/README.instrument_list.md b/instrumentation/README.instrument_list.md index 122be2b6..b47b50f6 100644 --- a/instrumentation/README.instrument_list.md +++ b/instrumentation/README.instrument_list.md @@ -1,8 +1,9 @@ # Using afl++ with partial instrumentation - This file describes how to selectively instrument only source files - or functions that are of interest to you using the LLVM and GCC_PLUGIN - instrumentation provided by afl++. + This file describes two different mechanisms to selectively instrument + only specific parts in the target. + + Both mechanisms work for LLVM and GCC_PLUGIN, but not for afl-clang/afl-gcc. ## 1) Description and purpose @@ -12,28 +13,42 @@ 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 to specify on a source file and function -level which function should be compiled with or without instrumentation. +For this purpose, "partial instrumentation" support is provided by afl++ that +allows to specify what should be instrumented and what not. + +Both mechanisms can be used together. + +## 2) Selective instrumentation with __AFL_COVERAGE_... directives + +In this mechanism the selective instrumentation is done in the source code. -Note: When using PCGUARD mode - and llvm 12+ - you can use this instead: -https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation +After the includes a special define has to be made, eg.: + +``` +#include <stdio.h> +#include <stdint.h> +// ... + +__AFL_COVERAGE(); // <- required for this feature to work +``` -The llvm sancov list format is fully supported by afl++, however afl++ has -more flexibility. +If you want to disable the coverage at startup until you specify coverage +should be started, then add `__AFL_COVERAGE_START_OFF();` at that position. -## 2a) Building the LLVM module +From here on out you have the following macros available that you can use +in any function where you want: -The new code is part of the existing afl++ LLVM module in the instrumentation/ -subdirectory. There is nothing specifically to do for the build :) + * `__AFL_COVERAGE_ON();` - enable coverage from this point onwards + * `__AFL_COVERAGE_OFF();` - disable coverage from this point onwards + * `__AFL_COVERAGE_DISCARD();` - reset all coverage gathered until this point + * `__AFL_COVERAGE_SKIP();` - mark this test case as unimportant. Whatever happens, afl-fuzz will ignore it. -## 2b) Building the GCC module +## 3) Selective instrumenation with AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST -The new code is part of the existing afl++ GCC_PLUGIN module in the -instrumentation/ subdirectory. There is nothing specifically to do for -the build :) +This feature is equivalent to llvm 12 sancov feature and allows to specify +on a filename and/or function name level to instrument these or skip them. -## 3) How to use the partial instrumentation mode +### 3a) 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++. @@ -90,7 +105,7 @@ fun: MallocFoo ``` Note that whitespace is ignored and comments (`# foo`) are supported. -## 4) UNIX-style pattern matching +### 3b) UNIX-style pattern matching You can add UNIX-style pattern matching in the "instrument file list" entries. See `man fnmatch` for the syntax. We do not set any of the `fnmatch` flags. diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 82e55218..016ac71f 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1111,7 +1111,7 @@ bool ModuleSanitizerCoverage::instrumentModule( getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); OKF("Instrumented %u locations with no collisions (on average %llu " - "collisions would be in afl-gcc/afl-clang-fast) (%s mode).", + "collisions would be in afl-gcc/vanilla AFL) (%s mode).", inst, calculateCollisions(inst), modeline); } @@ -1403,24 +1403,17 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, BasicBlock::iterator IP = BB.getFirstInsertionPt(); bool IsEntryBB = &BB == &F.getEntryBlock(); - DebugLoc EntryLoc; + if (IsEntryBB) { - if (auto SP = F.getSubprogram()) - EntryLoc = DebugLoc::get(SP->getScopeLine(), 0, SP); // Keep static allocas and llvm.localescape calls in the entry block. Even // if we aren't splitting the block, it's nice for allocas to be before // calls. IP = PrepareToSplitEntryBlock(BB, IP); - } else { - - EntryLoc = IP->getDebugLoc(); - } IRBuilder<> IRB(&*IP); - IRB.SetCurrentDebugLocation(EntryLoc); if (Options.TracePC) { IRB.CreateCall(SanCovTracePC) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 102b44a4..ecd6bc9b 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -1163,24 +1163,18 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, BasicBlock::iterator IP = BB.getFirstInsertionPt(); bool IsEntryBB = &BB == &F.getEntryBlock(); - DebugLoc EntryLoc; + if (IsEntryBB) { - if (auto SP = F.getSubprogram()) - EntryLoc = DebugLoc::get(SP->getScopeLine(), 0, SP); // Keep static allocas and llvm.localescape calls in the entry block. Even // if we aren't splitting the block, it's nice for allocas to be before // calls. IP = PrepareToSplitEntryBlock(BB, IP); - } else { - - EntryLoc = IP->getDebugLoc(); - } IRBuilder<> IRB(&*IP); - IRB.SetCurrentDebugLocation(EntryLoc); + if (Options.TracePC) { IRB.CreateCall(SanCovTracePC); diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index cddde87c..e31bff16 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -76,7 +76,9 @@ #endif u8 __afl_area_initial[MAP_INITIAL_SIZE]; +u8 * __afl_area_ptr_dummy = __afl_area_initial; u8 * __afl_area_ptr = __afl_area_initial; +u8 * __afl_area_ptr_backup = __afl_area_initial; u8 * __afl_dictionary; u8 * __afl_fuzz_ptr; u32 __afl_fuzz_len_dummy; @@ -87,7 +89,12 @@ u32 __afl_map_size = MAP_SIZE; u32 __afl_dictionary_len; u64 __afl_map_addr; -#ifdef __ANDROID__ +// for the __AFL_COVERAGE_ON/__AFL_COVERAGE_OFF features to work: +int __afl_selective_coverage __attribute__((weak)); +int __afl_selective_coverage_start_off __attribute__((weak)); +int __afl_selective_coverage_temp = 1; + +#if defined(__ANDROID__) || defined(__HAIKU__) PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; u32 __afl_prev_ctx; u32 __afl_cmp_counter; @@ -100,6 +107,7 @@ __thread u32 __afl_cmp_counter; int __afl_sharedmem_fuzzing __attribute__((weak)); struct cmp_map *__afl_cmp_map; +struct cmp_map *__afl_cmp_map_backup; /* Child pid? */ @@ -230,7 +238,7 @@ static void __afl_map_shm_fuzz() { static void __afl_map_shm(void) { // if we are not running in afl ensure the map exists - if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_initial; } + if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; } char *id_str = getenv(SHM_ENV_VAR); @@ -295,11 +303,17 @@ static void __afl_map_shm(void) { if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial) { - if (__afl_map_addr) + if (__afl_map_addr) { + munmap((void *)__afl_map_addr, __afl_final_loc); - else + + } else { + free(__afl_area_ptr); - __afl_area_ptr = __afl_area_initial; + + } + + __afl_area_ptr = __afl_area_ptr_dummy; } @@ -352,6 +366,18 @@ static void __afl_map_shm(void) { #else u32 shm_id = atoi(id_str); + if (__afl_map_size && __afl_map_size > MAP_SIZE) { + + u8 *map_env = getenv("AFL_MAP_SIZE"); + if (!map_env || atoi(map_env) < MAP_SIZE) { + + send_forkserver_error(FS_ERROR_MAP_SIZE); + _exit(1); + + } + + } + __afl_area_ptr = shmat(shm_id, (void *)__afl_map_addr, 0); /* Whooooops. */ @@ -396,9 +422,42 @@ static void __afl_map_shm(void) { free(__afl_area_ptr); __afl_area_ptr = NULL; - if (__afl_final_loc > MAP_INITIAL_SIZE) + + if (__afl_final_loc > MAP_INITIAL_SIZE) { + __afl_area_ptr = malloc(__afl_final_loc); - if (!__afl_area_ptr) __afl_area_ptr = __afl_area_initial; + + } + + if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; } + + } + + __afl_area_ptr_backup = __afl_area_ptr; + + if (__afl_selective_coverage) { + + if (__afl_map_size > MAP_INITIAL_SIZE) { + + __afl_area_ptr_dummy = malloc(__afl_map_size); + + if (__afl_area_ptr_dummy) { + + if (__afl_selective_coverage_start_off) { + + __afl_area_ptr = __afl_area_ptr_dummy; + + } + + } else { + + fprintf(stderr, "Error: __afl_selective_coverage failed!\n"); + __afl_selective_coverage = 0; + // continue; + + } + + } } @@ -449,6 +508,8 @@ static void __afl_map_shm(void) { __afl_cmp_map = shmat(shm_id, NULL, 0); #endif + __afl_cmp_map_backup = __afl_cmp_map; + if (!__afl_cmp_map || __afl_cmp_map == (void *)-1) { perror("shmat for cmplog"); @@ -683,7 +744,7 @@ static void __afl_start_forkserver(void) { #endif u8 tmp[4] = {0, 0, 0, 0}; - u32 status = 0; + u32 status_for_fsrv = 0; u32 already_read_first = 0; u32 was_killed; @@ -691,17 +752,26 @@ static void __afl_start_forkserver(void) { void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL); - if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) - status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); - if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT; - if (__afl_sharedmem_fuzzing != 0) status |= FS_OPT_SHDMEM_FUZZ; - if (status) status |= (FS_OPT_ENABLED); - memcpy(tmp, &status, 4); + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) { + + status_for_fsrv |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); + + } + + if (__afl_dictionary_len && __afl_dictionary) { + + status_for_fsrv |= FS_OPT_AUTODICT; + + } + + if (__afl_sharedmem_fuzzing != 0) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; } + if (status_for_fsrv) { status_for_fsrv |= (FS_OPT_ENABLED); } + memcpy(tmp, &status_for_fsrv, 4); /* Phone home and tell the parent that we're OK. If parent isn't there, assume we're not running in forkserver mode and just execute program. */ - if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; } if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) { @@ -726,7 +796,6 @@ static void __afl_start_forkserver(void) { // great lets pass the dictionary through the forkserver FD u32 len = __afl_dictionary_len, offset = 0; - s32 ret; if (write(FORKSRV_FD + 1, &len, 4) != 4) { @@ -738,6 +807,7 @@ static void __afl_start_forkserver(void) { while (len != 0) { + s32 ret; ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len); if (ret < 1) { @@ -894,6 +964,8 @@ int __afl_persistent_loop(unsigned int max_cnt) { cycle_cnt = max_cnt; first_pass = 0; + __afl_selective_coverage_temp = 1; + return 1; } @@ -906,6 +978,7 @@ int __afl_persistent_loop(unsigned int max_cnt) { __afl_area_ptr[0] = 1; memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); + __afl_selective_coverage_temp = 1; return 1; @@ -915,7 +988,7 @@ int __afl_persistent_loop(unsigned int max_cnt) { follows the loop is not traced. We do that by pivoting back to the dummy output region. */ - __afl_area_ptr = __afl_area_initial; + __afl_area_ptr = __afl_area_ptr_dummy; } @@ -937,7 +1010,7 @@ void __afl_manual_init(void) { init_done = 1; is_persistent = 0; __afl_sharedmem_fuzzing = 0; - if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_initial; + if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_ptr_dummy; if (getenv("AFL_DEBUG")) fprintf(stderr, @@ -998,7 +1071,12 @@ __attribute__((constructor(1))) void __afl_auto_second(void) { else ptr = (u8 *)malloc(__afl_final_loc); - if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr; + if (ptr && (ssize_t)ptr != -1) { + + __afl_area_ptr = ptr; + __afl_area_ptr_backup = __afl_area_ptr; + + } } @@ -1014,7 +1092,12 @@ __attribute__((constructor(0))) void __afl_auto_first(void) { ptr = (u8 *)malloc(1024000); - if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr; + if (ptr && (ssize_t)ptr != -1) { + + __afl_area_ptr = ptr; + __afl_area_ptr_backup = __afl_area_ptr; + + } } @@ -1304,3 +1387,69 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { } +/* COVERAGE manipulation features */ + +// this variable is then used in the shm setup to create an additional map +// if __afl_map_size > MAP_SIZE or cmplog is used. +// Especially with cmplog this would result in a ~260MB mem increase per +// target run. + +// disable coverage from this point onwards until turned on again +void __afl_coverage_off() { + + if (likely(__afl_selective_coverage)) { + + __afl_area_ptr = __afl_area_ptr_dummy; + __afl_cmp_map = NULL; + + } + +} + +// enable coverage +void __afl_coverage_on() { + + if (likely(__afl_selective_coverage && __afl_selective_coverage_temp)) { + + __afl_area_ptr = __afl_area_ptr_backup; + __afl_cmp_map = __afl_cmp_map_backup; + + } + +} + +// discard all coverage up to this point +void __afl_coverage_discard() { + + memset(__afl_area_ptr_backup, 0, __afl_map_size); + __afl_area_ptr_backup[0] = 1; + + if (__afl_cmp_map) { memset(__afl_cmp_map, 0, sizeof(struct cmp_map)); } + +} + +// discard the testcase +void __afl_coverage_skip() { + + __afl_coverage_discard(); + + if (likely(is_persistent && __afl_selective_coverage)) { + + __afl_coverage_off(); + __afl_selective_coverage_temp = 0; + + } else { + + exit(0); + + } + +} + +// mark this area as especially interesting +void __afl_coverage_interesting(u8 val, u32 id) { + + __afl_area_ptr[id] = val; + +} + diff --git a/instrumentation/afl-gcc-pass.so.cc b/instrumentation/afl-gcc-pass.so.cc index 25437609..41bb5152 100644 --- a/instrumentation/afl-gcc-pass.so.cc +++ b/instrumentation/afl-gcc-pass.so.cc @@ -228,7 +228,7 @@ struct afl_pass : gimple_opt_pass { const bool neverZero; /* Count instrumented blocks. */ - int inst_blocks; + unsigned int inst_blocks; virtual unsigned int execute(function *fn) { @@ -444,8 +444,10 @@ struct afl_pass : gimple_opt_pass { DECL_EXTERNAL(decl) = 1; DECL_ARTIFICIAL(decl) = 1; TREE_STATIC(decl) = 1; +#if !defined(__ANDROID__) && !defined(__HAIKU__) set_decl_tls_model( decl, (flag_pic ? TLS_MODEL_INITIAL_EXEC : TLS_MODEL_LOCAL_EXEC)); +#endif return decl; } @@ -920,8 +922,9 @@ int plugin_init(struct plugin_name_args * info, struct plugin_gcc_version *version) { if (!plugin_default_version_check(version, &gcc_version)) - FATAL(G_("GCC and plugin have incompatible versions, expected GCC %d.%d"), - GCCPLUGIN_VERSION_MAJOR, GCCPLUGIN_VERSION_MINOR); + FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, " + "is %s"), + gcc_version.basever, version->basever); /* Show a banner. */ bool quiet = false; @@ -931,7 +934,7 @@ int plugin_init(struct plugin_name_args * info, quiet = true; /* Decide instrumentation ratio. */ - int inst_ratio = 100; + unsigned int inst_ratio = 100U; if (char *inst_ratio_str = getenv("AFL_INST_RATIO")) if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || !inst_ratio || inst_ratio > 100) diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index bd8eb27a..a4b33732 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -355,7 +355,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { *Str2P = callInst->getArgOperand(1); std::string Str1, Str2; StringRef TmpStr; - bool HasStr1 = getConstantStringInfo(Str1P, TmpStr); + bool HasStr1; + getConstantStringInfo(Str1P, TmpStr); if (TmpStr.empty()) { HasStr1 = false; @@ -367,7 +368,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { } - bool HasStr2 = getConstantStringInfo(Str2P, TmpStr); + bool HasStr2; + getConstantStringInfo(Str2P, TmpStr); if (TmpStr.empty()) { HasStr2 = false; diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 9e026e57..13dca8c4 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -70,7 +70,7 @@ class AFLLTOPass : public ModulePass { if (getenv("AFL_DEBUG")) debug = 1; if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL) if ((afl_global_id = atoi(ptr)) < 0 || afl_global_id >= MAP_SIZE) - FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %d\n", + FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %u\n", ptr, MAP_SIZE - 1); skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); @@ -100,9 +100,9 @@ class AFLLTOPass : public ModulePass { bool AFLLTOPass::runOnModule(Module &M) { - LLVMContext & C = M.getContext(); - std::vector<std::string> dictionary; - std::vector<CallInst *> calls; + LLVMContext & C = M.getContext(); + std::vector<std::string> dictionary; + // std::vector<CallInst *> calls; DenseMap<Value *, std::string *> valueMap; std::vector<BasicBlock *> BlockList; char * ptr; @@ -471,7 +471,8 @@ bool AFLLTOPass::runOnModule(Module &M) { *Str2P = callInst->getArgOperand(1); std::string Str1, Str2; StringRef TmpStr; - bool HasStr1 = getConstantStringInfo(Str1P, TmpStr); + bool HasStr1; + getConstantStringInfo(Str1P, TmpStr); if (TmpStr.empty()) { HasStr1 = false; @@ -483,7 +484,8 @@ bool AFLLTOPass::runOnModule(Module &M) { } - bool HasStr2 = getConstantStringInfo(Str2P, TmpStr); + bool HasStr2; + getConstantStringInfo(Str2P, TmpStr); if (TmpStr.empty()) { HasStr2 = false; @@ -671,7 +673,6 @@ bool AFLLTOPass::runOnModule(Module &M) { if (!be_quiet) { - std::string outstring; fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen, thestring.length()); for (uint8_t i = 0; i < thestring.length(); i++) { @@ -799,7 +800,7 @@ bool AFLLTOPass::runOnModule(Module &M) { if (documentFile) { - fprintf(documentFile, "ModuleID=%llu Function=%s edgeID=%u\n", + fprintf(documentFile, "ModuleID=%llu Function=%s edgeID=%d\n", moduleID, F.getName().str().c_str(), afl_global_id); } @@ -871,10 +872,10 @@ bool AFLLTOPass::runOnModule(Module &M) { while ((map = map >> 1)) pow2map++; WARNF( - "We have %u blocks to instrument but the map size is only %u. Either " - "edit config.h and set MAP_SIZE_POW2 from %u to %u, then recompile " + "We have %d blocks to instrument but the map size is only %u. Either " + "edit config.h and set MAP_SIZE_POW2 from %d to %u, then recompile " "afl-fuzz and llvm_mode and then make this target - or set " - "AFL_MAP_SIZE with at least size %u when running afl-fuzz with this " + "AFL_MAP_SIZE with at least size %d when running afl-fuzz with this " "target.", afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map, afl_global_id); @@ -937,8 +938,7 @@ bool AFLLTOPass::runOnModule(Module &M) { if (dictionary.size()) { - size_t memlen = 0, count = 0, offset = 0; - char * ptr; + size_t memlen = 0, count = 0; // sort and unique the dictionary std::sort(dictionary.begin(), dictionary.end()); @@ -953,14 +953,14 @@ bool AFLLTOPass::runOnModule(Module &M) { } if (!be_quiet) - printf("AUTODICTIONARY: %lu string%s found\n", count, + printf("AUTODICTIONARY: %zu string%s found\n", count, count == 1 ? "" : "s"); if (count) { if ((ptr = (char *)malloc(memlen + count)) == NULL) { - fprintf(stderr, "Error: malloc for %lu bytes failed!\n", + fprintf(stderr, "Error: malloc for %zu bytes failed!\n", memlen + count); exit(-1); @@ -968,6 +968,7 @@ bool AFLLTOPass::runOnModule(Module &M) { count = 0; + size_t offset = 0; for (auto token : dictionary) { if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) { @@ -1031,8 +1032,8 @@ bool AFLLTOPass::runOnModule(Module &M) { getenv("AFL_USE_MSAN") ? ", MSAN" : "", getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); - OKF("Instrumented %u locations with no collisions (on average %llu " - "collisions would be in afl-gcc/afl-clang-fast) (%s mode).", + OKF("Instrumented %d locations with no collisions (on average %llu " + "collisions would be in afl-gcc/vanilla AFL) (%s mode).", inst_blocks, calculateCollisions(inst_blocks), modeline); } diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 8c8c987a..57ff3b47 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -241,7 +241,7 @@ bool AFLCoverage::runOnModule(Module &M) { GlobalVariable *AFLContext = NULL; if (ctx_str) -#ifdef __ANDROID__ +#if defined(__ANDROID__) || defined(__HAIKU__) AFLContext = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx"); #else @@ -252,7 +252,7 @@ bool AFLCoverage::runOnModule(Module &M) { #ifdef AFL_HAVE_VECTOR_INTRINSICS if (ngram_size) - #ifdef __ANDROID__ + #if defined(__ANDROID__) || defined(__HAIKU__) AFLPrevLoc = new GlobalVariable( M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, /* Initializer */ nullptr, "__afl_prev_loc"); @@ -265,7 +265,7 @@ bool AFLCoverage::runOnModule(Module &M) { #endif else #endif -#ifdef __ANDROID__ +#if defined(__ANDROID__) || defined(__HAIKU__) AFLPrevLoc = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); #else @@ -327,10 +327,10 @@ bool AFLCoverage::runOnModule(Module &M) { // does the function have calls? and is any of the calls larger than one // basic block? - for (auto &BB : F) { + for (auto &BB_2 : F) { if (has_calls) break; - for (auto &IN : BB) { + for (auto &IN : BB_2) { CallInst *callInst = nullptr; if ((callInst = dyn_cast<CallInst>(&IN))) { @@ -628,7 +628,7 @@ bool AFLCoverage::runOnModule(Module &M) { getenv("AFL_USE_MSAN") ? ", MSAN" : "", getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); - OKF("Instrumented %u locations (%s mode, ratio %u%%).", inst_blocks, + OKF("Instrumented %d locations (%s mode, ratio %u%%).", inst_blocks, modeline, inst_ratio); } diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc index 9921de0c..3499ccf0 100644 --- a/instrumentation/cmplog-instructions-pass.cc +++ b/instrumentation/cmplog-instructions-pass.cc @@ -186,16 +186,19 @@ bool CmpLogInstructions::hookInstrs(Module &M) { selectcmpInst->getPredicate() == CmpInst::ICMP_UGE || selectcmpInst->getPredicate() == CmpInst::ICMP_SGE || selectcmpInst->getPredicate() == CmpInst::ICMP_ULE || - selectcmpInst->getPredicate() == CmpInst::ICMP_SLE) { - - auto op0 = selectcmpInst->getOperand(0); - auto op1 = selectcmpInst->getOperand(1); - - IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType()); - IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType()); - - /* this is probably not needed but we do it anyway */ - if (!intTyOp0 || !intTyOp1) { continue; } + selectcmpInst->getPredicate() == CmpInst::ICMP_SLE || + selectcmpInst->getPredicate() == CmpInst::FCMP_OGE || + selectcmpInst->getPredicate() == CmpInst::FCMP_UGE || + selectcmpInst->getPredicate() == CmpInst::FCMP_OLE || + selectcmpInst->getPredicate() == CmpInst::FCMP_ULE || + selectcmpInst->getPredicate() == CmpInst::FCMP_OGT || + selectcmpInst->getPredicate() == CmpInst::FCMP_UGT || + selectcmpInst->getPredicate() == CmpInst::FCMP_OLT || + selectcmpInst->getPredicate() == CmpInst::FCMP_ULT || + selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ || + selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ || + selectcmpInst->getPredicate() == CmpInst::FCMP_UNE || + selectcmpInst->getPredicate() == CmpInst::FCMP_ONE) { icomps.push_back(selectcmpInst); @@ -221,16 +224,66 @@ bool CmpLogInstructions::hookInstrs(Module &M) { auto op0 = selectcmpInst->getOperand(0); auto op1 = selectcmpInst->getOperand(1); - IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType()); - IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType()); + IntegerType * intTyOp0 = NULL; + IntegerType * intTyOp1 = NULL; + unsigned max_size = 0; + std::vector<Value *> args; - unsigned max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth() - ? intTyOp0->getBitWidth() - : intTyOp1->getBitWidth(); + if (selectcmpInst->getOpcode() == Instruction::FCmp) { - std::vector<Value *> args; - args.push_back(op0); - args.push_back(op1); + auto ty0 = op0->getType(); + if (ty0->isHalfTy() +#if LLVM_VERSION_MAJOR >= 11 + || ty0->isBFloatTy() +#endif + ) + max_size = 16; + else if (ty0->isFloatTy()) + max_size = 32; + else if (ty0->isDoubleTy()) + max_size = 64; + + if (max_size) { + + Value *V0 = IRB.CreateBitCast(op0, IntegerType::get(C, max_size)); + intTyOp0 = dyn_cast<IntegerType>(V0->getType()); + Value *V1 = IRB.CreateBitCast(op1, IntegerType::get(C, max_size)); + intTyOp1 = dyn_cast<IntegerType>(V1->getType()); + + if (intTyOp0 && intTyOp1) { + + max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth() + ? intTyOp0->getBitWidth() + : intTyOp1->getBitWidth(); + args.push_back(V0); + args.push_back(V1); + + } else { + + max_size = 0; + + } + + } + + } else { + + intTyOp0 = dyn_cast<IntegerType>(op0->getType()); + intTyOp1 = dyn_cast<IntegerType>(op1->getType()); + + if (intTyOp0 && intTyOp1) { + + max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth() + ? intTyOp0->getBitWidth() + : intTyOp1->getBitWidth(); + args.push_back(op0); + args.push_back(op1); + + } + + } + + if (max_size < 8 || max_size > 64 || !intTyOp0 || !intTyOp1) continue; switch (max_size) { diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index de8b97f0..da5cf7e9 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -68,7 +68,7 @@ class CompareTransform : public ModulePass { const char *getPassName() const override { #else - StringRef getPassName() const override { + StringRef getPassName() const override { #endif return "transforms compare functions"; @@ -101,22 +101,31 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, IntegerType * Int64Ty = IntegerType::getInt64Ty(C); #if LLVM_VERSION_MAJOR < 9 - Constant * + Function *tolowerFn; #else - FunctionCallee + FunctionCallee tolowerFn; #endif - c = M.getOrInsertFunction("tolower", Int32Ty, Int32Ty + { + +#if LLVM_VERSION_MAJOR < 9 + Constant * +#else + FunctionCallee +#endif + c = M.getOrInsertFunction("tolower", Int32Ty, Int32Ty #if LLVM_VERSION_MAJOR < 5 - , - NULL + , + NULL #endif - ); + ); #if LLVM_VERSION_MAJOR < 9 - Function *tolowerFn = cast<Function>(c); + tolowerFn = cast<Function>(c); #else - FunctionCallee tolowerFn = c; + tolowerFn = c; #endif + } + /* iterate over all functions, bbs and instruction and add suitable calls to * strcmp/memcmp/strncmp/strcasecmp/strncasecmp */ for (auto &F : M) { @@ -234,7 +243,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, if (!HasStr2) { - auto *Ptr = dyn_cast<ConstantExpr>(Str1P); + Ptr = dyn_cast<ConstantExpr>(Str1P); if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) { diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 33a87719..b6d8c466 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -53,7 +53,7 @@ class SplitComparesTransform : public ModulePass { public: static char ID; - SplitComparesTransform() : ModulePass(ID) { + SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) { initInstrumentList(); @@ -555,6 +555,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) { if (selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ || + selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ || selectcmpInst->getPredicate() == CmpInst::FCMP_ONE || selectcmpInst->getPredicate() == CmpInst::FCMP_UNE || selectcmpInst->getPredicate() == CmpInst::FCMP_UGT || @@ -735,6 +736,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock * signequal2_bb = signequal_bb; switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: icmp_exponent_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1); @@ -816,6 +818,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: /* if the exponents are satifying the compare do a fraction cmp in * middle_bb */ @@ -900,11 +903,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* compare the fractions of the operands */ Instruction *icmp_fraction_result; - Instruction *icmp_fraction_result2; BasicBlock * middle2_bb = middle_bb; PHINode * PN2 = nullptr; switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: icmp_fraction_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1); @@ -927,6 +930,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { case CmpInst::FCMP_OLT: case CmpInst::FCMP_ULT: { + Instruction *icmp_fraction_result2; + middle2_bb = middle_bb->splitBasicBlock( BasicBlock::iterator(middle_bb->getTerminator())); @@ -980,6 +985,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: /* unequal signs cannot be equal values */ /* goto false branch */ diff --git a/qemu_mode/QEMUAFL_VERSION b/qemu_mode/QEMUAFL_VERSION index 43403430..9d6d7dba 100644 --- a/qemu_mode/QEMUAFL_VERSION +++ b/qemu_mode/QEMUAFL_VERSION @@ -1 +1 @@ -d66c9e2654 +6ea7398ee3 diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 6dac415b..0af489fe 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -26,9 +26,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif #include "config.h" #include "types.h" #include "debug.h" @@ -903,8 +900,8 @@ static void usage(u8 *argv0) { "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" + " -t msec - timeout for each run (%u ms)\n" + " -m megs - memory limit for child process (%u 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 " diff --git a/src/afl-cc.c b/src/afl-cc.c index e6a6718e..f3dfd49f 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -120,8 +120,13 @@ char compiler_mode_string[7][12] = { u8 *getthecwd() { - static u8 fail[] = ""; - if (getcwd(cwd, sizeof(cwd)) == NULL) return fail; + if (getcwd(cwd, sizeof(cwd)) == NULL) { + + static u8 fail[] = ""; + return fail; + + } + return cwd; } @@ -581,6 +586,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (instrument_mode == INSTRUMENT_PCGUARD) { #if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0) +#ifdef __ANDROID__ + cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; +#else if (have_instr_list) { if (!be_quiet) @@ -600,6 +608,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { } +#endif #else #if LLVM_MAJOR >= 4 if (!be_quiet) @@ -654,9 +663,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - u32 idx; if (lto_mode && argc > 1) { + u32 idx; for (idx = 1; idx < argc; idx++) { if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1; @@ -787,8 +796,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { } -#if defined(USEMMAP) && !defined(__HAIKU__) +#if defined(USEMMAP) + #if !defined(__HAIKU__) cc_params[cc_par_cnt++] = "-lrt"; + #endif #endif cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; @@ -822,6 +833,35 @@ static void edit_params(u32 argc, char **argv, char **envp) { "extern unsigned char *__afl_fuzz_ptr;" "unsigned char __afl_fuzz_alt[1048576];" "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;"; + + if (plusplus_mode) { + + cc_params[cc_par_cnt++] = + "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;" + "extern \"C\" void __afl_coverage_discard();" + "extern \"C\" void __afl_coverage_skip();" + "extern \"C\" void __afl_coverage_on();" + "extern \"C\" void __afl_coverage_off();"; + + } else { + + cc_params[cc_par_cnt++] = + "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;" + "void __afl_coverage_discard();" + "void __afl_coverage_skip();" + "void __afl_coverage_on();" + "void __afl_coverage_off();"; + + } + + cc_params[cc_par_cnt++] = + "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = " + "1;"; + cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_ON()=__afl_coverage_on()"; + cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_OFF()=__afl_coverage_off()"; + cc_params[cc_par_cnt++] = + "-D__AFL_COVERAGE_DISCARD()=__afl_coverage_discard()"; + cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_SKIP()=__afl_coverage_skip()"; cc_params[cc_par_cnt++] = "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : " "__afl_fuzz_alt_ptr)"; @@ -931,8 +971,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path); #endif - #ifdef USEMMAP + #if defined(USEMMAP) + #if !defined(__HAIKU__) cc_params[cc_par_cnt++] = "-lrt"; + #endif #endif } @@ -996,6 +1038,10 @@ int main(int argc, char **argv, char **envp) { #endif +#ifdef __ANDROID__ + have_llvm = 1; +#endif + if ((ptr = find_object("afl-gcc-pass.so", argv[0])) != NULL) { have_gcc_plugin = 1; @@ -1208,12 +1254,12 @@ int main(int argc, char **argv, char **envp) { if (getenv("AFL_LLVM_INSTRUMENT")) { - u8 *ptr = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;"); + u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;"); - while (ptr) { + while (ptr2) { - if (strncasecmp(ptr, "afl", strlen("afl")) == 0 || - strncasecmp(ptr, "classic", strlen("classic")) == 0) { + if (strncasecmp(ptr2, "afl", strlen("afl")) == 0 || + strncasecmp(ptr2, "classic", strlen("classic")) == 0) { if (instrument_mode == INSTRUMENT_LTO) { @@ -1229,8 +1275,8 @@ int main(int argc, char **argv, char **envp) { } - if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 || - strncasecmp(ptr, "pcguard", strlen("pcguard")) == 0) { + if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 || + strncasecmp(ptr2, "pcguard", strlen("pcguard")) == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD) instrument_mode = INSTRUMENT_PCGUARD; @@ -1241,8 +1287,8 @@ int main(int argc, char **argv, char **envp) { } // this is a hidden option - if (strncasecmp(ptr, "llvmnative", strlen("llvmnative")) == 0 || - strncasecmp(ptr, "llvm-native", strlen("llvm-native")) == 0) { + if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 || + strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE) instrument_mode = INSTRUMENT_LLVMNATIVE; @@ -1252,8 +1298,8 @@ int main(int argc, char **argv, char **envp) { } - if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 || - strncasecmp(ptr, "instrim", strlen("instrim")) == 0) { + if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 || + strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) { if (instrument_mode == INSTRUMENT_LTO) { @@ -1269,7 +1315,7 @@ int main(int argc, char **argv, char **envp) { } - if (strncasecmp(ptr, "lto", strlen("lto")) == 0) { + if (strncasecmp(ptr2, "lto", strlen("lto")) == 0) { lto_mode = 1; if (!instrument_mode || instrument_mode == INSTRUMENT_LTO) @@ -1280,7 +1326,7 @@ int main(int argc, char **argv, char **envp) { } - if (strcasecmp(ptr, "gcc") == 0) { + if (strcasecmp(ptr2, "gcc") == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_GCC) instrument_mode = INSTRUMENT_GCC; @@ -1291,7 +1337,7 @@ int main(int argc, char **argv, char **envp) { } - if (strcasecmp(ptr, "clang") == 0) { + if (strcasecmp(ptr2, "clang") == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_CLANG) instrument_mode = INSTRUMENT_CLANG; @@ -1302,29 +1348,29 @@ int main(int argc, char **argv, char **envp) { } - if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) { + if (strncasecmp(ptr2, "ctx", strlen("ctx")) == 0) { instrument_opt_mode |= INSTRUMENT_OPT_CTX; setenv("AFL_LLVM_CTX", "1", 1); } - if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) { + if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) { - ptr += strlen("ngram"); - while (*ptr && (*ptr < '0' || *ptr > '9')) - ptr++; + ptr2 += strlen("ngram"); + while (*ptr2 && (*ptr2 < '0' || *ptr2 > '9')) + ptr2++; - if (!*ptr) { + if (!*ptr2) { - if ((ptr = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL) + if ((ptr2 = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL) FATAL( "you must set the NGRAM size with (e.g. for value 2) " "AFL_LLVM_INSTRUMENT=ngram-2"); } - ngram_size = atoi(ptr); + ngram_size = atoi(ptr2); if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX) FATAL( "NGRAM instrumentation option must be between 2 and " @@ -1332,12 +1378,12 @@ int main(int argc, char **argv, char **envp) { "(%u)", NGRAM_SIZE_MAX); instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM); - ptr = alloc_printf("%u", ngram_size); - setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1); + ptr2 = alloc_printf("%u", ngram_size); + setenv("AFL_LLVM_NGRAM_SIZE", ptr2, 1); } - ptr = strtok(NULL, ":,;"); + ptr2 = strtok(NULL, ":,;"); } @@ -1448,20 +1494,28 @@ int main(int argc, char **argv, char **envp) { " The best is LTO but it often needs RANLIB and AR settings outside " "of afl-cc.\n\n"); +#if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0) + #define NATIVE_MSG \ + " NATIVE: use llvm's native PCGUARD instrumentation (less " \ + "performant)\n" +#else + #define NATIVE_MSG "" +#endif + SAYF( "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 + + NATIVE_MSG + " CLASSIC: decision target instrumentation (README.llvm.md)\n" " CTX: CLASSIC + callee context (instrumentation/README.ctx.md)\n" " NGRAM-x: CLASSIC + previous path " "((instrumentation/README.ngram.md)\n" " INSTRIM: Dominator tree (for LLVM <= 6.0) " "(instrumentation/README.instrim.md)\n\n"); +#undef NATIVE_MSG SAYF( "Features: (see documentation links)\n" @@ -1595,12 +1649,17 @@ int main(int argc, char **argv, char **envp) { if (have_lto) SAYF("afl-cc LTO with ld=%s %s\n", AFL_REAL_LD, AFL_CLANG_FLTO); if (have_llvm) - SAYF("afl-cc LLVM version %d with the the binary path \"%s\".\n", - LLVM_MAJOR, LLVM_BINDIR); + SAYF("afl-cc LLVM version %d using binary path \"%s\".\n", LLVM_MAJOR, + LLVM_BINDIR); #endif -#ifdef USEMMAP +#if defined(USEMMAP) + #if !defined(__HAIKU__) + cc_params[cc_par_cnt++] = "-lrt"; SAYF("Compiled with shm_open support (adds -lrt when linking).\n"); + #else + SAYF("Compiled with shm_open support.\n"); + #endif #else SAYF("Compiled with shmat support.\n"); #endif @@ -1625,7 +1684,7 @@ int main(int argc, char **argv, char **envp) { if (!instrument_mode) { instrument_mode = INSTRUMENT_CFG; - ptr = instrument_mode_string[instrument_mode]; + // ptr = instrument_mode_string[instrument_mode]; } @@ -1734,15 +1793,6 @@ int main(int argc, char **argv, char **envp) { } - if (!be_quiet && !lto_mode && - ((ptr2 = getenv("AFL_MAP_SIZE")) || (ptr2 = getenv("AFL_MAPSIZE")))) { - - u32 map_size = atoi(ptr2); - if (map_size != MAP_SIZE) - WARNF("AFL_MAP_SIZE is not supported by afl-clang-fast"); - - } - if (debug) { DEBUGF("cd '%s';", getthecwd()); @@ -1765,11 +1815,8 @@ int main(int argc, char **argv, char **envp) { if (!be_quiet && cmplog_mode) printf("CmpLog mode by <andreafioraldi@gmail.com>\n"); -#ifdef __ANDROID__ - ptr = find_object("afl-compiler-rt.so", argv[0]); -#else +#ifndef __ANDROID__ ptr = find_object("afl-compiler-rt.o", argv[0]); -#endif if (!ptr) { @@ -1782,6 +1829,7 @@ int main(int argc, char **argv, char **envp) { if (debug) { DEBUGF("rt=%s obj_path=%s\n", ptr, obj_path); } ck_free(ptr); +#endif edit_params(argc, argv, envp); diff --git a/src/afl-common.c b/src/afl-common.c index 1928663d..cf996548 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -424,6 +424,40 @@ u8 *find_binary(u8 *fname) { } +/* Parses the kill signal environment variable, FATALs on error. + If the env is not set, sets the env to default_signal for the signal handlers + and returns the default_signal. */ +int parse_afl_kill_signal_env(u8 *afl_kill_signal_env, int default_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 == (char *)afl_kill_signal_env) { + + FATAL("Invalid AFL_KILL_SIGNAL: %s (expected unsigned int)", + afl_kill_signal_env); + + } + + return signal_code; + + } else { + + char *sigstr = alloc_printf("%d", default_signal); + if (!sigstr) { FATAL("Failed to alloc mem for signal buf"); } + + /* Set the env for signal handler */ + setenv("AFL_KILL_SIGNAL", sigstr, 1); + free(sigstr); + return default_signal; + + } + +} + void check_environment_vars(char **envp) { if (be_quiet) { return; } @@ -696,16 +730,16 @@ u8 *stringify_mem_size(u8 *buf, size_t len, u64 val) { u8 *stringify_time_diff(u8 *buf, size_t len, u64 cur_ms, u64 event_ms) { - u64 delta; - s32 t_d, t_h, t_m, t_s; - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; - if (!event_ms) { snprintf(buf, len, "none seen yet"); } else { + u64 delta; + s32 t_d, t_h, t_m, t_s; + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + delta = cur_ms - event_ms; t_d = delta / 1000 / 60 / 60 / 24; @@ -858,16 +892,16 @@ u8 *u_stringify_mem_size(u8 *buf, u64 val) { u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) { - u64 delta; - s32 t_d, t_h, t_m, t_s; - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; - if (!event_ms) { sprintf(buf, "none seen yet"); } else { + u64 delta; + s32 t_d, t_h, t_m, t_s; + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + delta = cur_ms - event_ms; t_d = delta / 1000 / 60 / 60 / 24; @@ -893,14 +927,14 @@ u32 get_map_size(void) { if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) { map_size = atoi(ptr); - if (map_size < 8 || map_size > (1 << 29)) { + if (!map_size || map_size > (1 << 29)) { - FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 8, - 1 << 29); + FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 32U, + 1U << 29); } - if (map_size % 8) { map_size = (((map_size >> 3) + 1) << 3); } + if (map_size % 32) { map_size = (((map_size >> 5) + 1) << 5); } } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 90fa55e9..39f044f2 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,7 +96,6 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->uses_asan = false; fsrv->init_child_func = fsrv_exec_child; - list_append(&fsrv_list, fsrv); } @@ -116,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; @@ -213,7 +214,7 @@ restart_select: static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { unsigned char tmp[4] = {0, 0, 0, 0}; - pid_t child_pid = -1; + pid_t child_pid; if (!be_quiet) { ACTF("Using Fauxserver:"); } @@ -559,12 +560,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!time_ms) { - kill(fsrv->fsrv_pid, SIGKILL); + kill(fsrv->fsrv_pid, fsrv->kill_signal); } else if (time_ms > fsrv->init_tmout) { fsrv->last_run_timed_out = 1; - kill(fsrv->fsrv_pid, SIGKILL); + kill(fsrv->fsrv_pid, fsrv->kill_signal); } else { @@ -807,6 +808,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "before receiving any input\n" " from the fuzzer! There are several probable explanations:\n\n" + " - The target binary requires a large map and crashes before " + "reporting.\n" + " Set a high value (e.g. AFL_MAP_SIZE=1024000) or use " + "AFL_DEBUG=1 to see the\n" + " message from the target binary\n\n" + " - The binary is just buggy and explodes entirely on its own. " "If so, you\n" " need to fix the underlying problem or find a better " @@ -828,6 +835,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "before receiving any input\n" " from the fuzzer! There are several probable explanations:\n\n" + " - The target binary requires a large map and crashes before " + "reporting.\n" + " Set a high value (e.g. AFL_MAP_SIZE=1024000) or use " + "AFL_DEBUG=1 to see the\n" + " message from the target binary\n\n" + " - The current memory limit (%s) is too restrictive, causing " "the\n" " target to hit an OOM condition in the dynamic linker. Try " @@ -944,10 +957,10 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, static void afl_fsrv_kill(afl_forkserver_t *fsrv) { - if (fsrv->child_pid > 0) { kill(fsrv->child_pid, SIGKILL); } + if (fsrv->child_pid > 0) { kill(fsrv->child_pid, fsrv->kill_signal); } if (fsrv->fsrv_pid > 0) { - kill(fsrv->fsrv_pid, SIGKILL); + kill(fsrv->fsrv_pid, fsrv->kill_signal); if (waitpid(fsrv->fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); } } @@ -971,10 +984,10 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { hash64(fsrv->shmem_fuzz, *fsrv->shmem_fuzz_len, 0xa5b35705), *fsrv->shmem_fuzz_len); fprintf(stderr, "SHM :"); - for (int i = 0; i < *fsrv->shmem_fuzz_len; i++) + for (u32 i = 0; i < *fsrv->shmem_fuzz_len; i++) fprintf(stderr, "%02x", fsrv->shmem_fuzz[i]); fprintf(stderr, "\nORIG:"); - for (int i = 0; i < *fsrv->shmem_fuzz_len; i++) + for (u32 i = 0; i < *fsrv->shmem_fuzz_len; i++) fprintf(stderr, "%02x", buf[i]); fprintf(stderr, "\n"); @@ -1091,7 +1104,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* If there was no response from forkserver after timeout seconds, we kill the child. The forkserver should inform us afterwards */ - kill(fsrv->child_pid, SIGKILL); + kill(fsrv->child_pid, fsrv->kill_signal); fsrv->last_run_timed_out = 1; if (read(fsrv->fsrv_st_fd, &fsrv->child_status, 4) < 4) { exec_ms = 0; } @@ -1104,7 +1117,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, "Unable to communicate with fork server. Some possible reasons:\n\n" " - You've run out of memory. Use -m to increase the the memory " "limit\n" - " to something higher than %lld.\n" + " to something higher than %llu.\n" " - The binary or one of the libraries it uses manages to " "create\n" " threads before the forkserver initializes.\n" @@ -1137,36 +1150,44 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* Report outcome to caller. */ - if (WIFSIGNALED(fsrv->child_status) && !*stop_soon_p) { + /* Was the run unsuccessful? */ + if (unlikely(*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG)) { - fsrv->last_kill_signal = WTERMSIG(fsrv->child_status); + return FSRV_RUN_ERROR; - if (fsrv->last_run_timed_out && fsrv->last_kill_signal == SIGKILL) { - - return FSRV_RUN_TMOUT; + } - } + /* Did we timeout? */ + if (unlikely(fsrv->last_run_timed_out)) { - return FSRV_RUN_CRASH; + fsrv->last_kill_signal = fsrv->kill_signal; + return FSRV_RUN_TMOUT; } - /* 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) || - (fsrv->uses_crash_exitcode && - WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode)) { - - fsrv->last_kill_signal = 0; + /* Did we crash? + In a normal case, (abort) WIFSIGNALED(child_status) will be set. + 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 all three cases here. */ + + if (unlikely( + /* A normal crash/abort */ + (WIFSIGNALED(fsrv->child_status)) || + /* special handling for msan */ + (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) || + /* the custom crash_exitcode was returned by the target */ + (fsrv->uses_crash_exitcode && + WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { + + /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */ + fsrv->last_kill_signal = + WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0; return FSRV_RUN_CRASH; } - // Fauxserver should handle this now. - if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) return FSRV_RUN_ERROR; - + /* success :) */ return FSRV_RUN_OK; } diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 62a8211c..586f3990 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -703,7 +703,6 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (!classified) { classify_counts(&afl->fsrv); - classified = 1; } diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 171cce96..a3583651 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -266,7 +266,7 @@ static void extras_check_and_sort(afl_state_t *afl, u32 min_len, u32 max_len, if (afl->extras_cnt > afl->max_det_extras) { - WARNF("More than %d tokens - will use them probabilistically.", + WARNF("More than %u tokens - will use them probabilistically.", afl->max_det_extras); } @@ -431,7 +431,6 @@ void dedup_extras(afl_state_t *afl) { /* Adds a new extra / dict entry. */ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { - u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; u32 i, found = 0; for (i = 0; i < afl->extras_cnt; i++) { @@ -451,6 +450,7 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { if (len > MAX_DICT_FILE) { + u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; WARNF("Extra '%.*s' is too big (%s, limit is %s), skipping file!", (int)len, mem, stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), len), stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE)); @@ -481,7 +481,7 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { if (afl->extras_cnt == afl->max_det_extras + 1) { - WARNF("More than %d tokens - will use them probabilistically.", + WARNF("More than %u tokens - will use them probabilistically.", afl->max_det_extras); } diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 0c85458e..80df6d08 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -141,7 +141,10 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator)); mutator->name = fn; - mutator->name_short = strrchr(fn, '/') + 1; + if (memchr(fn, '/', strlen(fn))) + mutator->name_short = strrchr(fn, '/') + 1; + else + mutator->name_short = strdup(fn); ACTF("Loading custom mutator library from '%s'...", fn); dh = dlopen(fn, RTLD_NOW); @@ -316,16 +319,20 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, /* Initialize trimming in the custom mutator */ afl->stage_cur = 0; - afl->stage_max = mutator->afl_custom_init_trim(mutator->data, in_buf, q->len); - if (unlikely(afl->stage_max) < 0) { + s32 retval = mutator->afl_custom_init_trim(mutator->data, in_buf, q->len); + if (unlikely(retval) < 0) { - FATAL("custom_init_trim error ret: %d", afl->stage_max); + FATAL("custom_init_trim error ret: %d", retval); + + } else { + + afl->stage_max = retval; } if (afl->not_on_tty && afl->debug) { - SAYF("[Custom Trimming] START: Max %d iterations, %u bytes", afl->stage_max, + SAYF("[Custom Trimming] START: Max %u iterations, %u bytes", afl->stage_max, q->len); } @@ -343,7 +350,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (unlikely(!retbuf)) { - FATAL("custom_trim failed (ret %zd)", retlen); + FATAL("custom_trim failed (ret %zu)", retlen); } else if (unlikely(retlen > orig_len)) { @@ -409,7 +416,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (afl->not_on_tty && afl->debug) { - SAYF("[Custom Trimming] SUCCESS: %d/%d iterations (now at %u bytes)", + SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)", afl->stage_cur, afl->stage_max, q->len); } @@ -417,16 +424,20 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, } else { /* Tell the custom mutator that the trimming was unsuccessful */ - afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 0); - if (unlikely(afl->stage_cur < 0)) { + s32 retval2 = mutator->afl_custom_post_trim(mutator->data, 0); + if (unlikely(retval2 < 0)) { + + FATAL("Error ret in custom_post_trim: %d", retval2); + + } else { - FATAL("Error ret in custom_post_trim: %d", afl->stage_cur); + afl->stage_cur = retval2; } if (afl->not_on_tty && afl->debug) { - SAYF("[Custom Trimming] FAILURE: %d/%d iterations", afl->stage_cur, + SAYF("[Custom Trimming] FAILURE: %u/%u iterations", afl->stage_cur, afl->stage_max); } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index e6fa6064..f9509e86 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -368,7 +368,7 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) { u8 fuzz_one_original(afl_state_t *afl) { - s32 len, temp_len; + u32 len, temp_len; u32 j; u32 i; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; @@ -545,7 +545,7 @@ u8 fuzz_one_original(afl_state_t *afl) { else orig_perf = perf_score = calculate_score(afl, afl->queue_cur); - if (unlikely(perf_score <= 0)) { goto abandon_entry; } + if (unlikely(perf_score == 0)) { goto abandon_entry; } if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) { @@ -902,7 +902,7 @@ u8 fuzz_one_original(afl_state_t *afl) { orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 1; ++i) { + for (i = 0; i < len - 1; ++i) { /* Let's consult the effector map... */ @@ -945,7 +945,7 @@ u8 fuzz_one_original(afl_state_t *afl) { orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 3; ++i) { + for (i = 0; i < len - 3; ++i) { /* Let's consult the effector map... */ if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] && @@ -1405,7 +1405,7 @@ skip_arith: orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 1; ++i) { + for (i = 0; i < len - 1; ++i) { u16 orig = *(u16 *)(out_buf + i); @@ -1493,7 +1493,7 @@ skip_arith: orig_hit_cnt = new_hit_cnt; - for (i = 0; (s32)i < len - 3; i++) { + for (i = 0; i < len - 3; i++) { u32 orig = *(u32 *)(out_buf + i); @@ -1850,7 +1850,7 @@ custom_mutator_stage: if (unlikely(!mutated_buf)) { - FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); + FATAL("Error in custom_fuzz. Size returned: %zu", mutated_size); } @@ -2026,7 +2026,7 @@ havoc_stage: el->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE); if (unlikely(!custom_havoc_buf)) { - FATAL("Error in custom_havoc (return %zd)", new_len); + FATAL("Error in custom_havoc (return %zu)", new_len); } @@ -2458,7 +2458,7 @@ havoc_stage: u32 use_extra = rand_below(afl, afl->a_extras_cnt); u32 extra_len = afl->a_extras[use_extra].len; - if ((s32)extra_len > temp_len) { break; } + if (extra_len > temp_len) { break; } u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION @@ -2476,7 +2476,7 @@ havoc_stage: u32 use_extra = rand_below(afl, afl->extras_cnt); u32 extra_len = afl->extras[use_extra].len; - if ((s32)extra_len > temp_len) { break; } + if (extra_len > temp_len) { break; } u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION @@ -2577,7 +2577,7 @@ havoc_stage: u32 copy_from, copy_to, copy_len; copy_len = choose_block_len(afl, new_len - 1); - if ((s32)copy_len > temp_len) copy_len = temp_len; + if (copy_len > temp_len) copy_len = temp_len; copy_from = rand_below(afl, new_len - copy_len + 1); copy_to = rand_below(afl, temp_len - copy_len + 1); @@ -2952,7 +2952,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { else orig_perf = perf_score = calculate_score(afl, afl->queue_cur); - if (unlikely(perf_score <= 0)) { goto abandon_entry; } + if (unlikely(perf_score == 0)) { goto abandon_entry; } if (unlikely(afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized)) { diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 9a0d199e..66938635 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -43,7 +43,8 @@ inline u32 select_next_queue_entry(afl_state_t *afl) { } double compute_weight(afl_state_t *afl, struct queue_entry *q, - double avg_exec_us, double avg_bitmap_size) { + double avg_exec_us, double avg_bitmap_size, + double avg_top_size) { double weight = 1.0; @@ -54,9 +55,9 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q, } - weight *= avg_exec_us / q->exec_us; + if (likely(afl->schedule < RARE)) { weight *= (avg_exec_us / q->exec_us); } weight *= (log(q->bitmap_size) / avg_bitmap_size); - + weight *= (1 + (q->tc_ref / avg_top_size)); if (unlikely(q->favored)) weight *= 5; return weight; @@ -91,6 +92,7 @@ void create_alias_table(afl_state_t *afl) { double avg_exec_us = 0.0; double avg_bitmap_size = 0.0; + double avg_top_size = 0.0; u32 active = 0; for (i = 0; i < n; i++) { @@ -102,6 +104,7 @@ void create_alias_table(afl_state_t *afl) { avg_exec_us += q->exec_us; avg_bitmap_size += log(q->bitmap_size); + avg_top_size += q->tc_ref; ++active; } @@ -110,6 +113,7 @@ void create_alias_table(afl_state_t *afl) { avg_exec_us /= active; avg_bitmap_size /= active; + avg_top_size /= active; for (i = 0; i < n; i++) { @@ -117,7 +121,8 @@ void create_alias_table(afl_state_t *afl) { if (likely(!q->disabled)) { - q->weight = compute_weight(afl, q, avg_exec_us, avg_bitmap_size); + q->weight = + compute_weight(afl, q, avg_exec_us, avg_bitmap_size, avg_top_size); q->perf_score = calculate_score(afl, q); sum += q->weight; @@ -489,11 +494,12 @@ 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; - u32 i; + u32 i; for (i = 0; i < afl->queued_paths; i++) { + struct queue_entry *q; + q = afl->queue_buf[i]; ck_free(q->fname); ck_free(q->trace_mini); @@ -996,7 +1002,7 @@ inline void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, if (unlikely(!q->testcase_buf)) { - PFATAL("Unable to malloc '%s' with len %d", q->fname, len); + PFATAL("Unable to malloc '%s' with len %u", q->fname, len); } diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 37d66aef..28585afe 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -99,12 +99,12 @@ static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u64 *cksum) { } -static void rand_replace(afl_state_t *afl, u8 *buf, u32 len) { +static void xor_replace(u8 *buf, u32 len) { u32 i; for (i = 0; i < len; ++i) { - buf[i] = rand_below(afl, 256); + buf[i] ^= 0xff; } @@ -115,8 +115,6 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { struct range *ranges = add_range(NULL, 0, len); u8 * backup = ck_alloc_nozero(len); - u8 needs_write = 0; - u64 orig_hit_cnt, new_hit_cnt; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; @@ -136,7 +134,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { /* Range not empty */ memcpy(backup, buf + rng->start, s); - rand_replace(afl, buf + rng->start, s); + xor_replace(buf + rng->start, s); u64 cksum; u64 start_us = get_cur_time_us(); @@ -158,10 +156,6 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end); memcpy(buf + rng->start, backup, s); - } else { - - needs_write = 1; - } } @@ -191,32 +185,6 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { } - // save the input with the high entropy - - if (needs_write) { - - s32 fd; - - if (afl->no_unlink) { - - fd = open(afl->queue_cur->fname, O_WRONLY | O_CREAT | O_TRUNC, 0600); - - } else { - - unlink(afl->queue_cur->fname); /* ignore errors */ - fd = open(afl->queue_cur->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); - - } - - if (fd < 0) { PFATAL("Unable to create '%s'", afl->queue_cur->fname); } - - ck_write(fd, buf, len, afl->queue_cur->fname); - afl->queue_cur->len = len; // no-op, just to be 100% safe - - close(fd); - - } - return 0; checksum_fail: @@ -232,8 +200,6 @@ checksum_fail: } - // TODO: clang notices a _potential_ leak of mem pointed to by rng - return 1; } @@ -479,6 +445,10 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { u32 k; u8 cons_ff = 0, cons_0 = 0; + + if (shape > sizeof(v)) + FATAL("shape is greater than %zu, please report!", sizeof(v)); + for (k = 0; k < shape; ++k) { if (b[k] == 0) { @@ -487,7 +457,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { } else if (b[k] == 0xff) { - ++cons_0; + ++cons_ff; } else { @@ -701,12 +671,12 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { u8 status = 0; // opt not in the paper - u32 fails = 0; - u8 found_one = 0; + // u32 fails = 0; + u8 found_one = 0; for (i = 0; i < loggeds; ++i) { - fails = 0; + u32 fails = 0; struct cmpfn_operands *o = &((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[i]; @@ -802,13 +772,13 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, u64 exec_cksum) { u8 r = 1; - if (afl->orig_cmp_map == NULL) { + if (unlikely(!afl->orig_cmp_map)) { afl->orig_cmp_map = ck_alloc_nozero(sizeof(struct cmp_map)); } - if (afl->pass_stats == NULL) { + if (unlikely(!afl->pass_stats)) { afl->pass_stats = ck_alloc(sizeof(struct afl_pass_stat) * CMP_MAP_W); @@ -888,7 +858,7 @@ exit_its: afl->stage_finds[STAGE_ITS] += new_hit_cnt - orig_hit_cnt; afl->stage_cycles[STAGE_ITS] += afl->fsrv.total_execs - orig_execs; - memcpy(orig_buf, buf, len); + memcpy(buf, orig_buf, len); return r; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 339fb9c3..17c305ed 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -230,10 +230,10 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, hash64(afl->fsrv.shmem_fuzz, *afl->fsrv.shmem_fuzz_len, 0xa5b35705), *afl->fsrv.shmem_fuzz_len); fprintf(stderr, "SHM :"); - for (int i = 0; i < *afl->fsrv.shmem_fuzz_len; i++) + for (u32 i = 0; i < *afl->fsrv.shmem_fuzz_len; i++) fprintf(stderr, "%02x", afl->fsrv.shmem_fuzz[i]); fprintf(stderr, "\nORIG:"); - for (int i = 0; i < *afl->fsrv.shmem_fuzz_len; i++) + for (u32 i = 0; i < *afl->fsrv.shmem_fuzz_len; i++) fprintf(stderr, "%02x", (u8)((u8 *)mem)[i]); fprintf(stderr, "\n"); @@ -296,11 +296,11 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, u32 handicap, u8 from_queue) { + if (unlikely(afl->shm.cmplog_mode)) { q->exec_cksum = 0; } + u8 fault = 0, new_bits = 0, var_detected = 0, hnb = 0, first_run = (q->exec_cksum == 0); - - u64 start_us, stop_us; - + u64 start_us, stop_us, diff_us; s32 old_sc = afl->stage_cur, old_sm = afl->stage_max; u32 use_tmout = afl->fsrv.exec_tmout; u8 *old_sn = afl->stage_name; @@ -422,15 +422,32 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } - stop_us = get_cur_time_us(); + if (unlikely(afl->fixed_seed)) { + + diff_us = (u64)(afl->fsrv.exec_tmout - 1) * (u64)afl->stage_max; + + } else { + + stop_us = get_cur_time_us(); + diff_us = stop_us - start_us; + if (unlikely(!diff_us)) { ++diff_us; } - afl->total_cal_us += stop_us - start_us; + } + + afl->total_cal_us += diff_us; afl->total_cal_cycles += afl->stage_max; /* OK, let's collect some stats about the performance of this test case. This is used for fuzzing air time calculations in calculate_score(). */ - q->exec_us = (stop_us - start_us) / afl->stage_max; + if (unlikely(!afl->stage_max)) { + + // Pretty sure this cannot happen, yet scan-build complains. + FATAL("BUG: stage_max should not be 0 here! Please report this condition."); + + } + + q->exec_us = diff_us / afl->stage_max; q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits); q->handicap = handicap; q->cal_failed = 0; @@ -682,7 +699,7 @@ void sync_fuzzers(afl_state_t *afl) { // same time. If so, the first temporary main node running again will demote // themselves so this is not an issue - u8 path[PATH_MAX]; + // u8 path2[PATH_MAX]; afl->is_main_node = 1; sprintf(path, "%s/is_main_node", afl->out_dir); int fd = open(path, O_CREAT | O_RDWR, 0644); diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 34456c0d..60c9684c 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -418,6 +418,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { (u8 *)get_afl_env(afl_environment_variables[i]); #endif + } else if (!strncmp(env, "AFL_KILL_SIGNAL", + + afl_environment_variable_len)) { + + afl->afl_env.afl_kill_signal = + (u8 *)get_afl_env(afl_environment_variables[i]); + } } else { @@ -524,8 +531,8 @@ void afl_states_stop(void) { LIST_FOREACH(&afl_states, afl_state_t, { - if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, SIGKILL); - if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, SIGKILL); + if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, el->fsrv.kill_signal); + if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, el->fsrv.kill_signal); }); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index cb0d3dcd..e67bace9 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -31,8 +31,7 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { - char *val; - u8 fn[PATH_MAX]; + u8 fn[PATH_MAX]; snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir); FILE *f = create_ffile(fn); u32 i; @@ -44,6 +43,7 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { for (i = 0; i < s_afl_env; ++i) { + char *val; if ((val = getenv(afl_environment_variables[i])) != NULL) { fprintf(f, "%s=%s\n", afl_environment_variables[i], val); @@ -58,7 +58,11 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { for (i = 0; i < argc; ++i) { if (i) fprintf(f, " "); +#ifdef __ANDROID__ + if (memchr(argv[i], '\'', sizeof(argv[i]))) { +#else if (index(argv[i], '\'')) { +#endif fprintf(f, "'"); for (j = 0; j < strlen(argv[i]); j++) @@ -120,8 +124,8 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, cur_time - afl->last_avg_exec_update >= 60000))) { afl->last_avg_execs_saved = - (float)(1000 * (afl->fsrv.total_execs - afl->last_avg_execs)) / - (float)(cur_time - afl->last_avg_exec_update); + (double)(1000 * (afl->fsrv.total_execs - afl->last_avg_execs)) / + (double)(cur_time - afl->last_avg_exec_update); afl->last_avg_execs = afl->fsrv.total_execs; afl->last_avg_exec_update = cur_time; @@ -228,7 +232,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, if (afl->virgin_bits[i] != 0xff) { - fprintf(f, " %d[%02x]", i, afl->virgin_bits[i]); + fprintf(f, " %u[%02x]", i, afl->virgin_bits[i]); } @@ -238,7 +242,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, fprintf(f, "var_bytes :"); for (i = 0; i < afl->fsrv.map_size; i++) { - if (afl->var_bytes[i]) { fprintf(f, " %d", i); } + if (afl->var_bytes[i]) { fprintf(f, " %u", i); } } @@ -1163,7 +1167,7 @@ void show_init_stats(afl_state_t *afl) { } else { - ACTF("-t option specified. We'll use an exec timeout of %d ms.", + ACTF("-t option specified. We'll use an exec timeout of %u ms.", afl->fsrv.exec_tmout); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 2af374f2..7facf261 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -76,8 +76,17 @@ static void at_exit() { } - if (pid1 > 0) { kill(pid1, SIGKILL); } - if (pid2 > 0) { kill(pid2, SIGKILL); } + int kill_signal = SIGKILL; + + /* AFL_KILL_SIGNAL should already be a valid int at this point */ + if (getenv("AFL_KILL_SIGNAL")) { + + kill_signal = atoi(getenv("AFL_KILL_SIGNAL")); + + } + + if (pid1 > 0) { kill(pid1, kill_signal); } + if (pid2 > 0) { kill(pid2, kill_signal); } } @@ -94,13 +103,13 @@ static void usage(u8 *argv0, int more_help) { "Execution control settings:\n" " -p schedule - power schedules compute a seed's performance score:\n" - " <explore(default), rare, exploit, seek, mmopt, coe, " - "fast,\n" + " <fast(default), rare, exploit, seek, mmopt, coe, " + "explore,\n" " lin, quad> -- see docs/power_schedules.md\n" " -f file - location read by the fuzzed program (default: stdin " "or @@)\n" - " -t msec - timeout for each run (auto-scaled, 50-%d ms)\n" - " -m megs - memory limit for child process (%d MB, 0 = no limit)\n" + " -t msec - timeout for each run (auto-scaled, 50-%u ms)\n" + " -m megs - memory limit for child process (%u MB, 0 = no limit)\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 " @@ -185,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" @@ -299,7 +309,8 @@ int main(int argc, char **argv_orig, char **envp) { s32 opt, i, auto_sync = 0 /*, user_set_cache = 0*/; u64 prev_queued = 0; - u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, map_size = MAP_SIZE; + u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, + map_size = get_map_size(); u8 *extras_dir[4]; u8 mem_limit_given = 0, exit_1 = 0, debug = 0, extras_dir_cnt = 0 /*, have_p = 0*/; @@ -326,7 +337,6 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_DEBUG")) { debug = afl->debug = 1; } - map_size = get_map_size(); afl_state_init(afl, map_size); afl->debug = debug; afl_fsrv_init(&afl->fsrv); @@ -575,7 +585,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->timeout_given) { FATAL("Multiple -t options not supported"); } - if (sscanf(optarg, "%u%c", &afl->fsrv.exec_tmout, &suffix) < 1 || + if (!optarg || sscanf(optarg, "%u%c", &afl->fsrv.exec_tmout, &suffix) < 1 || optarg[0] == '-') { FATAL("Bad syntax used for -t"); @@ -757,7 +767,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'V': { afl->most_time_key = 1; - if (sscanf(optarg, "%llu", &afl->most_time) < 1 || optarg[0] == '-') { + if (!optarg || sscanf(optarg, "%llu", &afl->most_time) < 1 || optarg[0] == '-') { FATAL("Bad syntax used for -V"); @@ -768,7 +778,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'E': { afl->most_execs_key = 1; - if (sscanf(optarg, "%llu", &afl->most_execs) < 1 || optarg[0] == '-') { + if (!optarg || sscanf(optarg, "%llu", &afl->most_execs) < 1 || optarg[0] == '-') { FATAL("Bad syntax used for -E"); @@ -976,6 +986,9 @@ int main(int argc, char **argv_orig, char **envp) { #endif + afl->fsrv.kill_signal = + parse_afl_kill_signal_env(afl->afl_env.afl_kill_signal, SIGKILL); + setup_signal_handlers(); check_asan_opts(afl); @@ -1534,7 +1547,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!afl->pending_not_fuzzed) { - FATAL("We need at least on valid input seed that does not crash!"); + FATAL("We need at least one valid input seed that does not crash!"); } @@ -1767,15 +1780,27 @@ int main(int argc, char **argv_orig, char **envp) { } while (skipped_fuzz && afl->queue_cur && !afl->stop_soon); - if (!afl->stop_soon && afl->sync_id) { + if (likely(!afl->stop_soon && afl->sync_id)) { + + if (likely(afl->skip_deterministic)) { - if (unlikely(afl->is_main_node)) { + if (unlikely(afl->is_main_node)) { - if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) { sync_fuzzers(afl); } + if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) { + + sync_fuzzers(afl); + + } + + } else { + + if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); } + + } } else { - if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); } + sync_fuzzers(afl); } diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c index 1aea3e40..ac002a93 100644 --- a/src/afl-gotcpu.c +++ b/src/afl-gotcpu.c @@ -35,9 +35,6 @@ #define _GNU_SOURCE #endif -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif #include <stdio.h> #include <stdlib.h> #include <unistd.h> diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index fccdb1a5..0671d1c4 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -187,7 +187,7 @@ static void edit_params(int argc, char **argv) { if (debug) DEBUGF( - "passthrough=%s instrim=%d, gold_pos=%d, gold_present=%s " + "passthrough=%s instrim=%u, gold_pos=%u, gold_present=%s " "inst_present=%s rt_present=%s rt_lto_present=%s\n", passthrough ? "true" : "false", instrim, gold_pos, gold_present ? "true" : "false", inst_present ? "true" : "false", @@ -252,11 +252,10 @@ static void edit_params(int argc, char **argv) { int main(int argc, char **argv) { - s32 pid, i, status; - u8 * ptr; + s32 pid, i, status; char thecwd[PATH_MAX]; - if ((ptr = getenv("AFL_LD_CALLER")) != NULL) { + if (getenv("AFL_LD_CALLER") != NULL) { FATAL("ld loop detected! Set AFL_REAL_LD!\n"); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 355b2dc3..6d95fc1d 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -31,9 +31,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif #include "config.h" #include "types.h" #include "debug.h" @@ -662,7 +659,7 @@ static void usage(u8 *argv0) { "Execution control settings:\n" " -t msec - timeout for each run (none)\n" - " -m megs - memory limit for child process (%d MB)\n" + " -m megs - memory limit for child process (%u 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" @@ -693,12 +690,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); @@ -1014,9 +1012,9 @@ int main(int argc, char **argv_orig, char **envp) { DIR * dir_in, *dir_out = NULL; struct dirent *dir_ent; - int done = 0; - u8 infile[PATH_MAX], outfile[PATH_MAX]; - u8 wait_for_gdb = 0; + // int done = 0; + u8 infile[PATH_MAX], outfile[PATH_MAX]; + u8 wait_for_gdb = 0; #if !defined(DT_REG) struct stat statbuf; #endif @@ -1090,11 +1088,11 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_DEBUG")) { - int i = optind; + int j = optind; DEBUGF("%s:", fsrv->target_path); - while (argv[i] != NULL) { + while (argv[j] != NULL) { - SAYF(" \"%s\"", argv[i++]); + SAYF(" \"%s\"", argv[j++]); } @@ -1115,6 +1113,9 @@ int main(int argc, char **argv_orig, char **envp) { } + fsrv->kill_signal = + parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); + if (getenv("AFL_CRASH_EXITCODE")) { long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); @@ -1143,7 +1144,7 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - while (done == 0 && (dir_ent = readdir(dir_in))) { + while ((dir_ent = readdir(dir_in))) { if (dir_ent->d_name[0] == '.') { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index ed928c7c..5fd60cd2 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -29,10 +29,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif - #include "config.h" #include "types.h" #include "debug.h" @@ -835,8 +831,8 @@ static void usage(u8 *argv0) { "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" + " -t msec - timeout for each run (%u ms)\n" + " -m megs - memory limit for child process (%u 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 " @@ -855,6 +851,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 +1131,9 @@ int main(int argc, char **argv_orig, char **envp) { } + fsrv->kill_signal = + parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); + if (getenv("AFL_CRASH_EXITCODE")) { long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); diff --git a/test/test-basic.sh b/test/test-basic.sh index 79f90ea0..8296b6cc 100755 --- a/test/test-basic.sh +++ b/test/test-basic.sh @@ -106,7 +106,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc ;; esac } else { - $ECHO "$GRAY[*] no bash available, cannot test afl-cmin.bash" + $ECHO "$GREY[*] no bash available, cannot test afl-cmin.bash" } fi ../afl-tmin -m ${MEM_LIMIT} -i in/in2 -o in2/in2 -- ./test-instr.plain > /dev/null 2>&1 @@ -210,7 +210,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc CNT=`ls in2/* 2>/dev/null | wc -l` case "$CNT" in *2) $ECHO "$GREEN[+] afl-cmin correctly minimized the number of testcases" ;; - 1) { + \ *1|1) { # allow leading whitecase for portability test -s in2/* && $ECHO "$YELLOW[?] afl-cmin did minimize to one testcase. This can be a bug or due compiler optimization." test -s in2/* || { $ECHO "$RED[!] afl-cmin did not correctly minimize the number of testcases ($CNT)" @@ -229,8 +229,8 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc CNT=`ls in2/* 2>/dev/null | wc -l` case "$CNT" in *2) $ECHO "$GREEN[+] afl-cmin.bash correctly minimized the number of testcases" ;; - 1) { - test -s in2/* && $ECHO "$YELLOW[?] afl-cmin.bash did minimize to one testcase. This can be a bug or due compiler optimization." + \ *1|1) { # allow leading whitecase for portability + test -s in2/* && $ECHO "$YELLOW[?] afl-cmin.bash did minimize to one testcase. This can be a bug or due compiler optimization." test -s in2/* || { $ECHO "$RED[!] afl-cmin.bash did not correctly minimize the number of testcases ($CNT)" CODE=1 @@ -242,7 +242,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc ;; esac } else { - $ECHO "$GRAY[*] no bash available, cannot test afl-cmin.bash" + $ECHO "$GREY[*] no bash available, cannot test afl-cmin.bash" } fi ../afl-tmin -m ${MEM_LIMIT} -i in/in2 -o in2/in2 -- ./test-instr.plain > /dev/null 2>&1 diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index f5537ed8..2dbc30b8 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -768e6bb2 +83d1b426 diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh index f1306a06..8f6ceab7 100755 --- a/unicorn_mode/build_unicorn_support.sh +++ b/unicorn_mode/build_unicorn_support.sh @@ -44,7 +44,7 @@ echo "[*] Performing basic sanity checks..." PLT=`uname -s` -if [ ! "$PLT" = "Linux" ] && [ ! "$PLT" = "Darwin" ] && [ ! "$PLT" = "FreeBSD" ] && [ ! "$PLT" = "NetBSD" ] && [ ! "$PLT" = "OpenBSD" ]; then +if [ ! "$PLT" = "Linux" ] && [ ! "$PLT" = "Darwin" ] && [ ! "$PLT" = "FreeBSD" ] && [ ! "$PLT" = "NetBSD" ] && [ ! "$PLT" = "OpenBSD" ] && [ ! "$PLT" = "DragonFly" ]; then echo "[-] Error: Unicorn instrumentation is unsupported on $PLT." exit 1 @@ -89,6 +89,12 @@ if [ "$PLT" = "FreeBSD" ]; then TARCMD=gtar fi +if [ "$PLT" = "DragonFly" ]; then + MAKECMD=gmake + CORES=`sysctl -n hw.ncpu` + TARCMD=tar +fi + if [ "$PLT" = "NetBSD" ] || [ "$PLT" = "OpenBSD" ]; then MAKECMD=gmake CORES=`sysctl -n hw.ncpu` @@ -150,6 +156,7 @@ if [ $? -eq 0 ]; then echo "[*] initializing unicornafl submodule" git submodule init || exit 1 git submodule update ./unicornafl 2>/dev/null # ignore errors + git submodule sync ./unicornafl 2>/dev/null # ignore errors else echo "[*] cloning unicornafl" test -d unicornafl || { diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl -Subproject 8cca4801adb767dce7cf72202d7d25bdb420cf7 +Subproject 83d1b426be5d373edcc81576f58a10f617df143 diff --git a/utils/afl_frida/afl-frida.c b/utils/afl_frida/afl-frida.c index b5b8196d..087f18e8 100644 --- a/utils/afl_frida/afl-frida.c +++ b/utils/afl_frida/afl-frida.c @@ -153,7 +153,7 @@ static int enumerate_ranges(const GumRangeDetails *details, } -int main() { +int main(int argc, char** argv) { #ifndef __APPLE__ (void)personality(ADDR_NO_RANDOMIZE); // disable ASLR @@ -164,105 +164,140 @@ int main() { // If there is just one function, then there is nothing to change // or add here. - void *dl = dlopen(TARGET_LIBRARY, RTLD_LAZY); + void *dl = NULL; + if (argc > 2) { + dl = dlopen(argv[1], RTLD_LAZY); + } else { + dl = dlopen(TARGET_LIBRARY, RTLD_LAZY); + } if (!dl) { - fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY); + if (argc > 2) + fprintf(stderr, "Could not load %s\n", argv[1]); + else + fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY); exit(-1); } - if (!(o_function = dlsym(dl, TARGET_FUNCTION))) { + if (argc > 2) + o_function = dlsym(dl, argv[2]); + else + o_function = dlsym(dl, TARGET_FUNCTION); + if (!o_function) { - fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION); + if (argc > 2) + fprintf(stderr, "Could not find function %s\n", argv[2]); + else + fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION); exit(-1); } // END STEP 2 - gum_init_embedded(); - if (!gum_stalker_is_supported()) { - - gum_deinit_embedded(); - return 1; - - } - - GumStalker *stalker = gum_stalker_new(); - - 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; - guint64 code_end = code_range.base_address + code_range.size; - range_t instr_range = {0, code_start, code_end}; - - printf("Frida instrumentation: base=0x%lx instrumenting=0x%lx-%lx\n", - base_address, code_start, code_end); - if (!code_start || !code_end) { - - fprintf(stderr, "Error: no valid memory address found for %s\n", - TARGET_LIBRARY); - exit(-1); - - } - - GumStalkerTransformer *transformer = - gum_stalker_transformer_make_from_callback(instr_basic_block, - &instr_range, NULL); - - // 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, NULL); - - 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); - + if (!getenv("AFL_FRIDA_TEST_INPUT")) { + gum_init_embedded(); + if (!gum_stalker_is_supported()) { + + gum_deinit_embedded(); + return 1; + } + + GumStalker *stalker = gum_stalker_new(); + + GumAddress base_address; + if (argc > 2) + base_address = gum_module_find_base_address(argv[1]); + else + base_address = gum_module_find_base_address(TARGET_LIBRARY); + GumMemoryRange code_range; + if (argc > 2) + gum_module_enumerate_ranges(argv[1], GUM_PAGE_RX, enumerate_ranges, + &code_range); + else + gum_module_enumerate_ranges(TARGET_LIBRARY, GUM_PAGE_RX, enumerate_ranges, + &code_range); + + guint64 code_start = code_range.base_address; + guint64 code_end = code_range.base_address + code_range.size; + range_t instr_range = {0, code_start, code_end}; + + printf("Frida instrumentation: base=0x%lx instrumenting=0x%lx-%lx\n", + base_address, code_start, code_end); + if (!code_start || !code_end) { + + if (argc > 2) + fprintf(stderr, "Error: no valid memory address found for %s\n", + argv[1]); + else + fprintf(stderr, "Error: no valid memory address found for %s\n", + TARGET_LIBRARY); + exit(-1); + + } + + GumStalkerTransformer *transformer = + gum_stalker_transformer_make_from_callback(instr_basic_block, + &instr_range, NULL); + + // 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, NULL); + + 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); + gum_deinit_embedded(); - // END STEP 3 - + } else { + char buf[8*1024] = {0}; + int count = read(0, buf, sizeof(buf)); + buf[8*1024-1] = '\0'; + (*o_function)(buf, count); } - gum_stalker_unfollow_me(stalker); - - while (gum_stalker_garbage_collect(stalker)) - g_usleep(10000); - - g_object_unref(stalker); - g_object_unref(transformer); - gum_deinit_embedded(); - return 0; } diff --git a/utils/afl_frida/android/README.md b/utils/afl_frida/android/README.md new file mode 100644 index 00000000..044b48a1 --- /dev/null +++ b/utils/afl_frida/android/README.md @@ -0,0 +1 @@ +For android, frida-gum package (ex. https://github.com/frida/frida/releases/download/14.2.6/frida-gum-devkit-14.2.6-android-arm64.tar.xz) is needed to be extracted in the directory. diff --git a/utils/afl_frida/android/frida-gum-example.c b/utils/afl_frida/android/frida-gum-example.c new file mode 100644 index 00000000..14d98248 --- /dev/null +++ b/utils/afl_frida/android/frida-gum-example.c @@ -0,0 +1,130 @@ +/* + * Compile with: + * + * clang -fPIC -DANDROID -ffunction-sections -fdata-sections -Os -pipe -g3 frida-gum-example.c -o frida-gum-example -L. -lfrida-gum -llog -ldl -lm -pthread -Wl,--gc-sections,-z,noexecstack,-z,relro,-z,now -fuse-ld=gold -fuse-ld=gold -Wl,--icf=all + * + * Visit https://frida.re to learn more about Frida. + */ + +#include "frida-gum.h" + +#include <fcntl.h> +#include <unistd.h> + +typedef struct _ExampleListener ExampleListener; +typedef enum _ExampleHookId ExampleHookId; + +struct _ExampleListener +{ + GObject parent; + + guint num_calls; +}; + +enum _ExampleHookId +{ + EXAMPLE_HOOK_OPEN, + EXAMPLE_HOOK_CLOSE +}; + +static void example_listener_iface_init (gpointer g_iface, gpointer iface_data); + +#define EXAMPLE_TYPE_LISTENER (example_listener_get_type ()) +G_DECLARE_FINAL_TYPE (ExampleListener, example_listener, EXAMPLE, LISTENER, GObject) +G_DEFINE_TYPE_EXTENDED (ExampleListener, + example_listener, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE (GUM_TYPE_INVOCATION_LISTENER, + example_listener_iface_init)) + +int +main (int argc, + char * argv[]) +{ + GumInterceptor * interceptor; + GumInvocationListener * listener; + + gum_init_embedded (); + + interceptor = gum_interceptor_obtain (); + listener = g_object_new (EXAMPLE_TYPE_LISTENER, NULL); + + gum_interceptor_begin_transaction (interceptor); + gum_interceptor_attach (interceptor, + GSIZE_TO_POINTER (gum_module_find_export_by_name (NULL, "open")), + listener, + GSIZE_TO_POINTER (EXAMPLE_HOOK_OPEN)); + gum_interceptor_attach (interceptor, + GSIZE_TO_POINTER (gum_module_find_export_by_name (NULL, "close")), + listener, + GSIZE_TO_POINTER (EXAMPLE_HOOK_CLOSE)); + gum_interceptor_end_transaction (interceptor); + + close (open ("/etc/hosts", O_RDONLY)); + close (open ("/etc/fstab", O_RDONLY)); + + g_print ("[*] listener got %u calls\n", EXAMPLE_LISTENER (listener)->num_calls); + + gum_interceptor_detach (interceptor, listener); + + close (open ("/etc/hosts", O_RDONLY)); + close (open ("/etc/fstab", O_RDONLY)); + + g_print ("[*] listener still has %u calls\n", EXAMPLE_LISTENER (listener)->num_calls); + + g_object_unref (listener); + g_object_unref (interceptor); + + gum_deinit_embedded (); + + return 0; +} + +static void +example_listener_on_enter (GumInvocationListener * listener, + GumInvocationContext * ic) +{ + ExampleListener * self = EXAMPLE_LISTENER (listener); + ExampleHookId hook_id = GUM_IC_GET_FUNC_DATA (ic, ExampleHookId); + + switch (hook_id) + { + case EXAMPLE_HOOK_OPEN: + g_print ("[*] open(\"%s\")\n", (const gchar *) gum_invocation_context_get_nth_argument (ic, 0)); + break; + case EXAMPLE_HOOK_CLOSE: + g_print ("[*] close(%d)\n", GPOINTER_TO_INT (gum_invocation_context_get_nth_argument (ic, 0))); + break; + } + + self->num_calls++; +} + +static void +example_listener_on_leave (GumInvocationListener * listener, + GumInvocationContext * ic) +{ +} + +static void +example_listener_class_init (ExampleListenerClass * klass) +{ + (void) EXAMPLE_IS_LISTENER; + (void) glib_autoptr_cleanup_ExampleListener; +} + +static void +example_listener_iface_init (gpointer g_iface, + gpointer iface_data) +{ + GumInvocationListenerInterface * iface = g_iface; + + iface->on_enter = example_listener_on_enter; + iface->on_leave = example_listener_on_leave; +} + +static void +example_listener_init (ExampleListener * self) +{ +} diff --git a/utils/afl_network_proxy/afl-network-server.c b/utils/afl_network_proxy/afl-network-server.c index 513dc8f2..fe225416 100644 --- a/utils/afl_network_proxy/afl-network-server.c +++ b/utils/afl_network_proxy/afl-network-server.c @@ -24,10 +24,6 @@ #define AFL_MAIN -#ifdef __ANDROID__ - #include "android-ashmem.h" -#endif - #include "config.h" #include "types.h" #include "debug.h" diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c index c6f5a76c..30e6ebb9 100644 --- a/utils/aflpp_driver/aflpp_driver.c +++ b/utils/aflpp_driver/aflpp_driver.c @@ -1,12 +1,8 @@ -//===- 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 +//===- afl_driver.cpp - a glue between AFL++ and libFuzzer ------*- C++ -* ===// //===----------------------------------------------------------------------===// /* This file allows to fuzz libFuzzer-style target functions - (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode. + (LLVMFuzzerTestOneInput) with AFL++ using persistent in-memory fuzzing. Usage: ################################################################################ @@ -25,25 +21,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { EOF # Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang. -clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c +clang -c aflpp_driver.c # Build afl-compiler-rt.o.c from the AFL distribution. -clang -c -w $AFL_HOME/instrumentation/afl-compiler-rt.o.c +clang -c $AFL_HOME/instrumentation/afl-compiler-rt.o.c # Build this file, link it with afl-compiler-rt.o.o and the target code. -clang++ afl_driver.cpp test_fuzzer.o afl-compiler-rt.o.o +afl-clang-fast -o test_fuzzer test_fuzzer.cc afl-compiler-rt.o aflpp_driver.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 <assert.h> #include <errno.h> #include <stdarg.h> @@ -65,47 +53,6 @@ If 1, close stdout at startup. If 2 close stderr; if 3 close both. #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; diff --git a/utils/defork/defork.c b/utils/defork/defork.c index f71d1124..f50b9a4b 100644 --- a/utils/defork/defork.c +++ b/utils/defork/defork.c @@ -1,4 +1,4 @@ -#define __GNU_SOURCE +#define _GNU_SOURCE #include <dlfcn.h> #include <unistd.h> #include <stdio.h> diff --git a/utils/libdislocator/README.md b/utils/libdislocator/README.md index 1785463e..d0340af0 100644 --- a/utils/libdislocator/README.md +++ b/utils/libdislocator/README.md @@ -1,6 +1,6 @@ # libdislocator, an abusive allocator - (See ../README.md for the general instruction manual.) + (See ../../README.md for the general instruction manual.) This is a companion library that can be used as a drop-in replacement for the libc allocator in the fuzzed binaries. It improves the odds of bumping into diff --git a/utils/libdislocator/libdislocator.so.c b/utils/libdislocator/libdislocator.so.c index 2324e390..c041fec6 100644 --- a/utils/libdislocator/libdislocator.so.c +++ b/utils/libdislocator/libdislocator.so.c @@ -345,10 +345,10 @@ void free(void *ptr) { len = PTR_L(ptr); total_mem -= len; + u8 *ptr_ = ptr; if (align_allocations && (len & (ALLOC_ALIGN_SIZE - 1))) { - u8 * ptr_ = ptr; size_t rlen = (len & ~(ALLOC_ALIGN_SIZE - 1)) + ALLOC_ALIGN_SIZE; for (; len < rlen; ++len) if (ptr_[len] != TAIL_ALLOC_CANARY) @@ -359,11 +359,13 @@ void free(void *ptr) { /* Protect everything. Note that the extra page at the end is already set as PROT_NONE, so we don't need to touch that. */ - ptr -= PAGE_SIZE * PG_COUNT(len + 8) - len - 8; + ptr_ -= PAGE_SIZE * PG_COUNT(len + 8) - len - 8; - if (mprotect(ptr - 8, PG_COUNT(len + 8) * PAGE_SIZE, PROT_NONE)) + if (mprotect(ptr_ - 8, PG_COUNT(len + 8) * PAGE_SIZE, PROT_NONE)) FATAL("mprotect() failed when freeing memory"); + ptr = ptr_; + /* Keep the mapping; this is wasteful, but prevents ptr reuse. */ } diff --git a/utils/libtokencap/README.md b/utils/libtokencap/README.md index 13a440da..a39ed3a5 100644 --- a/utils/libtokencap/README.md +++ b/utils/libtokencap/README.md @@ -1,6 +1,11 @@ # strcmp() / memcmp() token capture library - (See ../README.md for the general instruction manual.) + NOTE: libtokencap is only recommended for binary-only targets or targets that + do not compile with afl-clang-fast/afl-clang-lto. + The afl-clang-fast AFL_LLVM_DICT2FILE feature is much better, afl-clang-lto + has that feature automatically integrated. + + (See ../../README.md for the general instruction manual.) This companion library allows you to instrument `strcmp()`, `memcmp()`, and related functions to automatically extract syntax tokens passed to any of diff --git a/utils/persistent_mode/Makefile b/utils/persistent_mode/Makefile index 6fa1c30e..e348c46c 100644 --- a/utils/persistent_mode/Makefile +++ b/utils/persistent_mode/Makefile @@ -1,10 +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 + ../../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 + 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/qemu_persistent_hook/test.c b/utils/qemu_persistent_hook/test.c index afeff202..a0e815dc 100644 --- a/utils/qemu_persistent_hook/test.c +++ b/utils/qemu_persistent_hook/test.c @@ -2,7 +2,7 @@ int target_func(unsigned char *buf, int size) { - printf("buffer:%p, size:%p\n", buf, size); + printf("buffer:%p, size:%d\n", buf, size); switch (buf[0]) { case 1: |