diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index d0b9a86f..43d63419 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - fuzz_target: [deser_net_msg, deserialize_address, deserialize_amount, deserialize_block, deserialize_psbt, deserialize_script, deserialize_transaction, outpoint_string, uint128_fuzz, script_bytes_to_asm_fmt] + fuzz_target: [deser_net_msg, deserialize_address, deserialize_amount, deserialize_block, deserialize_psbt, deserialize_script, deserialize_transaction, deserialize_witness, outpoint_string, uint128_fuzz, script_bytes_to_asm_fmt] 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 diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index e8dff82d..b893483b 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -59,3 +59,7 @@ path = "fuzz_targets/uint128_fuzz.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" diff --git a/fuzz/fuzz_targets/deserialize_transaction.rs b/fuzz/fuzz_targets/deserialize_transaction.rs index 67ad6ce7..ca7b2de2 100644 --- a/fuzz/fuzz_targets/deserialize_transaction.rs +++ b/fuzz/fuzz_targets/deserialize_transaction.rs @@ -10,7 +10,7 @@ fn do_test(data: &[u8]) { let len = ser.len(); let calculated_weight = tx.get_weight(); for input in &mut tx.input { - input.witness = vec![]; + input.witness = bitcoin::blockdata::witness::Witness::default(); } let no_witness_len = bitcoin::consensus::encode::serialize(&tx).len(); // For 0-input transactions, `no_witness_len` will be incorrect because diff --git a/fuzz/fuzz_targets/deserialize_witness.rs b/fuzz/fuzz_targets/deserialize_witness.rs new file mode 100644 index 00000000..b445e8d5 --- /dev/null +++ b/fuzz/fuzz_targets/deserialize_witness.rs @@ -0,0 +1,59 @@ +extern crate bitcoin; + +use bitcoin::consensus::{serialize, deserialize}; +use bitcoin::blockdata::witness::Witness; + +fn do_test(data: &[u8]) { + let w: Result = deserialize(data); + if let Ok(witness) = w { + let serialized = serialize(&witness); + 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| { + do_test(data); + }); + } +} + +#[cfg(test)] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + 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("00", &mut a); + super::do_test(&a); + } +}