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.profrawout/sanitizers.logubsan10sout/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