c-kzg-4844/fuzz
Justin Traglia 7d170f9939
Add coverage-guided C fuzzers (#203)
* Start to add fuzzers

* Update path to trusted setup in gen_corpus

* Update path one more time

* Add support for two more targets

* Add fuzzers for remaining targets

* Clean up a little

* Add README

* Fix typos

* De-dup fuzzing files

* Add newline at the end of base_fuzz

* Make generic rule for displaying targets

* Use regular make command

* Remove duplicate targets

* Update .gitignore file
2023-03-13 12:45:02 +02:00
..
blob_to_kzg_commitment Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00
compute_blob_kzg_proof Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00
compute_kzg_proof Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00
gen_corpus Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00
verify_blob_kzg_proof Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00
verify_blob_kzg_proof_batch Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00
verify_kzg_proof Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00
.gitignore Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00
Makefile Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00
README.md Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00
base_fuzz.h Add coverage-guided C fuzzers (#203) 2023-03-13 12:45:02 +02:00

README.md

Fuzzing

This directory contains coverage-guided fuzzers for KZG functions. It uses LLVM's libFuzzer for the heavy lifting. Each directory is named after a target and contains a single file (fuzz.c) that implements a LLVMFuzzerTestOneInput function. These are relatively simple; if the input matches the size requirements, it passes the data to the target function. There is a Makefile that compiles and starts the fuzzer, which means it should be pretty easy.

Dependencies

This is expected to run on Linux/macOS, it is not expected to work on Windows. In additional to build-essentials and clang, this requires llvm be installed:

Linux

sudo apt install llvm

macOS

brew install llvm

Targets

Currently, only the public KZG interface functions are fuzzable:

$ make
Available targets:
 - fuzz_blob_to_kzg_commitment
 - fuzz_compute_blob_kzg_proof
 - fuzz_compute_kzg_proof
 - fuzz_verify_blob_kzg_proof
 - fuzz_verify_blob_kzg_proof_batch
 - fuzz_verify_kzg_proof

To run a fuzzer, run make fuzz_<func> like:

$ make fuzz_verify_kzg_proof
[+] Building blst
+ cc -O2 -fno-builtin -fPIC -Wall -Wextra -Werror -c ./src/server.c
+ cc -O2 -fno-builtin -fPIC -Wall -Wextra -Werror -c ./build/assembly.S
+ ar rc libblst.a assembly.o server.o
[+] Generating corpus
[+] Compiling verify_kzg_proof fuzzer
[+] Starting verify_kzg_proof fuzzer
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 855755358
INFO: Loaded 1 modules   (228 inline 8-bit counters): 228 [0x1025a00f8, 0x1025a01dc), 
INFO: Loaded 1 PC tables (228 PCs): 228 [0x1025a01e0,0x1025a1020), 
INFO:        1 files found in ./verify_kzg_proof/corpus
INFO: seed corpus: files: 1 min: 160b max: 160b total: 160b rss: 28Mb
#2      pulse  ft: 17 exec/s: 1 rss: 29Mb
#2      INITED cov: 17 ft: 17 corp: 1/160b exec/s: 1 rss: 29Mb
#4      pulse  cov: 17 ft: 17 corp: 1/160b lim: 160 exec/s: 2 rss: 29Mb
#5      NEW    cov: 19 ft: 20 corp: 2/320b lim: 160 exec/s: 2 rss: 29Mb L: 160/160 MS: 3 ChangeASCIIInt-ChangeBit-ChangeBit-
#7      NEW    cov: 20 ft: 21 corp: 3/477b lim: 160 exec/s: 3 rss: 29Mb L: 157/160 MS: 2 ChangeByte-EraseBytes-
#8      pulse  cov: 20 ft: 21 corp: 3/477b lim: 160 exec/s: 4 rss: 29Mb
#13     NEW    cov: 21 ft: 23 corp: 4/637b lim: 160 exec/s: 6 rss: 29Mb L: 160/160 MS: 1 ChangeBit-
#16     pulse  cov: 21 ft: 23 corp: 4/637b lim: 160 exec/s: 8 rss: 29Mb
...

There are a few steps:

  • Build the blst library.
  • Generate initial corpora files.
  • Compile the fuzzer.
  • Start the fuzzer.

Reference this page for a guide on reading the output.

To stop the fuzzer, press ctrl-C on your keyboard. It will print something like:

...
#65536  pulse  cov: 25 ft: 29 corp: 7/961b lim: 160 exec/s: 16384 rss: 29Mb
#131072 pulse  cov: 25 ft: 29 corp: 7/961b lim: 160 exec/s: 18724 rss: 29Mb
^C==11616== libFuzzer: run interrupted; exiting
make: [run_fuzz_verify_kzg_proof] Error 72 (ignored)

If your system has multiple cores, it's easy to run fuzzers on multiple threads. Append THREADS=<n> where n is the number of threads you would like there to be. If you wish to use all available CPU cores, specify -1 as the count.

$ make fuzz_verify_kzg_proof THREADS=4
[+] Starting verify_kzg_proof fuzzer
./verify_kzg_proof/fuzz -artifact_prefix=./verify_kzg_proof/ -max_len=160 ./verify_kzg_proof/corpus >fuzz-0.log 2>&1
./verify_kzg_proof/fuzz -artifact_prefix=./verify_kzg_proof/ -max_len=160 ./verify_kzg_proof/corpus >fuzz-2.log 2>&1
./verify_kzg_proof/fuzz -artifact_prefix=./verify_kzg_proof/ -max_len=160 ./verify_kzg_proof/corpus >fuzz-1.log 2>&1
./verify_kzg_proof/fuzz -artifact_prefix=./verify_kzg_proof/ -max_len=160 ./verify_kzg_proof/corpus >fuzz-3.log 2>&1

When you press ctrl-C it will stop all the fuzzers and print their output to your console sequentially. You will most likely need to scroll up to see their outputs.

When operating in parallel (threads) the fuzzers use a shared corpus and are intelligent enough to learn from other threads that have progressed further. When you see a line that starts with "RELOAD" that fuzzer process is updating its corpus with findings from other threads.

Findings

If there is a crash or timeout, the fuzzer will write a file to the target directory containing the input data associated with that crash/timeout. If this happens, please report the finding via an issue on GitHub.