From 6fea17f446ce0fd3573c195d8240a4c0d1b34304 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 8 May 2023 19:21:07 +0000 Subject: [PATCH 1/5] fuzz: copy *.sh files from rust-bitcoin; tweak generate-files.sh --- fuzz/cycle.sh | 25 +++++++++++ fuzz/fuzz-util.sh | 51 ++++++++++++++++++++++ fuzz/fuzz.sh | 34 +++++++++++++++ fuzz/generate-files.sh | 98 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100755 fuzz/cycle.sh create mode 100755 fuzz/fuzz-util.sh create mode 100755 fuzz/fuzz.sh create mode 100755 fuzz/generate-files.sh diff --git a/fuzz/cycle.sh b/fuzz/cycle.sh new file mode 100755 index 000000000..0b59827a1 --- /dev/null +++ b/fuzz/cycle.sh @@ -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 + diff --git a/fuzz/fuzz-util.sh b/fuzz/fuzz-util.sh new file mode 100755 index 000000000..804e0da92 --- /dev/null +++ b/fuzz/fuzz-util.sh @@ -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 +} diff --git a/fuzz/fuzz.sh b/fuzz/fuzz.sh new file mode 100755 index 000000000..5fc65ae63 --- /dev/null +++ b/fuzz/fuzz.sh @@ -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 diff --git a/fuzz/generate-files.sh b/fuzz/generate-files.sh new file mode 100755 index 000000000..f5e91f539 --- /dev/null +++ b/fuzz/generate-files.sh @@ -0,0 +1,98 @@ +#!/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" <> "$REPO_DIR/fuzz/Cargo.toml" < "$REPO_DIR/.github/workflows/fuzz.yml" <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 + From 14ceccd823dd1ef0794f735d2a81bb3d69e69bc3 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 8 May 2023 19:22:00 +0000 Subject: [PATCH 2/5] fuzz: remove existing CI; run fuzz/generate-files.sh to make new one --- .github/workflows/fuzz.yml | 63 ++++++++++++++++++++++++++++++++++++++ .github/workflows/rust.yml | 19 ------------ contrib/test.sh | 11 ------- fuzz/Cargo.toml | 43 ++++++++++++-------------- 4 files changed, 83 insertions(+), 53 deletions(-) create mode 100644 .github/workflows/fuzz.yml diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml new file mode 100644 index 000000000..e3225591b --- /dev/null +++ b/.github/workflows/fuzz.yml @@ -0,0 +1,63 @@ +# 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: [ +roundtrip_miniscript_str, +roundtrip_miniscript_script, +parse_descriptor, +roundtrip_semantic, +parse_descriptor_secret, +roundtrip_descriptor, +roundtrip_concrete, +compile_descriptor, + ] + 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 diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8e91289c9..d035a0d6d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -3,25 +3,6 @@ on: [push, pull_request] name: Continuous integration jobs: - Fuzz: - name: Fuzz - runs-on: ubuntu-latest - steps: - - name: Checkout Crate - uses: actions/checkout@v2 - - name: Install hongfuzz dependencies - run: sudo apt update && sudo apt install build-essential binutils-dev libunwind-dev libblocksruntime-dev liblzma-dev - - name: Checkout Toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.58.0 - override: true - - name: Running fuzzer - env: - DO_FUZZ: true - run: ./contrib/test.sh - Nightly: name: Nightly - Bench + Docs + Fmt runs-on: ubuntu-latest diff --git a/contrib/test.sh b/contrib/test.sh index edb530892..eed23e09c 100755 --- a/contrib/test.sh +++ b/contrib/test.sh @@ -26,17 +26,6 @@ if cargo --version | grep "1\.47\.0"; then cargo update -p serde --precise 1.0.156 fi -# Fuzz if told to -if [ "$DO_FUZZ" = true ] -then - cd fuzz - cargo test --verbose - ./travis-fuzz.sh - - # Exit out of the fuzzer, do not run other tests. - exit 0 -fi - # Test bitcoind integration tests if told to (this only works with the stable toolchain) if [ "$DO_BITCOIND_TESTS" = true ]; then cd bitcoind-tests diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 6f93ec66d..542183526 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -1,50 +1,47 @@ [package] name = "descriptor-fuzz" +edition = "2018" version = "0.0.1" -authors = ["Automatically generated"] +authors = ["Generated by fuzz/generate-files.sh"] publish = false [package.metadata] cargo-fuzz = true -[features] -afl_fuzz = ["afl"] -honggfuzz_fuzz = ["honggfuzz"] - [dependencies] -honggfuzz = { version = "0.5.55", default-features = false, optional = true } -afl = { version = "0.8", optional = true } -regex = { version = "1.4"} -miniscript = { path = "..", features = ["compiler"] } +honggfuzz = { version = "0.5.55", default-features = false } +miniscript = { path = "..", features = [ "compiler" ] } + +regex = "1.4" [[bin]] -name = "roundtrip_descriptor" -path = "fuzz_targets/roundtrip_descriptor.rs" +name = "roundtrip_miniscript_str" +path = "fuzz_targets/roundtrip_miniscript_str.rs" [[bin]] name = "roundtrip_miniscript_script" path = "fuzz_targets/roundtrip_miniscript_script.rs" [[bin]] -name = "roundtrip_miniscript_str" -path = "fuzz_targets/roundtrip_miniscript_str.rs" - -[[bin]] -name = "roundtrip_concrete" -path = "fuzz_targets/roundtrip_concrete.rs" +name = "parse_descriptor" +path = "fuzz_targets/parse_descriptor.rs" [[bin]] name = "roundtrip_semantic" path = "fuzz_targets/roundtrip_semantic.rs" [[bin]] -name = "compile_descriptor" -path = "fuzz_targets/compile_descriptor.rs" +name = "parse_descriptor_secret" +path = "fuzz_targets/parse_descriptor_secret.rs" [[bin]] -name = "parse_descriptor" -path = "fuzz_targets/parse_descriptor.rs" +name = "roundtrip_descriptor" +path = "fuzz_targets/roundtrip_descriptor.rs" [[bin]] -name = "parse_descriptor_secret" -path = "fuzz_targets/parse_descriptor_secret.rs" +name = "roundtrip_concrete" +path = "fuzz_targets/roundtrip_concrete.rs" + +[[bin]] +name = "compile_descriptor" +path = "fuzz_targets/compile_descriptor.rs" From 8e8dcb466fc736648ff42f65b4b1f90f5d6d6de7 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 8 May 2023 19:27:59 +0000 Subject: [PATCH 3/5] fuzz: remove afl support, run clippy and fmt on fuzz targets --- fuzz/fuzz_targets/compile_descriptor.rs | 21 ++-------------- fuzz/fuzz_targets/parse_descriptor.rs | 20 +++------------- fuzz/fuzz_targets/parse_descriptor_secret.rs | 16 +------------ fuzz/fuzz_targets/roundtrip_concrete.rs | 22 ++++------------- fuzz/fuzz_targets/roundtrip_descriptor.rs | 18 +------------- .../roundtrip_miniscript_script.rs | 24 ++++--------------- fuzz/fuzz_targets/roundtrip_miniscript_str.rs | 24 ++++--------------- fuzz/fuzz_targets/roundtrip_semantic.rs | 16 +------------ 8 files changed, 21 insertions(+), 140 deletions(-) diff --git a/fuzz/fuzz_targets/compile_descriptor.rs b/fuzz/fuzz_targets/compile_descriptor.rs index add5a8670..cfd6c7f4f 100644 --- a/fuzz/fuzz_targets/compile_descriptor.rs +++ b/fuzz/fuzz_targets/compile_descriptor.rs @@ -1,7 +1,6 @@ -extern crate miniscript; - use std::str::FromStr; +use honggfuzz::fuzz; use miniscript::{policy, Miniscript, Segwitv0}; use policy::Liftable; @@ -14,10 +13,7 @@ fn do_test(data: &[u8]) { // Compile if let Ok(desc) = pol.compile::() { // Lift - assert_eq!( - desc.clone().lift().unwrap().sorted(), - pol.clone().lift().unwrap().sorted() - ); + assert_eq!(desc.lift().unwrap().sorted(), pol.lift().unwrap().sorted()); // Try to roundtrip the output of the compiler let output = desc.to_string(); if let Ok(desc) = Script::from_str(&output) { @@ -30,19 +26,6 @@ fn do_test(data: &[u8]) { } } -#[cfg(feature = "afl")] -extern crate afl; -#[cfg(feature = "afl")] -fn main() { - afl::read_stdio_bytes(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] -extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { diff --git a/fuzz/fuzz_targets/parse_descriptor.rs b/fuzz/fuzz_targets/parse_descriptor.rs index 63fb6f134..1d1ee77a1 100644 --- a/fuzz/fuzz_targets/parse_descriptor.rs +++ b/fuzz/fuzz_targets/parse_descriptor.rs @@ -1,30 +1,16 @@ -extern crate miniscript; - use std::str::FromStr; +use honggfuzz::fuzz; use miniscript::DescriptorPublicKey; fn do_test(data: &[u8]) { let data_str = String::from_utf8_lossy(data); if let Ok(dpk) = DescriptorPublicKey::from_str(&data_str) { - let output = dpk.to_string(); - // assert_eq!(data_str.to_lowercase(), output.to_lowercase()); + let _output = dpk.to_string(); + // assert_eq!(data_str.to_lowercase(), _output.to_lowercase()); } } -#[cfg(feature = "afl")] -extern crate afl; -#[cfg(feature = "afl")] -fn main() { - afl::read_stdio_bytes(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] -extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { diff --git a/fuzz/fuzz_targets/parse_descriptor_secret.rs b/fuzz/fuzz_targets/parse_descriptor_secret.rs index 951630e0e..8ef758bb5 100644 --- a/fuzz/fuzz_targets/parse_descriptor_secret.rs +++ b/fuzz/fuzz_targets/parse_descriptor_secret.rs @@ -1,7 +1,6 @@ -extern crate miniscript; - use std::str::FromStr; +use honggfuzz::fuzz; use miniscript::descriptor::DescriptorSecretKey; fn do_test(data: &[u8]) { @@ -12,19 +11,6 @@ fn do_test(data: &[u8]) { } } -#[cfg(feature = "afl")] -extern crate afl; -#[cfg(feature = "afl")] -fn main() { - afl::read_stdio_bytes(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] -extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { diff --git a/fuzz/fuzz_targets/roundtrip_concrete.rs b/fuzz/fuzz_targets/roundtrip_concrete.rs index d0ca6fd1b..41e437221 100644 --- a/fuzz/fuzz_targets/roundtrip_concrete.rs +++ b/fuzz/fuzz_targets/roundtrip_concrete.rs @@ -1,7 +1,6 @@ -extern crate miniscript; -extern crate regex; use std::str::FromStr; +use honggfuzz::fuzz; use miniscript::policy; use regex::Regex; @@ -19,19 +18,6 @@ fn do_test(data: &[u8]) { } } -#[cfg(feature = "afl")] -extern crate afl; -#[cfg(feature = "afl")] -fn main() { - afl::read_stdio_bytes(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] -extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { @@ -47,9 +33,9 @@ mod tests { 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 { diff --git a/fuzz/fuzz_targets/roundtrip_descriptor.rs b/fuzz/fuzz_targets/roundtrip_descriptor.rs index 7ee6653b2..d74569e88 100644 --- a/fuzz/fuzz_targets/roundtrip_descriptor.rs +++ b/fuzz/fuzz_targets/roundtrip_descriptor.rs @@ -1,10 +1,7 @@ -extern crate miniscript; -extern crate regex; - use std::str::FromStr; +use honggfuzz::fuzz; use miniscript::Descriptor; -use regex::Regex; fn do_test(data: &[u8]) { let s = String::from_utf8_lossy(data); @@ -16,19 +13,6 @@ fn do_test(data: &[u8]) { } } -#[cfg(feature = "afl")] -extern crate afl; -#[cfg(feature = "afl")] -fn main() { - afl::read_stdio_bytes(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] -extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { diff --git a/fuzz/fuzz_targets/roundtrip_miniscript_script.rs b/fuzz/fuzz_targets/roundtrip_miniscript_script.rs index d825be31d..2215e18a5 100644 --- a/fuzz/fuzz_targets/roundtrip_miniscript_script.rs +++ b/fuzz/fuzz_targets/roundtrip_miniscript_script.rs @@ -1,5 +1,4 @@ -extern crate miniscript; - +use honggfuzz::fuzz; use miniscript::bitcoin::blockdata::script; use miniscript::{Miniscript, Segwitv0}; @@ -7,26 +6,13 @@ fn do_test(data: &[u8]) { // Try round-tripping as a script let script = script::Script::from_bytes(data); - if let Ok(pt) = Miniscript::::parse(&script) { + if let Ok(pt) = Miniscript::::parse(script) { let output = pt.encode(); assert_eq!(pt.script_size(), output.len()); assert_eq!(&output, script); } } -#[cfg(feature = "afl")] -extern crate afl; -#[cfg(feature = "afl")] -fn main() { - afl::read_stdio_bytes(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] -extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { @@ -42,9 +28,9 @@ mod tests { 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 { diff --git a/fuzz/fuzz_targets/roundtrip_miniscript_str.rs b/fuzz/fuzz_targets/roundtrip_miniscript_str.rs index b6b742c18..98d247af0 100644 --- a/fuzz/fuzz_targets/roundtrip_miniscript_str.rs +++ b/fuzz/fuzz_targets/roundtrip_miniscript_str.rs @@ -1,10 +1,7 @@ -extern crate miniscript; -extern crate regex; - use std::str::FromStr; +use honggfuzz::fuzz; use miniscript::{Miniscript, Segwitv0}; -use regex::Regex; fn do_test(data: &[u8]) { let s = String::from_utf8_lossy(data); @@ -16,19 +13,6 @@ fn do_test(data: &[u8]) { } } -#[cfg(feature = "afl")] -extern crate afl; -#[cfg(feature = "afl")] -fn main() { - afl::read_stdio_bytes(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] -extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { @@ -44,9 +28,9 @@ mod tests { 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 { diff --git a/fuzz/fuzz_targets/roundtrip_semantic.rs b/fuzz/fuzz_targets/roundtrip_semantic.rs index d363d7e44..cebc223b2 100644 --- a/fuzz/fuzz_targets/roundtrip_semantic.rs +++ b/fuzz/fuzz_targets/roundtrip_semantic.rs @@ -1,7 +1,6 @@ -extern crate miniscript; - use std::str::FromStr; +use honggfuzz::fuzz; use miniscript::policy; type Policy = policy::Semantic; @@ -14,19 +13,6 @@ fn do_test(data: &[u8]) { } } -#[cfg(feature = "afl")] -extern crate afl; -#[cfg(feature = "afl")] -fn main() { - afl::read_stdio_bytes(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] -extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { From 7b04860d6f2746e591c894df785547d3cc707215 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 8 May 2023 19:28:24 +0000 Subject: [PATCH 4/5] fuzz: delete old ./travis-fuzz.sh --- fuzz/travis-fuzz.sh | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100755 fuzz/travis-fuzz.sh diff --git a/fuzz/travis-fuzz.sh b/fuzz/travis-fuzz.sh deleted file mode 100755 index db1b9eb38..000000000 --- a/fuzz/travis-fuzz.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -set -e -cargo install --force honggfuzz --no-default-features -for TARGET in fuzz_targets/*; do - 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="-N1000000 --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 From a6405f844695077b27aedd51932fad7dd5dfbd4c Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 8 May 2023 19:31:19 +0000 Subject: [PATCH 5/5] fuzz: replace README.md --- fuzz/README.md | 120 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 7 deletions(-) diff --git a/fuzz/README.md b/fuzz/README.md index f636c9d82..2b4a2730b 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -1,13 +1,119 @@ -# Fuzz Tests +# Fuzzing -Repository for fuzz testing Miniscript. +`miniscript` has a fuzzing harness setup for use with honggfuzz. -## How to reproduce crashes? +To run the fuzz-tests as in CI -- briefly fuzzing every target -- simply +run -Travis should output a offending hex("048531e80700ae6400670000af5168" in the example) -which you can use as shown. Copy and paste the following code lines into file reporting crashes and -replace the hex with the offending hex. -Refer to file [roundtrip_concrete.rs](./fuzz_targets/roundtrip_concrete.rs) for an example. + ./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. + +# Fuzzing with weak cryptography + +You may wish to replace the hashing and signing code with broken crypto, +which will be faster and enable the fuzzer to do otherwise impossible +things such as forging signatures or finding preimages to hashes. + +Doing so may result in spurious bug reports since the broken crypto does +not respect the encoding or algebraic invariants upheld by the real crypto. We +would like to improve this but it's a nontrivial problem -- though not +beyond the abilities of a motivated student with a few months of time. +Please let us know if you are interested in taking this on! + +Meanwhile, to use the broken crypto, simply compile (and run the fuzzing +scripts) with + + RUSTFLAGS="--cfg=hashes_fuzz --cfg=secp256k1_fuzz" + +which will replace the hashing library with broken hashes, and the +secp256k1 library with broken cryptography. + +Needless to say, NEVER COMPILE REAL CODE WITH THESE FLAGS because if a +fuzzer can break your crypto, so can anybody. + +# 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 + + cargo hfuzz run + +`cycle.sh` 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 + +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 + + cargo test + +Note that if you set your `RUSTFLAGS` while fuzzing (see above) you must make +sure they are set the same way when running `cargo test`. + +If the `duplicate_crash` function is not present, please add it. A template is +as follows: ``` #[cfg(test)]