Fuzzing on transaction parser
Fuzzing allows us to test how a program behaves when provided with invalid, unexpected, or random data as input.
In the case of app-plugin-boilerplate
we want to test the code that is responsible for handling the contract data.
The fuzzer needs to implement int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
, which provides an array of random bytes that can be used to simulate a serialized transaction.
If the application crashes, or a sanitizer detects any kind of access violation, the fuzzing process is stopped, a report regarding the vulnerability is shown, and the input that triggered the bug is written to disk under the name crash-*
. The vulnerable input file created can be passed as an argument to the fuzzer to triage the issue.
Note: Usually we want to write a separate fuzz target for each functionality.
Manual usage based on Ledger container
Preparation
Before being able to use the fuzzing tests, the environment must be prepared with all submodules. To install them, use the following command in the repository root directory:
The fuzzer can run from the docker ledger-app-builder-legacy
. You can download it from the ghcr.io
docker repository:
You can then enter this development environment by executing the following command from the repository root directory:
sudo docker run --rm -ti --user "$(id -u):$(id -g)" -v "$(realpath .):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest
Compilation
Once in the container, go into the fuzzing
folder to compile the fuzzer:
cd fuzzing
# cmake initialization
cmake -DBOLOS_SDK=/opt/nanox-secure-sdk -DCMAKE_C_COMPILER=/usr/bin/clang -Bbuild -H.
# Fuzzer compilation
make -C build
Run
Full usage based on clusterfuzzlite
container
Exactly the same context as the CI, directly using the clusterfuzzlite
environment.
More info can be found here: https://google.github.io/clusterfuzzlite/
Preparation
The principle is to build the container, and run it to perform the fuzzing.
Note: The container contains a copy of the sources (they are not cloned), which means the
docker build
command must be re-executed after each code modification.
# Prepare directory tree
mkdir fuzzing/{corpus,out}
# Container generation
docker build -t app-plugin-boilerplate --file .clusterfuzzlite/Dockerfile .
Compilation
docker run --rm --privileged -e FUZZING_LANGUAGE=c -v "$(realpath .)/fuzzing/out:/out" -ti app-plugin-boilerplate