|home| |posts| |projects| |cv| |bookmarks| |github|

Fuzztesting Cpp

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.

Fuzz target

bool FuzzMe(const uint8_t *Data, size_t DataSize) {
  return DataSize >= 3 &&
      Data[0] == 'F' &&
      Data[1] == 'U' &&
      Data[2] == 'Z' &&
      Data[3] == 'Z';  // :‑<
}

Fuzzer

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
  FuzzMe(Data, Size);
  return 0;
}

Compile

clang++ -g -fsanitize=address,undefined,fuzzer -fprofile-instr-generate -fcoverage-mapping -O1 -o fuzzer fuzzer.cc

Explanation:

Run

export 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:

-artifact_prefix can be omitted if you want the sanitizer logs combined with the fuzz target's logs.

Code coverage

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:

llvm-cov show fuzzer1 src/ -object=fuzzer2 -instr-profile=fuzzer.profdata
llvm-cov show  fuzzer1 src/foo.cc -object=fuzzer2 -instr-profile=fuzzer.profdata
llvm-cov show -ignore-filename-regex=".*_test.cc" fuzzer1 src/ -object=fuzzer2 -instr-profile=fuzzer.profdata

Corpus

Terms used:

Create 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

Reproducers

Minimize a reproducer:

./fuzzer -minimize_crash=1 -runs=10000 out/artifacts/crash-0eb8e4ed029b774d80f2b66408203801cb982a60