Stockholm C++ 20190314
The biggest improvement!
Both use feedback, compiler instrumentation
AFL | LibFuzzer | |
---|---|---|
Status | stable | stable and improving |
Performance | "slow" | fast |
UI | great | ok |
Disclaimer: this is *my opinion* :-)
bdecode, by Arvid Norberg
parses a tree from a serialized format
From a bdecode unit test:
char b[] = "i12453e"; bdecode_node e; error_code ec; int ret = bdecode(b, b + sizeof(b)-1, e, ec);
$apt install afl g++ afl-clang clang++-6.0
entrypoint_afl_plain.cpp
#include "bdecode.hpp" #include <array> #include <cassert> #include <fstream> int main(int argc, char* argv[]) { std::ifstream ifs(argv[1]); std::array<char, 8192> buf; ifs.read(buf.data(), buf.size()); auto nbytes = ifs.gcount(); bdecode_node e; error_code ec; int ret = bdecode(buf.begin(),buf.begin() + nbytes, e, ec); }
afl-g++ entrypoint_afl_plain.cpp \ bdecode.cpp -lboost_system -o afl_plain
mkdir -p corpus echo "" >corpus/empty
Note: putting more effort into this can pay off well
mkdir -p output-afl-plain
afl-fuzz -i corpus/ -o output-afl-plain/ -- ./afl_plain @@
entrypoint_libfuzzer.cpp
#include "bdecode.hpp" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { bdecode_node e; error_code ec; auto b = reinterpret_cast<const char*>(Data); int ret = bdecode(b, b + Size, e, ec); return 0; }
clang++-6.0 -std=c++14 -g -O3 -fsanitize=fuzzer \ entrypoint_libfuzzer.cpp bdecode.cpp -lboost_system -o libfuzzer_plain
mkdir -p output-libfuzzer-plain ./libfuzzer_plain output-libfuzzer-plain/
make run-libfuzzer-plain
#1450971 REDUCE cov: 96 ft: 295 corp: 112/5838b \ exec/s: 483657 rss: 33Mb L: 293/1072 MS: 1 EraseBytes-https://llvm.org/docs/LibFuzzer.html#output
Minimal program to replay an input
For running in a debugger, valgrind
There are caveats!