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
|
name: Fuzz
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
@ -8,14 +9,32 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
fuzz:
|
fuzz:
|
||||||
if: ${{ !github.event.act }}
|
if: ${{ !github.event.act }}
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
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:
|
steps:
|
||||||
- name: Install test dependencies
|
- 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
|
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
|
override: true
|
||||||
profile: minimal
|
profile: minimal
|
||||||
- name: fuzz
|
- name: fuzz
|
||||||
run: cd bitcoin/fuzz && ./travis-fuzz.sh "${{ matrix.fuzz_target }}"
|
run: cd fuzz && ./fuzz.sh "${{ matrix.fuzz_target }}"
|
||||||
- run: echo "${{ matrix.fuzz_target }}.rs" >executed_${{ matrix.fuzz_target }}
|
- run: echo "${{ matrix.fuzz_target }}" >executed_${{ matrix.fuzz_target }}
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: executed_${{ matrix.fuzz_target }}
|
name: executed_${{ matrix.fuzz_target }}
|
||||||
|
@ -51,5 +70,4 @@ jobs:
|
||||||
- name: Display structure of downloaded files
|
- name: Display structure of downloaded files
|
||||||
run: ls -R
|
run: ls -R
|
||||||
- run: find executed_* -type f -exec cat {} + | sort > executed
|
- run: find executed_* -type f -exec cat {} + | sort > executed
|
||||||
- run: ls bitcoin/fuzz/fuzz_targets | sort > expected
|
- run: source ./fuzz/fuzz-util.sh && listTargetNames | sort | diff - executed
|
||||||
- run: diff expected executed
|
|
||||||
|
|
|
@ -16,7 +16,5 @@ hashes/target
|
||||||
bitcoin/dep_test
|
bitcoin/dep_test
|
||||||
|
|
||||||
# Fuzz artifacts
|
# Fuzz artifacts
|
||||||
bitcoin/fuzz/hfuzz_target
|
hfuzz_target
|
||||||
bitcoin/fuzz/hfuzz_workspace
|
hfuzz_workspace
|
||||||
hashes/fuzz/hfuzz_target
|
|
||||||
hashes/fuzz/hfuzz_workspace
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["bitcoin", "hashes", "internals"]
|
members = ["bitcoin", "hashes", "internals", "fuzz"]
|
||||||
|
|
||||||
|
[patch.crates-io.bitcoin]
|
||||||
|
path = "bitcoin"
|
||||||
|
|
||||||
[patch.crates-io.bitcoin_hashes]
|
[patch.crates-io.bitcoin_hashes]
|
||||||
path = "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
|
# serde 1.0.157 uses syn 2.0 which requires edition 2021
|
||||||
cargo update -p serde --precise 1.0.156
|
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
|
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
|
RUSTDOCFLAGS="-D warnings" cargo +stable doc --all-features
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Fuzz if told to
|
|
||||||
if [ "$DO_FUZZ" = true ]
|
|
||||||
then
|
|
||||||
(
|
|
||||||
cd fuzz
|
|
||||||
cargo test --verbose
|
|
||||||
./travis-fuzz.sh
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run formatter if told to.
|
# Run formatter if told to.
|
||||||
if [ "$DO_FMT" = true ]; then
|
if [ "$DO_FMT" = true ]; then
|
||||||
if [ "$NIGHTLY" = false ]; 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
|
set -ex
|
||||||
|
|
||||||
CRATES="bitcoin hashes internals"
|
CRATES="bitcoin hashes internals fuzz"
|
||||||
|
|
||||||
for crate in ${CRATES}
|
for crate in ${CRATES}
|
||||||
do
|
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]) {
|
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() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|data| {
|
fuzz!(|data| {
|
||||||
|
@ -24,7 +13,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
|
@ -1,5 +1,7 @@
|
||||||
extern crate bitcoin;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use honggfuzz::fuzz;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
fn do_test(data: &[u8]) {
|
||||||
let data_str = String::from_utf8_lossy(data);
|
let data_str = String::from_utf8_lossy(data);
|
||||||
let addr = match bitcoin::address::Address::from_str(&data_str) {
|
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);
|
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() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|data| {
|
fuzz!(|data| {
|
||||||
|
@ -29,7 +19,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
|
@ -1,5 +1,7 @@
|
||||||
extern crate bitcoin;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use honggfuzz::fuzz;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
fn do_test(data: &[u8]) {
|
||||||
let data_str = String::from_utf8_lossy(data);
|
let data_str = String::from_utf8_lossy(data);
|
||||||
|
|
||||||
|
@ -26,18 +28,6 @@ fn do_test(data: &[u8]) {
|
||||||
assert_eq!(amt, amt_roundtrip);
|
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() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|data| {
|
fuzz!(|data| {
|
||||||
|
@ -46,7 +36,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
|
@ -1,21 +1,10 @@
|
||||||
extern crate bitcoin;
|
use honggfuzz::fuzz;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
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() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|data| {
|
fuzz!(|data| {
|
||||||
|
@ -24,7 +13,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
|
@ -1,30 +1,19 @@
|
||||||
extern crate bitcoin;
|
use honggfuzz::fuzz;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
fn do_test(data: &[u8]) {
|
||||||
// We already fuzz Transactions in `./deserialize_transaction.rs`.
|
// 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 {
|
match tx_result {
|
||||||
Err(_) => {},
|
Err(_) => {}
|
||||||
Ok(mut tx) => {
|
Ok(tx) => {
|
||||||
let ser = bitcoin::consensus::encode::serialize(&tx);
|
let ser = bitcoin::consensus::encode::serialize(&tx);
|
||||||
assert_eq!(&ser[..], data);
|
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() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|data| {
|
fuzz!(|data| {
|
||||||
|
@ -33,7 +22,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
|
@ -1,9 +1,10 @@
|
||||||
extern crate bitcoin;
|
use honggfuzz::fuzz;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
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 {
|
match psbt {
|
||||||
Err(_) => {},
|
Err(_) => {}
|
||||||
Ok(psbt) => {
|
Ok(psbt) => {
|
||||||
let ser = bitcoin::psbt::Psbt::serialize(&psbt);
|
let ser = bitcoin::psbt::Psbt::serialize(&psbt);
|
||||||
let deser = bitcoin::psbt::Psbt::deserialize(&ser).unwrap();
|
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() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|data| {
|
fuzz!(|data| {
|
||||||
|
@ -33,7 +22,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
|
@ -1,9 +1,8 @@
|
||||||
extern crate bitcoin;
|
|
||||||
|
|
||||||
use bitcoin::address::Address;
|
use bitcoin::address::Address;
|
||||||
use bitcoin::network::constants::Network;
|
|
||||||
use bitcoin::blockdata::script;
|
use bitcoin::blockdata::script;
|
||||||
use bitcoin::consensus::encode;
|
use bitcoin::consensus::encode;
|
||||||
|
use bitcoin::network::constants::Network;
|
||||||
|
use honggfuzz::fuzz;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
fn do_test(data: &[u8]) {
|
||||||
let s: Result<script::ScriptBuf, _> = encode::deserialize(data);
|
let s: Result<script::ScriptBuf, _> = encode::deserialize(data);
|
||||||
|
@ -16,7 +15,9 @@ fn do_test(data: &[u8]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match ins.ok().unwrap() {
|
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) => {
|
script::Instruction::PushBytes(bytes) => {
|
||||||
// Any one-byte pushes, except -0, which can be interpreted as numbers, should be
|
// 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
|
// 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() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|data| {
|
fuzz!(|data| {
|
||||||
|
@ -63,7 +52,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
|
@ -1,9 +1,10 @@
|
||||||
extern crate bitcoin;
|
use honggfuzz::fuzz;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
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 {
|
match tx_result {
|
||||||
Err(_) => {},
|
Err(_) => {}
|
||||||
Ok(mut tx) => {
|
Ok(mut tx) => {
|
||||||
let ser = bitcoin::consensus::encode::serialize(&tx);
|
let ser = bitcoin::consensus::encode::serialize(&tx);
|
||||||
assert_eq!(&ser[..], data);
|
assert_eq!(&ser[..], data);
|
||||||
|
@ -21,22 +22,10 @@ fn do_test(data: &[u8]) {
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(no_witness_len * 3 + len, calculated_weight);
|
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() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|data| {
|
fuzz!(|data| {
|
||||||
|
@ -45,7 +34,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
|
@ -1,28 +1,15 @@
|
||||||
extern crate bitcoin;
|
|
||||||
|
|
||||||
use bitcoin::consensus::{serialize, deserialize};
|
|
||||||
use bitcoin::blockdata::witness::Witness;
|
use bitcoin::blockdata::witness::Witness;
|
||||||
|
use bitcoin::consensus::{deserialize, serialize};
|
||||||
|
use honggfuzz::fuzz;
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
fn do_test(data: &[u8]) {
|
||||||
let w: Result<Witness, _> = deserialize(data);
|
let w: Result<Witness, _> = deserialize(data);
|
||||||
if let Ok(witness) = w {
|
if let Ok(witness) = w {
|
||||||
let serialized = serialize(&witness);
|
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() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|data| {
|
fuzz!(|data| {
|
||||||
|
@ -31,7 +18,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
|
@ -1,21 +1,22 @@
|
||||||
|
use std::str::FromStr;
|
||||||
extern crate bitcoin;
|
|
||||||
|
|
||||||
use bitcoin::blockdata::transaction::OutPoint;
|
use bitcoin::blockdata::transaction::OutPoint;
|
||||||
use bitcoin::consensus::encode;
|
use bitcoin::consensus::encode;
|
||||||
|
use honggfuzz::fuzz;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
fn do_test(data: &[u8]) {
|
fn do_test(data: &[u8]) {
|
||||||
let lowercase: Vec<u8> = data.iter().map(|c| match *c {
|
let lowercase: Vec<u8> = data
|
||||||
b'A' => b'a',
|
.iter()
|
||||||
b'B' => b'b',
|
.map(|c| match *c {
|
||||||
b'C' => b'c',
|
b'A' => b'a',
|
||||||
b'D' => b'd',
|
b'B' => b'b',
|
||||||
b'E' => b'e',
|
b'C' => b'c',
|
||||||
b'F' => b'f',
|
b'D' => b'd',
|
||||||
x => x
|
b'E' => b'e',
|
||||||
}).collect();
|
b'F' => b'f',
|
||||||
|
x => x,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
let data_str = match String::from_utf8(lowercase) {
|
let data_str = match String::from_utf8(lowercase) {
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
|
@ -33,25 +34,13 @@ fn do_test(data: &[u8]) {
|
||||||
let string = deser.to_string();
|
let string = deser.to_string();
|
||||||
match OutPoint::from_str(&string) {
|
match OutPoint::from_str(&string) {
|
||||||
Ok(destring) => assert_eq!(destring, deser),
|
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() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|data| {
|
fuzz!(|data| {
|
||||||
|
@ -60,7 +49,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
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 @@
|
||||||
|
use bitcoin::hashes::{ripemd160, sha1, sha256d, sha512, Hmac};
|
||||||
extern crate serde;
|
use honggfuzz::fuzz;
|
||||||
#[macro_use] extern crate serde_derive;
|
use serde::{Deserialize, Serialize};
|
||||||
extern crate bitcoin_hashes;
|
|
||||||
extern crate serde_cbor;
|
|
||||||
|
|
||||||
use bitcoin_hashes::Hmac;
|
|
||||||
use bitcoin_hashes::{sha1, sha512, ripemd160, sha256d};
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
struct Hmacs {
|
struct Hmacs {
|
||||||
|
@ -27,27 +22,22 @@ fn do_test(data: &[u8]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "honggfuzz")]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate honggfuzz;
|
|
||||||
|
|
||||||
#[cfg(feature = "honggfuzz")]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|d| { do_test(d) });
|
fuzz!(|d| { do_test(d) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
||||||
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
||||||
b <<= 4;
|
b <<= 4;
|
||||||
match *c {
|
match *c {
|
||||||
b'A'...b'F' => b |= c - b'A' + 10,
|
b'A'..=b'F' => b |= c - b'A' + 10,
|
||||||
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'0'..=b'9' => b |= c - b'0',
|
||||||
_ => panic!("Bad hex"),
|
_ => panic!("Bad hex"),
|
||||||
}
|
}
|
||||||
if (idx & 1) == 1 {
|
if (idx & 1) == 1 {
|
|
@ -1,11 +1,6 @@
|
||||||
|
use bitcoin::hashes::{ripemd160, sha1, sha256d, sha512, Hmac};
|
||||||
extern crate serde;
|
use honggfuzz::fuzz;
|
||||||
#[macro_use] extern crate serde_derive;
|
use serde::{Deserialize, Serialize};
|
||||||
extern crate bitcoin_hashes;
|
|
||||||
extern crate serde_json;
|
|
||||||
|
|
||||||
use bitcoin_hashes::Hmac;
|
|
||||||
use bitcoin_hashes::{sha1, sha512, ripemd160, sha256d};
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
struct Hmacs {
|
struct Hmacs {
|
||||||
|
@ -27,27 +22,22 @@ fn do_test(data: &[u8]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "honggfuzz")]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate honggfuzz;
|
|
||||||
|
|
||||||
#[cfg(feature = "honggfuzz")]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
loop {
|
loop {
|
||||||
fuzz!(|d| { do_test(d) });
|
fuzz!(|d| { do_test(d) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, fuzzing))]
|
||||||
mod tests {
|
mod tests {
|
||||||
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
|
||||||
let mut b = 0;
|
let mut b = 0;
|
||||||
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
for (idx, c) in hex.as_bytes().iter().enumerate() {
|
||||||
b <<= 4;
|
b <<= 4;
|
||||||
match *c {
|
match *c {
|
||||||
b'A'...b'F' => b |= c - b'A' + 10,
|
b'A'..=b'F' => b |= c - b'A' + 10,
|
||||||
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'0'..=b'9' => b |= c - b'0',
|
||||||
_ => panic!("Bad hex"),
|
_ => panic!("Bad hex"),
|
||||||
}
|
}
|
||||||
if (idx & 1) == 1 {
|
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