Based on google/fuzzing repo.
First, read the Introduction to fuzzing and follow the links from that page to get more familiar with the subject of fuzzing.
bool FuzzMe(const uint8_t *Data, size_t DataSize) {
return DataSize >= 3 &&
Data[0] == 'F' &&
Data[1] == 'U' &&
Data[2] == 'Z' &&
Data[3] == 'Z'; // :‑<
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
FuzzMe(Data, Size);
return 0;
}
clang++ -g -fsanitize=address,undefined,fuzzer -fprofile-instr-generate -fcoverage-mapping -O1 -o fuzzer fuzzer.cc
Explanation:
-g
: add debug info(better stack traces)-fsanitize=address,undefined,fuzzer
: enable AddressSanitizer, UndefinedBehaviorSanitizer and fuzzing runtime-fprofile-instr-generate -fcoverage-mapping
: needed for code coverageexport LLVM_PROFILE_FILE=fuzzer.profraw
export ASAN_OPTIONS=log_path=out/sanitizers.log
export UBSAN_OPTIONS=print_stacktrace=1
mkdir -p out/artifacts/
./fuzzer -max_total_time=10 -artifact_prefix=out/artifacts/
Explanation:
fuzzer.profraw
out/sanitizers.log
ubsan
10s
out/artifacts/
-artifact_prefix
can be omitted if you want the sanitizer logs combined with the fuzz target's logs.
Index the raw profile:
llvm-profdata merge -sparse fuzzer.profraw -o fuzzer.profdata
Show coverage on command line:
llvm-cov show -instr-profile=fuzzer.profdata fuzzer
Generate HTML report:
llvm-cov show -instr-profile=fuzzer.profdata -format=html -o=coverage fuzzer
Open coverage/index.html
to see the report.
More than one raw profile can be merged togheter and coverage can be generated for all binaries corresponding to those profiles:
llvm-profdata merge -sparse fuzzer1.profraw fuzzer2.profraw -o fuzzer.profdata
llvm-cov show fuzzer1 -object fuzzer1 -instr-profile=fuzzer.profdata
Only some file/directory can be selected and regexps can be used to ignore certain files/dirs via -ignore-filename-regex
.
For example:
src
directory:llvm-cov show fuzzer1 src/ -object=fuzzer2 -instr-profile=fuzzer.profdata
src/foo.cc
file:llvm-cov show fuzzer1 src/foo.cc -object=fuzzer2 -instr-profile=fuzzer.profdata
src
directory and those that don't end with _test.cc
:llvm-cov show -ignore-filename-regex=".*_test.cc" fuzzer1 src/ -object=fuzzer2 -instr-profile=fuzzer.profdata
Terms used:
reproducers
: previous artifacts(crashers etc.)seed_corpus
: inital set of inputs which are valid for the fuzz targetprevious_corpus
: corpus from a previous run of the fuzzercurrent_corpus
: contains seed_corpus
+ previous_corpus
+ any other new input generated by current run of the fuzzerCreate initial corpus:
mkdir current_corpus
cp reproducers/* current_corpus/
cp seed_corpus/* current_corpus/
cp previous_corpus/* current_corpus/
Run the fuzzer:
./fuzzer current_corpus
Add new items from current_corpus
to previous_corpus
:
./fuzzer -merge=1 previous_corpus current_corpus
Minimize previous_corpus
:
./fuzzer -merge=1 tmp_corpus previous_corpus
rm -rf previous_corpus
mv tmp_corpus previous_corpus
Minimize a reproducer:
./fuzzer -minimize_crash=1 -runs=10000 out/artifacts/crash-0eb8e4ed029b774d80f2b66408203801cb982a60