Merge rust-bitcoin/rust-bitcoin#1732: Overhaul fuzzing
2860aae1a5
fuzz: don't fuzz hashes against RustCrypto (Andrew Poelstra)6467728202
fuzz: disable tests unless 'cfg(fuzzing)' is passed; update README for reproducing failures (Andrew Poelstra)6e2ee5be66
fuzz: run 'cargo fmt' on all the fuzz targets (Andrew Poelstra)9cfc0fcd81
fuzz: add contrib/test.sh so we at least 'cargo test' it in CI (Andrew Poelstra)933ecb19e1
fuzz: fix warnings, clippy lints, 1.48.0 failures (Andrew Poelstra)fd88e48696
fuzz: remove AFL support (Andrew Poelstra)ab467cb091
fuzz: make hongfuzz fuzzing the default feature (Andrew Poelstra)6f754df231
fuzz: add fuzzing README (Andrew Poelstra)f093765efe
fix fuzz.sh and cycle.sh to use generated lists of targets (Andrew Poelstra)6534f22362
fuzz: auto-generate CI and Cargo.toml files (Andrew Poelstra)8021034d86
rename travis-fuzz.sh to fuzz.sh; partially patch CI (Andrew Poelstra)0be75f7edc
move hashes/fuzz into main fuzz/ directory (Andrew Poelstra)5a891dec2d
move bitcoin fuzz targets into bitcoin/ subdirectory (Andrew Poelstra)e3111c748b
move bitcoin/fuzz into repo root; add to workspace (Andrew Poelstra) Pull request description: Several big changes here: * Moves fuzzing to its own workspace with a `contrib/test.sh` etc so that CI will check that it compiles * FIx all warnings, clippy lints, MSRV problems, etc.; mostly move to Rust 2018 * Merge `hashes/` fuzztests into workspace * Rewrite all scripts; add file that auto-generates CI fuzz job and Cargo.toml so we don't have to manually keep these in sync * Remove bitrotted and partial AFL support. Supercedes #1422 I suspect the hashes fuzztests will actually fail since we haven't touched them in so long. Will address that if CI fails here. ACKs for top commit: sanket1729: ACK2860aae1a5
tcharding: ACK2860aae1a5
Tree-SHA512: b1aa3d6fac75fee51966f1d3f3245784e331bdea2a3fa7d6609bc4196c34f81acb7701faf8f269c3741568ea100438f24a2f06e75c8d01cb84c8b22d7886f1dd
This commit is contained in:
commit
c9347cd021
|
@ -1,3 +1,4 @@
|
|||
# Automatically generated by fuzz/generate-files.sh
|
||||
name: Fuzz
|
||||
|
||||
on:
|
||||
|
@ -8,14 +9,32 @@ on:
|
|||
pull_request:
|
||||
|
||||
jobs:
|
||||
|
||||
fuzz:
|
||||
if: ${{ !github.event.act }}
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
fuzz_target: [deser_net_msg, deserialize_address, deserialize_amount, deserialize_block, deserialize_psbt, deserialize_script, deserialize_transaction, deserialize_prefilled_transaction, deserialize_witness, outpoint_string, script_bytes_to_asm_fmt]
|
||||
fuzz_target: [
|
||||
bitcoin_outpoint_string,
|
||||
bitcoin_deserialize_amount,
|
||||
bitcoin_deserialize_transaction,
|
||||
bitcoin_deser_net_msg,
|
||||
bitcoin_deserialize_address,
|
||||
bitcoin_script_bytes_to_asm_fmt,
|
||||
bitcoin_deserialize_prefilled_transaction,
|
||||
bitcoin_deserialize_witness,
|
||||
bitcoin_deserialize_psbt,
|
||||
bitcoin_deserialize_block,
|
||||
bitcoin_deserialize_script,
|
||||
hashes_json,
|
||||
hashes_cbor,
|
||||
hashes_sha256,
|
||||
hashes_ripemd160,
|
||||
hashes_sha512_256,
|
||||
hashes_sha512,
|
||||
hashes_sha1,
|
||||
]
|
||||
steps:
|
||||
- name: Install test dependencies
|
||||
run: sudo apt-get update -y && sudo apt-get install -y binutils-dev libunwind8-dev libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc libiberty-dev
|
||||
|
@ -34,8 +53,8 @@ jobs:
|
|||
override: true
|
||||
profile: minimal
|
||||
- name: fuzz
|
||||
run: cd bitcoin/fuzz && ./travis-fuzz.sh "${{ matrix.fuzz_target }}"
|
||||
- run: echo "${{ matrix.fuzz_target }}.rs" >executed_${{ matrix.fuzz_target }}
|
||||
run: cd fuzz && ./fuzz.sh "${{ matrix.fuzz_target }}"
|
||||
- run: echo "${{ matrix.fuzz_target }}" >executed_${{ matrix.fuzz_target }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: executed_${{ matrix.fuzz_target }}
|
||||
|
@ -51,5 +70,4 @@ jobs:
|
|||
- name: Display structure of downloaded files
|
||||
run: ls -R
|
||||
- run: find executed_* -type f -exec cat {} + | sort > executed
|
||||
- run: ls bitcoin/fuzz/fuzz_targets | sort > expected
|
||||
- run: diff expected executed
|
||||
- run: source ./fuzz/fuzz-util.sh && listTargetNames | sort | diff - executed
|
||||
|
|
|
@ -16,7 +16,5 @@ hashes/target
|
|||
bitcoin/dep_test
|
||||
|
||||
# Fuzz artifacts
|
||||
bitcoin/fuzz/hfuzz_target
|
||||
bitcoin/fuzz/hfuzz_workspace
|
||||
hashes/fuzz/hfuzz_target
|
||||
hashes/fuzz/hfuzz_workspace
|
||||
hfuzz_target
|
||||
hfuzz_workspace
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
[workspace]
|
||||
members = ["bitcoin", "hashes", "internals"]
|
||||
members = ["bitcoin", "hashes", "internals", "fuzz"]
|
||||
|
||||
[patch.crates-io.bitcoin]
|
||||
path = "bitcoin"
|
||||
|
||||
[patch.crates-io.bitcoin_hashes]
|
||||
path = "hashes"
|
||||
|
|
|
@ -82,6 +82,7 @@ To build with the MSRV you will need to pin `serde` (if you have the feature ena
|
|||
```
|
||||
# serde 1.0.157 uses syn 2.0 which requires edition 2021
|
||||
cargo update -p serde --precise 1.0.156
|
||||
cargo update -p half --precise 1.7.1
|
||||
```
|
||||
|
||||
before building. (And if your code is a library, your downstream users will need to run these
|
||||
|
|
|
@ -108,16 +108,6 @@ if [ "$DO_DOCS" = true ]; then
|
|||
RUSTDOCFLAGS="-D warnings" cargo +stable doc --all-features
|
||||
fi
|
||||
|
||||
# Fuzz if told to
|
||||
if [ "$DO_FUZZ" = true ]
|
||||
then
|
||||
(
|
||||
cd fuzz
|
||||
cargo test --verbose
|
||||
./travis-fuzz.sh
|
||||
)
|
||||
fi
|
||||
|
||||
# Run formatter if told to.
|
||||
if [ "$DO_FMT" = true ]; then
|
||||
if [ "$NIGHTLY" = false ]; then
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
[package]
|
||||
name = "bitcoin-fuzz"
|
||||
version = "0.0.1"
|
||||
authors = ["Automatically generated"]
|
||||
publish = false
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[features]
|
||||
afl_fuzz = ["afl"]
|
||||
honggfuzz_fuzz = ["honggfuzz"]
|
||||
|
||||
[dependencies]
|
||||
honggfuzz = { version = "0.5", optional = true, default-features = false }
|
||||
afl = { version = "0.4", optional = true }
|
||||
bitcoin = { path = "../" }
|
||||
|
||||
# Prevent this from interfering with workspaces
|
||||
[workspace]
|
||||
members = ["."]
|
||||
|
||||
[[bin]]
|
||||
name = "deserialize_block"
|
||||
path = "fuzz_targets/deserialize_block.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "deserialize_script"
|
||||
path = "fuzz_targets/deserialize_script.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "deserialize_transaction"
|
||||
path = "fuzz_targets/deserialize_transaction.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "deserialize_prefilled_transaction"
|
||||
path = "fuzz_targets/deserialize_prefilled_transaction.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "deserialize_address"
|
||||
path = "fuzz_targets/deserialize_address.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "deserialize_amount"
|
||||
path = "fuzz_targets/deserialize_amount.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "outpoint_string"
|
||||
path = "fuzz_targets/outpoint_string.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "deserialize_psbt"
|
||||
path = "fuzz_targets/deserialize_psbt.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "deser_net_msg"
|
||||
path = "fuzz_targets/deser_net_msg.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "script_bytes_to_asm_fmt"
|
||||
path = "fuzz_targets/script_bytes_to_asm_fmt.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "deserialize_witness"
|
||||
path = "fuzz_targets/deserialize_witness.rs"
|
||||
|
||||
[patch.crates-io.bitcoin_hashes]
|
||||
path = "../../hashes"
|
|
@ -1,23 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Continuosly cycle over fuzz targets running each for 1 hour.
|
||||
# It uses chrt SCHED_IDLE so that other process takes priority.
|
||||
#
|
||||
# For hfuzz options see https://github.com/google/honggfuzz/blob/master/docs/USAGE.md
|
||||
|
||||
export HFUZZ_BUILD_ARGS='--features honggfuzz_fuzz'
|
||||
|
||||
while :
|
||||
do
|
||||
for FILE in fuzz_targets/*;
|
||||
do
|
||||
TARGET=$(echo $FILE | cut -c 14- | cut -f 1 -d '.')
|
||||
|
||||
# fuzz for one hour
|
||||
HFUZZ_RUN_ARGS='--run_time 3600' chrt -i 0 cargo hfuzz run $TARGET
|
||||
|
||||
# minimize the corpus
|
||||
HFUZZ_RUN_ARGS="-i hfuzz_workspace/$TARGET/input/ -P -M" chrt -i 0 cargo hfuzz run $TARGET
|
||||
done
|
||||
done
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
extern crate bitcoin;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
// faster than String, we don't need to actually produce the value, just check absence of panics
|
||||
struct NullWriter;
|
||||
|
||||
impl fmt::Write for NullWriter {
|
||||
fn write_str(&mut self, _s: &str) -> fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_char(&mut self, _c: char) -> fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let mut writer = NullWriter;
|
||||
bitcoin::Script::from_bytes(data).fmt_asm(&mut writer);
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
do_test(data);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Check that input files are correct Windows file names
|
||||
incorrectFilenames=$(find . -type f -name "*,*" -o -name "*:*" -o -name "*<*" -o -name "*>*" -o -name "*|*" -o -name "*\?*" -o -name "*\**" -o -name "*\"*" | wc -l)
|
||||
|
||||
if [ ${incorrectFilenames} -gt 0 ]; then
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$1" == "" ]; then
|
||||
TARGETS=fuzz_targets/*
|
||||
else
|
||||
TARGETS=fuzz_targets/"$1".rs
|
||||
fi
|
||||
|
||||
cargo --version
|
||||
rustc --version
|
||||
|
||||
# Testing
|
||||
cargo install --force honggfuzz --no-default-features
|
||||
for TARGET in $TARGETS; do
|
||||
echo "Fuzzing target $TARGET"
|
||||
FILENAME=$(basename $TARGET)
|
||||
FILE="${FILENAME%.*}"
|
||||
if [ -d hfuzz_input/$FILE ]; then
|
||||
HFUZZ_INPUT_ARGS="-f hfuzz_input/$FILE/input"
|
||||
fi
|
||||
HFUZZ_BUILD_ARGS="--features honggfuzz_fuzz" HFUZZ_RUN_ARGS="--run_time 30 --exit_upon_crash -v $HFUZZ_INPUT_ARGS" cargo hfuzz run $FILE
|
||||
|
||||
if [ -f hfuzz_workspace/$FILE/HONGGFUZZ.REPORT.TXT ]; then
|
||||
cat hfuzz_workspace/$FILE/HONGGFUZZ.REPORT.TXT
|
||||
for CASE in hfuzz_workspace/$FILE/SIG*; do
|
||||
cat $CASE | xxd -p
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
done
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
set -ex
|
||||
|
||||
CRATES="bitcoin hashes internals"
|
||||
CRATES="bitcoin hashes internals fuzz"
|
||||
|
||||
for crate in ${CRATES}
|
||||
do
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
[package]
|
||||
name = "bitcoin-fuzz"
|
||||
edition = "2018"
|
||||
version = "0.0.1"
|
||||
authors = ["Generated by fuzz/generate-files.sh"]
|
||||
publish = false
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
honggfuzz = { version = "0.5", default-features = false }
|
||||
bitcoin = { version = "0.30.0", features = [ "serde" ] }
|
||||
|
||||
serde = { version = "1.0.103", features = [ "derive" ] }
|
||||
serde_json = "1.0"
|
||||
serde_cbor = "0.9"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_outpoint_string"
|
||||
path = "fuzz_targets/bitcoin/outpoint_string.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_deserialize_amount"
|
||||
path = "fuzz_targets/bitcoin/deserialize_amount.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_deserialize_transaction"
|
||||
path = "fuzz_targets/bitcoin/deserialize_transaction.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_deser_net_msg"
|
||||
path = "fuzz_targets/bitcoin/deser_net_msg.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_deserialize_address"
|
||||
path = "fuzz_targets/bitcoin/deserialize_address.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_script_bytes_to_asm_fmt"
|
||||
path = "fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_deserialize_prefilled_transaction"
|
||||
path = "fuzz_targets/bitcoin/deserialize_prefilled_transaction.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_deserialize_witness"
|
||||
path = "fuzz_targets/bitcoin/deserialize_witness.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_deserialize_psbt"
|
||||
path = "fuzz_targets/bitcoin/deserialize_psbt.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_deserialize_block"
|
||||
path = "fuzz_targets/bitcoin/deserialize_block.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "bitcoin_deserialize_script"
|
||||
path = "fuzz_targets/bitcoin/deserialize_script.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "hashes_json"
|
||||
path = "fuzz_targets/hashes/json.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "hashes_cbor"
|
||||
path = "fuzz_targets/hashes/cbor.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "hashes_sha256"
|
||||
path = "fuzz_targets/hashes/sha256.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "hashes_ripemd160"
|
||||
path = "fuzz_targets/hashes/ripemd160.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "hashes_sha512_256"
|
||||
path = "fuzz_targets/hashes/sha512_256.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "hashes_sha512"
|
||||
path = "fuzz_targets/hashes/sha512.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "hashes_sha1"
|
||||
path = "fuzz_targets/hashes/sha1.rs"
|
|
@ -0,0 +1,93 @@
|
|||
# Fuzzing
|
||||
|
||||
`bitcoin` and `bitcoin_hashes` have fuzzing harnesses setup for use with
|
||||
honggfuzz.
|
||||
|
||||
To run the fuzz-tests as in CI -- briefly fuzzing every target -- simply
|
||||
run
|
||||
|
||||
./fuzz.sh
|
||||
|
||||
in this directory.
|
||||
|
||||
To build honggfuzz, you must have libunwind on your system, as well as
|
||||
libopcodes and libbfd from binutils **2.38** on your system. The most
|
||||
recently-released binutils 2.39 has changed their API in a breaking way.
|
||||
|
||||
On Nix, you can obtain these libraries by running
|
||||
|
||||
nix-shell -p libopcodes_2_38 -p libunwind
|
||||
|
||||
and then run fuzz.sh as above.
|
||||
|
||||
# Long-term fuzzing
|
||||
|
||||
To see the full list of targets, the most straightforward way is to run
|
||||
|
||||
source ./fuzz-util.sh
|
||||
listTargetNames
|
||||
|
||||
To run each of them for an hour, run
|
||||
|
||||
./cycle.sh
|
||||
|
||||
To run a single fuzztest indefinitely, run
|
||||
|
||||
HFUZZ_BUILD_ARGS='--features honggfuzz_fuzz' cargo hfuzz run <target>
|
||||
|
||||
This script uses the `chrt` utility to try to reduce the priority of the
|
||||
jobs. If you would like to run for longer, the most straightforward way
|
||||
is to edit `cycle.sh` before starting. To run the fuzz-tests in parallel,
|
||||
you will need to implement a custom harness.
|
||||
|
||||
# Adding fuzz tests
|
||||
|
||||
All fuzz tests can be found in the `fuzz_target/` directory. Adding a new
|
||||
one is as simple as copying an existing one and editing the `do_test`
|
||||
function to do what you want.
|
||||
|
||||
If your test clearly belongs to a specific crate, please put it in that
|
||||
crate's directory. Otherwise you can put it directly in `fuzz_target/`.
|
||||
|
||||
If you need to add dependencies, edit the file `generate-files.sh` to add
|
||||
it to the generated `Cargo.toml`.
|
||||
|
||||
Once you've added a fuzztest, regenerate the `Cargo.toml` and CI job by
|
||||
running
|
||||
|
||||
./generate-files.sh
|
||||
|
||||
Then to test your fuzztest, run
|
||||
|
||||
./fuzz.sh <target>
|
||||
|
||||
If it is working, you will see a rapid stream of data for many seconds
|
||||
(you can hit Ctrl+C to stop it early). If not, you should quickly see
|
||||
an error.
|
||||
|
||||
# Reproducing Failures
|
||||
|
||||
If a fuzztest fails, it will exit with a summary which looks something like
|
||||
|
||||
```
|
||||
...
|
||||
fuzzTarget : hfuzz_target/x86_64-unknown-linux-gnu/release/hashes_sha256
|
||||
CRASH:
|
||||
DESCRIPTION:
|
||||
ORIG_FNAME: 00000000000000000000000000000000.00000000.honggfuzz.cov
|
||||
FUZZ_FNAME: hfuzz_workspace/hashes_sha256/SIGABRT.PC.7ffff7c8abc7.STACK.18826d9b64.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz
|
||||
...
|
||||
=====================================================================
|
||||
fff400610004
|
||||
```
|
||||
|
||||
The final line is a hex-encoded version of the input that caused the crash. You
|
||||
can test this directly by editing the `duplicate_crash` test to copy/paste the
|
||||
hex output into the call to `extend_vec_from_hex`. Then run the test with
|
||||
|
||||
RUSTFLAGS=--cfg=fuzzing cargo test
|
||||
|
||||
It is important to add the `cfg=fuzzing` flag, which tells rustc to compile the
|
||||
library as though it were running a fuzztest. In particular, this will disable
|
||||
or weaken all the cryptography.
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
FEATURES=""
|
||||
|
||||
cargo --version
|
||||
rustc --version
|
||||
|
||||
# Make all cargo invocations verbose
|
||||
export CARGO_TERM_VERBOSE=true
|
||||
|
||||
# Pin dependencies as required if we are using MSRV toolchain.
|
||||
if cargo --version | grep "1\.41"; then
|
||||
# 1.0.157 uses syn 2.0 which requires edition 2021
|
||||
cargo update -p serde --precise 1.0.156
|
||||
# 1.0.108 uses `matches!` macro so does not work with Rust 1.41.1, bad `syn` no biscuit.
|
||||
cargo update -p syn --precise 1.0.107
|
||||
# Half 1.8 uses edition 2021 features
|
||||
cargo update -p half --precise 1.7.1
|
||||
fi
|
||||
|
||||
if [ "$DO_LINT" = true ]
|
||||
then
|
||||
cargo clippy --all-features --all-targets -- -D warnings
|
||||
fi
|
||||
|
||||
# Defaults / sanity checks
|
||||
cargo build
|
||||
cargo test
|
||||
|
||||
# Address Sanitizer
|
||||
if [ "$DO_ASAN" = true ]; then
|
||||
cargo clean
|
||||
CC='clang -fsanitize=address -fno-omit-frame-pointer' \
|
||||
RUSTFLAGS='-Zsanitizer=address -Clinker=clang -Cforce-frame-pointers=yes' \
|
||||
ASAN_OPTIONS='detect_leaks=1 detect_invalid_pointer_pairs=1 detect_stack_use_after_return=1' \
|
||||
cargo test --lib --no-default-features --features="$FEATURES" -Zbuild-std --target x86_64-unknown-linux-gnu
|
||||
cargo clean
|
||||
CC='clang -fsanitize=memory -fno-omit-frame-pointer' \
|
||||
RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins -Cforce-frame-pointers=yes' \
|
||||
cargo test --lib --no-default-features --features="$FEATURES" -Zbuild-std --target x86_64-unknown-linux-gnu
|
||||
fi
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Continuosly cycle over fuzz targets running each for 1 hour.
|
||||
# It uses chrt SCHED_IDLE so that other process takes priority.
|
||||
#
|
||||
# For hfuzz options see https://github.com/google/honggfuzz/blob/master/docs/USAGE.md
|
||||
|
||||
set -e
|
||||
REPO_DIR=$(git rev-parse --show-toplevel)
|
||||
# shellcheck source=./fuzz-util.sh
|
||||
source "$REPO_DIR/fuzz/fuzz-util.sh"
|
||||
|
||||
while :
|
||||
do
|
||||
for targetFile in $(listTargetFiles); do
|
||||
targetName=$(targetFileToName "$targetFile")
|
||||
echo "Fuzzing target $targetName ($targetFile)"
|
||||
|
||||
# fuzz for one hour
|
||||
HFUZZ_RUN_ARGS='--run_time 3600' chrt -i 0 cargo hfuzz run "$targetName"
|
||||
# minimize the corpus
|
||||
HFUZZ_RUN_ARGS="-i hfuzz_workspace/$targetName/input/ -P -M" chrt -i 0 cargo hfuzz run "$targetName"
|
||||
done
|
||||
done
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
REPO_DIR=$(git rev-parse --show-toplevel)
|
||||
|
||||
listTargetFiles() {
|
||||
pushd "$REPO_DIR/fuzz" > /dev/null || exit 1
|
||||
find fuzz_targets/ -type f -name "*.rs"
|
||||
popd > /dev/null || exit 1
|
||||
}
|
||||
|
||||
targetFileToName() {
|
||||
echo "$1" \
|
||||
| sed 's/^fuzz_targets\///' \
|
||||
| sed 's/\.rs$//' \
|
||||
| sed 's/\//_/g'
|
||||
}
|
||||
|
||||
targetFileToHFuzzInputArg() {
|
||||
baseName=$(basename "$1")
|
||||
dirName="${baseName%.*}"
|
||||
if [ -d "hfuzz_input/$dirName" ]; then
|
||||
echo "HFUZZ_INPUT_ARGS=\"-f hfuzz_input/$FILE/input\""
|
||||
fi
|
||||
}
|
||||
|
||||
listTargetNames() {
|
||||
for target in $(listTargetFiles); do
|
||||
targetFileToName "$target"
|
||||
done
|
||||
}
|
||||
|
||||
# Utility function to avoid CI failures on Windows
|
||||
checkWindowsFiles() {
|
||||
incorrectFilenames=$(find . -type f -name "*,*" -o -name "*:*" -o -name "*<*" -o -name "*>*" -o -name "*|*" -o -name "*\?*" -o -name "*\**" -o -name "*\"*" | wc -l)
|
||||
if [ "$incorrectFilenames" -gt 0 ]; then
|
||||
echo "Bailing early because there is a Windows-incompatible filename in the tree."
|
||||
exit 2
|
||||
fi
|
||||
}
|
||||
|
||||
# Checks whether a fuzz case output some report, and dumps it in hex
|
||||
checkReport() {
|
||||
reportFile="hfuzz_workspace/$1/HONGGFUZZ.REPORT.TXT"
|
||||
if [ -f "$reportFile" ]; then
|
||||
cat "$reportFile"
|
||||
for CASE in "hfuzz_workspace/$1/SIG"*; do
|
||||
xxd -p -c10000 < "$CASE"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
REPO_DIR=$(git rev-parse --show-toplevel)
|
||||
|
||||
# shellcheck source=./fuzz-util.sh
|
||||
source "$REPO_DIR/fuzz/fuzz-util.sh"
|
||||
|
||||
# Check that input files are correct Windows file names
|
||||
checkWindowsFiles
|
||||
|
||||
if [ "$1" == "" ]; then
|
||||
targetFiles="$(listTargetFiles)"
|
||||
else
|
||||
targetFiles=fuzz_targets/"$1".rs
|
||||
fi
|
||||
|
||||
cargo --version
|
||||
rustc --version
|
||||
|
||||
# Testing
|
||||
cargo install --force honggfuzz --no-default-features
|
||||
for targetFile in $targetFiles; do
|
||||
targetName=$(targetFileToName "$targetFile")
|
||||
echo "Fuzzing target $targetName ($targetFile)"
|
||||
if [ -d "hfuzz_input/$targetName" ]; then
|
||||
HFUZZ_INPUT_ARGS="-f hfuzz_input/$targetName/input\""
|
||||
else
|
||||
HFUZZ_INPUT_ARGS=""
|
||||
fi
|
||||
HFUZZ_RUN_ARGS="--run_time 30 --exit_upon_crash -v $HFUZZ_INPUT_ARGS" cargo hfuzz run "$targetName"
|
||||
|
||||
checkReport "$targetName"
|
||||
done
|
|
@ -1,21 +1,10 @@
|
|||
extern crate bitcoin;
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let _: Result<bitcoin::network::message::RawNetworkMessage, _> = bitcoin::consensus::encode::deserialize(data);
|
||||
let _: Result<bitcoin::network::message::RawNetworkMessage, _> =
|
||||
bitcoin::consensus::encode::deserialize(data);
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
|
@ -24,7 +13,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
|
@ -1,5 +1,7 @@
|
|||
extern crate bitcoin;
|
||||
use std::str::FromStr;
|
||||
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let data_str = String::from_utf8_lossy(data);
|
||||
let addr = match bitcoin::address::Address::from_str(&data_str) {
|
||||
|
@ -9,18 +11,6 @@ fn do_test(data: &[u8]) {
|
|||
assert_eq!(addr.to_string(), data_str);
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
|
@ -29,7 +19,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
|
@ -1,5 +1,7 @@
|
|||
extern crate bitcoin;
|
||||
use std::str::FromStr;
|
||||
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let data_str = String::from_utf8_lossy(data);
|
||||
|
||||
|
@ -26,18 +28,6 @@ fn do_test(data: &[u8]) {
|
|||
assert_eq!(amt, amt_roundtrip);
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
|
@ -46,7 +36,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
|
@ -1,21 +1,10 @@
|
|||
extern crate bitcoin;
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let _: Result<bitcoin::blockdata::block::Block, _>= bitcoin::consensus::encode::deserialize(data);
|
||||
let _: Result<bitcoin::blockdata::block::Block, _> =
|
||||
bitcoin::consensus::encode::deserialize(data);
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
|
@ -24,7 +13,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
|
@ -1,30 +1,19 @@
|
|||
extern crate bitcoin;
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
// We already fuzz Transactions in `./deserialize_transaction.rs`.
|
||||
let tx_result: Result<bitcoin::bip152::PrefilledTransaction, _> = bitcoin::consensus::encode::deserialize(data);
|
||||
let tx_result: Result<bitcoin::bip152::PrefilledTransaction, _> =
|
||||
bitcoin::consensus::encode::deserialize(data);
|
||||
|
||||
match tx_result {
|
||||
Err(_) => {},
|
||||
Ok(mut tx) => {
|
||||
Err(_) => {}
|
||||
Ok(tx) => {
|
||||
let ser = bitcoin::consensus::encode::serialize(&tx);
|
||||
assert_eq!(&ser[..], data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
|
@ -33,7 +22,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
|
@ -1,9 +1,10 @@
|
|||
extern crate bitcoin;
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let psbt: Result<bitcoin::psbt::PartiallySignedTransaction, _> = bitcoin::psbt::Psbt::deserialize(data);
|
||||
let psbt: Result<bitcoin::psbt::PartiallySignedTransaction, _> =
|
||||
bitcoin::psbt::Psbt::deserialize(data);
|
||||
match psbt {
|
||||
Err(_) => {},
|
||||
Err(_) => {}
|
||||
Ok(psbt) => {
|
||||
let ser = bitcoin::psbt::Psbt::serialize(&psbt);
|
||||
let deser = bitcoin::psbt::Psbt::deserialize(&ser).unwrap();
|
||||
|
@ -13,18 +14,6 @@ fn do_test(data: &[u8]) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
|
@ -33,7 +22,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
|
@ -1,9 +1,8 @@
|
|||
extern crate bitcoin;
|
||||
|
||||
use bitcoin::address::Address;
|
||||
use bitcoin::network::constants::Network;
|
||||
use bitcoin::blockdata::script;
|
||||
use bitcoin::consensus::encode;
|
||||
use bitcoin::network::constants::Network;
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let s: Result<script::ScriptBuf, _> = encode::deserialize(data);
|
||||
|
@ -16,7 +15,9 @@ fn do_test(data: &[u8]) {
|
|||
return;
|
||||
}
|
||||
match ins.ok().unwrap() {
|
||||
script::Instruction::Op(op) => { b = b.push_opcode(op); }
|
||||
script::Instruction::Op(op) => {
|
||||
b = b.push_opcode(op);
|
||||
}
|
||||
script::Instruction::PushBytes(bytes) => {
|
||||
// Any one-byte pushes, except -0, which can be interpreted as numbers, should be
|
||||
// reserialized as numbers. (For -1 through 16, this will use special ops; for
|
||||
|
@ -43,18 +44,6 @@ fn do_test(data: &[u8]) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
|
@ -63,7 +52,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
|
@ -1,9 +1,10 @@
|
|||
extern crate bitcoin;
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let tx_result: Result<bitcoin::blockdata::transaction::Transaction, _> = bitcoin::consensus::encode::deserialize(data);
|
||||
let tx_result: Result<bitcoin::blockdata::transaction::Transaction, _> =
|
||||
bitcoin::consensus::encode::deserialize(data);
|
||||
match tx_result {
|
||||
Err(_) => {},
|
||||
Err(_) => {}
|
||||
Ok(mut tx) => {
|
||||
let ser = bitcoin::consensus::encode::serialize(&tx);
|
||||
assert_eq!(&ser[..], data);
|
||||
|
@ -21,22 +22,10 @@ fn do_test(data: &[u8]) {
|
|||
} else {
|
||||
assert_eq!(no_witness_len * 3 + len, calculated_weight);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
|
@ -45,7 +34,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
|
@ -1,28 +1,15 @@
|
|||
extern crate bitcoin;
|
||||
|
||||
use bitcoin::consensus::{serialize, deserialize};
|
||||
use bitcoin::blockdata::witness::Witness;
|
||||
use bitcoin::consensus::{deserialize, serialize};
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let w: Result<Witness, _> = deserialize(data);
|
||||
if let Ok(witness) = w {
|
||||
let serialized = serialize(&witness);
|
||||
assert_eq!(data, serialized);
|
||||
assert_eq!(data, &serialized[..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
|
@ -31,7 +18,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
|
@ -1,21 +1,22 @@
|
|||
|
||||
extern crate bitcoin;
|
||||
use std::str::FromStr;
|
||||
|
||||
use bitcoin::blockdata::transaction::OutPoint;
|
||||
use bitcoin::consensus::encode;
|
||||
|
||||
use std::str::FromStr;
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let lowercase: Vec<u8> = data.iter().map(|c| match *c {
|
||||
let lowercase: Vec<u8> = data
|
||||
.iter()
|
||||
.map(|c| match *c {
|
||||
b'A' => b'a',
|
||||
b'B' => b'b',
|
||||
b'C' => b'c',
|
||||
b'D' => b'd',
|
||||
b'E' => b'e',
|
||||
b'F' => b'f',
|
||||
x => x
|
||||
}).collect();
|
||||
x => x,
|
||||
})
|
||||
.collect();
|
||||
let data_str = match String::from_utf8(lowercase) {
|
||||
Err(_) => return,
|
||||
Ok(s) => s,
|
||||
|
@ -33,25 +34,13 @@ fn do_test(data: &[u8]) {
|
|||
let string = deser.to_string();
|
||||
match OutPoint::from_str(&string) {
|
||||
Ok(destring) => assert_eq!(destring, deser),
|
||||
Err(_) => panic!()
|
||||
Err(_) => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "afl")]
|
||||
#[macro_use] extern crate afl;
|
||||
#[cfg(feature = "afl")]
|
||||
fn main() {
|
||||
fuzz!(|data| {
|
||||
do_test(&data);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use] extern crate honggfuzz;
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
|
@ -60,7 +49,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
|
@ -0,0 +1,52 @@
|
|||
use std::fmt;
|
||||
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
// faster than String, we don't need to actually produce the value, just check absence of panics
|
||||
struct NullWriter;
|
||||
|
||||
impl fmt::Write for NullWriter {
|
||||
fn write_str(&mut self, _s: &str) -> fmt::Result { Ok(()) }
|
||||
|
||||
fn write_char(&mut self, _c: char) -> fmt::Result { Ok(()) }
|
||||
}
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let mut writer = NullWriter;
|
||||
bitcoin::Script::from_bytes(data).fmt_asm(&mut writer).unwrap();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data| {
|
||||
do_test(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
||||
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
||||
b <<= 4;
|
||||
match *c {
|
||||
b'A'..=b'F' => b |= c - b'A' + 10,
|
||||
b'a'..=b'f' => b |= c - b'a' + 10,
|
||||
b'0'..=b'9' => b |= c - b'0',
|
||||
_ => panic!("Bad hex"),
|
||||
}
|
||||
if (idx & 1) == 1 {
|
||||
out.push(b);
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_crash() {
|
||||
let mut a = Vec::new();
|
||||
extend_vec_from_hex("00000", &mut a);
|
||||
super::do_test(&a);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,6 @@
|
|||
|
||||
extern crate serde;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
extern crate bitcoin_hashes;
|
||||
extern crate serde_cbor;
|
||||
|
||||
use bitcoin_hashes::Hmac;
|
||||
use bitcoin_hashes::{sha1, sha512, ripemd160, sha256d};
|
||||
use bitcoin::hashes::{ripemd160, sha1, sha256d, sha512, Hmac};
|
||||
use honggfuzz::fuzz;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct Hmacs {
|
||||
|
@ -27,27 +22,22 @@ fn do_test(data: &[u8]) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use]
|
||||
extern crate honggfuzz;
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|d| { do_test(d) });
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
||||
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
||||
b <<= 4;
|
||||
match *c {
|
||||
b'A'...b'F' => b |= c - b'A' + 10,
|
||||
b'a'...b'f' => b |= c - b'a' + 10,
|
||||
b'0'...b'9' => b |= c - b'0',
|
||||
b'A'..=b'F' => b |= c - b'A' + 10,
|
||||
b'a'..=b'f' => b |= c - b'a' + 10,
|
||||
b'0'..=b'9' => b |= c - b'0',
|
||||
_ => panic!("Bad hex"),
|
||||
}
|
||||
if (idx & 1) == 1 {
|
|
@ -1,11 +1,6 @@
|
|||
|
||||
extern crate serde;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
extern crate bitcoin_hashes;
|
||||
extern crate serde_json;
|
||||
|
||||
use bitcoin_hashes::Hmac;
|
||||
use bitcoin_hashes::{sha1, sha512, ripemd160, sha256d};
|
||||
use bitcoin::hashes::{ripemd160, sha1, sha256d, sha512, Hmac};
|
||||
use honggfuzz::fuzz;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct Hmacs {
|
||||
|
@ -27,27 +22,22 @@ fn do_test(data: &[u8]) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
#[macro_use]
|
||||
extern crate honggfuzz;
|
||||
|
||||
#[cfg(feature = "honggfuzz")]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|d| { do_test(d) });
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
||||
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
||||
b <<= 4;
|
||||
match *c {
|
||||
b'A'...b'F' => b |= c - b'A' + 10,
|
||||
b'a'...b'f' => b |= c - b'a' + 10,
|
||||
b'0'...b'9' => b |= c - b'0',
|
||||
b'A'..=b'F' => b |= c - b'A' + 10,
|
||||
b'a'..=b'f' => b |= c - b'a' + 10,
|
||||
b'0'..=b'9' => b |= c - b'0',
|
||||
_ => panic!("Bad hex"),
|
||||
}
|
||||
if (idx & 1) == 1 {
|
|
@ -0,0 +1,44 @@
|
|||
use bitcoin::hashes::{ripemd160, Hash, HashEngine};
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let mut engine = ripemd160::Hash::engine();
|
||||
engine.input(data);
|
||||
let eng_hash = ripemd160::Hash::from_engine(engine);
|
||||
|
||||
let hash = ripemd160::Hash::hash(data);
|
||||
assert_eq!(&hash[..], &eng_hash[..]);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|d| { do_test(d) });
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
||||
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
||||
b <<= 4;
|
||||
match *c {
|
||||
b'A'..=b'F' => b |= c - b'A' + 10,
|
||||
b'a'..=b'f' => b |= c - b'a' + 10,
|
||||
b'0'..=b'9' => b |= c - b'0',
|
||||
_ => panic!("Bad hex"),
|
||||
}
|
||||
if (idx & 1) == 1 {
|
||||
out.push(b);
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_crash() {
|
||||
let mut a = Vec::new();
|
||||
extend_vec_from_hex("00000", &mut a);
|
||||
super::do_test(&a);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
use bitcoin::hashes::{sha1, Hash, HashEngine};
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let mut engine = sha1::Hash::engine();
|
||||
engine.input(data);
|
||||
let eng_hash = sha1::Hash::from_engine(engine);
|
||||
|
||||
let hash = sha1::Hash::hash(data);
|
||||
assert_eq!(&hash[..], &eng_hash[..]);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|d| { do_test(d) });
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
||||
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
||||
b <<= 4;
|
||||
match *c {
|
||||
b'A'..=b'F' => b |= c - b'A' + 10,
|
||||
b'a'..=b'f' => b |= c - b'a' + 10,
|
||||
b'0'..=b'9' => b |= c - b'0',
|
||||
_ => panic!("Bad hex"),
|
||||
}
|
||||
if (idx & 1) == 1 {
|
||||
out.push(b);
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_crash() {
|
||||
let mut a = Vec::new();
|
||||
extend_vec_from_hex("00000", &mut a);
|
||||
super::do_test(&a);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
use bitcoin::hashes::{sha256, Hash, HashEngine};
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let mut engine = sha256::Hash::engine();
|
||||
engine.input(data);
|
||||
let eng_hash = sha256::Hash::from_engine(engine);
|
||||
|
||||
let hash = sha256::Hash::hash(data);
|
||||
assert_eq!(&hash[..], &eng_hash[..]);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|d| { do_test(d) });
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
||||
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
||||
b <<= 4;
|
||||
match *c {
|
||||
b'A'..=b'F' => b |= c - b'A' + 10,
|
||||
b'a'..=b'f' => b |= c - b'a' + 10,
|
||||
b'0'..=b'9' => b |= c - b'0',
|
||||
_ => panic!("Bad hex"),
|
||||
}
|
||||
if (idx & 1) == 1 {
|
||||
out.push(b);
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_crash() {
|
||||
let mut a = Vec::new();
|
||||
extend_vec_from_hex("fff400610004", &mut a);
|
||||
super::do_test(&a);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
use bitcoin::hashes::{sha512, Hash, HashEngine};
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let mut engine = sha512::Hash::engine();
|
||||
engine.input(data);
|
||||
let eng_hash = sha512::Hash::from_engine(engine);
|
||||
|
||||
let hash = sha512::Hash::hash(data);
|
||||
assert_eq!(&hash[..], &eng_hash[..]);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|d| { do_test(d) });
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
||||
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
||||
b <<= 4;
|
||||
match *c {
|
||||
b'A'..=b'F' => b |= c - b'A' + 10,
|
||||
b'a'..=b'f' => b |= c - b'a' + 10,
|
||||
b'0'..=b'9' => b |= c - b'0',
|
||||
_ => panic!("Bad hex"),
|
||||
}
|
||||
if (idx & 1) == 1 {
|
||||
out.push(b);
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_crash() {
|
||||
let mut a = Vec::new();
|
||||
extend_vec_from_hex("00000", &mut a);
|
||||
super::do_test(&a);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
use bitcoin::hashes::{sha512_256, Hash, HashEngine};
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
fn do_test(data: &[u8]) {
|
||||
let mut engine = sha512_256::Hash::engine();
|
||||
engine.input(data);
|
||||
let eng_hash = sha512_256::Hash::from_engine(engine);
|
||||
|
||||
let hash = sha512_256::Hash::hash(data);
|
||||
assert_eq!(&hash[..], &eng_hash[..]);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|d| { do_test(d) });
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, fuzzing))]
|
||||
mod tests {
|
||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||
let mut b = 0;
|
||||
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
||||
b <<= 4;
|
||||
match *c {
|
||||
b'A'..=b'F' => b |= c - b'A' + 10,
|
||||
b'a'..=b'f' => b |= c - b'a' + 10,
|
||||
b'0'..=b'9' => b |= c - b'0',
|
||||
_ => panic!("Bad hex"),
|
||||
}
|
||||
if (idx & 1) == 1 {
|
||||
out.push(b);
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_crash() {
|
||||
let mut a = Vec::new();
|
||||
extend_vec_from_hex("00000", &mut a);
|
||||
super::do_test(&a);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
REPO_DIR=$(git rev-parse --show-toplevel)
|
||||
|
||||
# shellcheck source=./fuzz-util.sh
|
||||
source "$REPO_DIR/fuzz/fuzz-util.sh"
|
||||
|
||||
# 1. Generate fuzz/Cargo.toml
|
||||
cat > "$REPO_DIR/fuzz/Cargo.toml" <<EOF
|
||||
[package]
|
||||
name = "bitcoin-fuzz"
|
||||
edition = "2018"
|
||||
version = "0.0.1"
|
||||
authors = ["Generated by fuzz/generate-files.sh"]
|
||||
publish = false
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
honggfuzz = { version = "0.5", default-features = false }
|
||||
bitcoin = { version = "0.30.0", features = [ "serde" ] }
|
||||
|
||||
serde = { version = "1.0.103", features = [ "derive" ] }
|
||||
serde_json = "1.0"
|
||||
serde_cbor = "0.9"
|
||||
EOF
|
||||
|
||||
for targetFile in $(listTargetFiles); do
|
||||
targetName=$(targetFileToName "$targetFile")
|
||||
cat >> "$REPO_DIR/fuzz/Cargo.toml" <<EOF
|
||||
|
||||
[[bin]]
|
||||
name = "$targetName"
|
||||
path = "$targetFile"
|
||||
EOF
|
||||
done
|
||||
|
||||
# 2. Generate .github/workflows/fuzz.yml
|
||||
cat > "$REPO_DIR/.github/workflows/fuzz.yml" <<EOF
|
||||
# Automatically generated by fuzz/generate-files.sh
|
||||
name: Fuzz
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- 'test-ci/**'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
fuzz:
|
||||
if: \${{ !github.event.act }}
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
fuzz_target: [
|
||||
$(for name in $(listTargetNames); do echo "$name,"; done)
|
||||
]
|
||||
steps:
|
||||
- name: Install test dependencies
|
||||
run: sudo apt-get update -y && sudo apt-get install -y binutils-dev libunwind8-dev libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc libiberty-dev
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
id: cache-fuzz
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin
|
||||
fuzz/target
|
||||
target
|
||||
key: cache-\${{ matrix.target }}-\${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }}
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: 1.58
|
||||
override: true
|
||||
profile: minimal
|
||||
- name: fuzz
|
||||
run: cd fuzz && ./fuzz.sh "\${{ matrix.fuzz_target }}"
|
||||
- run: echo "\${{ matrix.fuzz_target }}" >executed_\${{ matrix.fuzz_target }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: executed_\${{ matrix.fuzz_target }}
|
||||
path: executed_\${{ matrix.fuzz_target }}
|
||||
|
||||
verify-execution:
|
||||
if: \${{ !github.event.act }}
|
||||
needs: fuzz
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@v2
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -R
|
||||
- run: find executed_* -type f -exec cat {} + | sort > executed
|
||||
- run: source ./fuzz/fuzz-util.sh && listTargetNames | sort | diff - executed
|
||||
EOF
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue