Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

67 Commits

Folders and files

Repository files navigation

stratamoto

A fuzzer for Stratum V2 roles, built along the lines of fuzzamoto.

How far each protocol message is taken is tracked in FEATURES.md. How the whole thing works, from a program to a filed finding, is in docs/HowStratamotoWorks.md.

Test cases are not byte strings. They are programs in a typed intermediate representation, where the types record how one message depends on another: a SetupConnection finalized for one subprotocol cannot be sent as another, and what needs a session can only run inside the block that runs once the server agreed to the setup. A mutator can rewrite anything it likes and still not fabricate a relationship the protocol does not allow, which is what separates this from feeding random bytes at a decoder.

The scope today is the SetupConnection message flow: every component handles that one flow completely before the next message is added.

Programs run against the real roles from sv2-apps over real sockets. A deterministic runtime for simulated roles is being sketched in stratamoto-dst, and is not wired in yet.

Layout

crate what it is
stratamoto-dst a seeded executor, clock, network and filesystem, in progress and not yet used
stratamoto-ir the programs: typed variables, operations, builder, compiler, generators, mutators, minimizers
stratamoto the harness: the transport, the runner and the oracles
stratamoto-targets the real roles: sv2-apps' pool, against Bitcoin Core
stratamoto-scenarios one binary per scenario
stratamoto-nyx-sys the Nyx agent a scenario talks to the snapshotting VM through, vendored from fuzzamoto
stratamoto-libafl the fuzzer: LibAFL clients driving Nyx VMs, mutating programs
stratamoto-cli generating, printing and compiling programs by hand, and building a Nyx share directory

A run goes: a generator builds a program through the builder, which rejects anything ill-typed; the compiler lowers it to actions; the runner carries those out against a deployment; the oracles judge what came back.

A campaign goes the way fuzzamoto's does: a scenario binary boots inside a Nyx VM, brings the roles up and takes a snapshot; the fuzzer mutates programs and runs each from that snapshot, with coverage from the pool's AFL instrumentation; findings are filed by the oracle that made them.

Getting started

cargo build
cargo test

The programs and the harness need nothing but a Rust toolchain (built with 1.98, edition 2024). Anything touching a real role additionally needs Bitcoin Core; see running against real roles.

Run one scenario

cargo build
target/debug/stratamoto generate 7 1 | target/debug/stratamoto print          # read it
target/debug/stratamoto generate 7 1 | target/debug/pool_setup_connection

A scenario binary takes a serialized program on stdin and exits non-zero when an oracle finds a violation.

Fuzz

Fuzzing needs bare metal Linux on x86_64 with KVM, and the VMware backdoor enabled in KVM:

sudo modprobe -r kvm-intel kvm       # or kvm-amd
sudo modprobe kvm enable_vmware_backdoor=y && sudo modprobe kvm-intel

Then, with a pool binary instrumented by cargo-afl (an uninstrumented one runs too, with no coverage to guide the fuzzer):

export STRATAMOTO_POOL=/path/to/instrumented/pool_sv2
cargo build --release -p stratamoto-scenarios --features nyx   # the scenario, for the VM
cargo build --release -p stratamoto-libafl                     # the fuzzer, builds QEMU-Nyx
cargo build --release -p stratamoto-cli
target/release/stratamoto init --sharedir /tmp/share \
    --scenario target/release/pool_setup_connection --pool $STRATAMOTO_POOL \
    --template-provider /path/to/sv2-apps/integration-tests/template-provider \
    --nyx-dir target/release
mkdir -p /tmp/in
target/release/stratamoto-libafl --input /tmp/in --output /tmp/out --share /tmp/share --cores 0-7

STRATAMOTO_POOL is read when the Nyx agent is built, so that the shared coverage map is the size the pool's instrumentation expects. Findings land under /tmp/out/cpu_*/crashes, filed by cause, as bare programs a scenario binary replays. See stratamoto-libafl.

Fuzz from a container

Dockerfile.libafl carries all of the above but the checkout: the toolchain, cargo-afl, what QEMU-Nyx needs to build, the pool built with AFL instrumentation, and Bitcoin Core where the launcher looks for it. The host still has to be bare metal with KVM and the VMware backdoor enabled, as above.

docker build -f Dockerfile.libafl -t stratamoto-libafl .
docker run --privileged --shm-size=4g -it -v $PWD:/stratamoto stratamoto-libafl bash

--privileged is what lets Nyx use KVM, and the fuzzer's clients talk over shared memory, so /dev/shm wants to be larger than Docker's default. Inside the container:

just -f /ci/libafl.justfile run            # build, create the share directory, fuzz on core 0
just -f /ci/libafl.justfile cores=0-7 run

The recipes are the commands above and can be run by hand instead. The container builds into target/docker, apart from anything the host built, and QEMU-Nyx is built there once, on the first build.

The pool comes from sv2-apps at the revision this workspace pins. Another one is a build argument away:

docker build --build-arg PR_NUMBER=1234 -f Dockerfile.libafl -t stratamoto-libafl .
docker build --build-arg SV2_APPS_COMMIT=abc123 -f Dockerfile.libafl -t stratamoto-libafl .
docker build --build-arg OWNER=someone --build-arg SV2_APPS_COMMIT=abc123 -f Dockerfile.libafl -t stratamoto-libafl .

Running against real roles

stratamoto-targets starts sv2-apps' pool binary as its own process and feeds it from a real Bitcoin Core node, started with sv2-apps' own launcher. The pool carries bitcoin-core-sv2 and talks to the node over its IPC socket, with nothing in between. Templates therefore come from a node, not from us, and the pool is the real thing when it is asked to set a connection up.

The pool binary is built from sv2-apps at the revision this workspace pins, and named by STRATAMOTO_POOL:

cargo install --git https://github.com/stratum-mining/sv2-apps.git \
    --rev ab8f30f1784ea20c2de1b2726c47e7eea10f4556 pool_sv2 --root ./sv2
export STRATAMOTO_POOL=$PWD/sv2/bin/pool_sv2

That launcher looks for Bitcoin Core in a template-provider directory beside the working directory and downloads it when it is missing. If you already have a copy, point at it and nothing is downloaded:

export STRATAMOTO_TEMPLATE_PROVIDER_CACHE=/path/to/sv2-apps/integration-tests/template-provider

Without it, a checkout of sv2-apps beside this one is found automatically.

The node runs in regtest.

A known upstream finding

The suite has one ignored test, a_second_frame_in_the_teardown_window_can_livelock_the_pool.

On a rejected SetupConnection the pool answers and then sleeps one second before closing the connection, deliberately, so the error reaches the client. A second frame arriving in that window races the teardown, and on an unlucky interleaving a pool worker spins at close to a full core: measured, the busiest thread burns 198 of 200 jiffies over two seconds that should be idle, while an idle pool sits at zero. The pegged worker starves the runtime and fresh connections fail their handshake.

It is a livelock rather than a crash, and a race that fires about half the time, so the test repeats the trigger. It is ignored because it asserts a bug is present: when sv2-apps fixes it, the test fails, and that is the signal to update the record.

Environment

variable what it does
STRATAMOTO_INPUT read a scenario's program from a file instead of stdin
STRATAMOTO_POOL the pool binary the pool target runs
STRATAMOTO_POOL_LOG write the pool's log to this file, and keep it after the run
STRATAMOTO_DUMP_IR_CONTEXT where a locally run scenario writes the program context it dumps for the fuzzer
STRATAMOTO_TEMPLATE_PROVIDER_CACHE where Bitcoin Core already lives
RUST_LOG filters logging from the harness and the real roles alike, through tracing

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages