Skip to content

Commit ac46eb9

Browse files
committed
Fix fuzzer crash while allocating keys for multi_a
1 parent 84feb33 commit ac46eb9

File tree

4 files changed

+64
-0
lines changed

4 files changed

+64
-0
lines changed

fuzz/fuzz_targets/roundtrip_miniscript_script.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,30 @@ fn main() {
3535
});
3636
}
3737
}
38+
39+
#[cfg(test)]
40+
mod tests {
41+
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
42+
let mut b = 0;
43+
for (idx, c) in hex.as_bytes().iter().enumerate() {
44+
b <<= 4;
45+
match *c {
46+
b'A'...b'F' => b |= c - b'A' + 10,
47+
b'a'...b'f' => b |= c - b'a' + 10,
48+
b'0'...b'9' => b |= c - b'0',
49+
_ => panic!("Bad hex"),
50+
}
51+
if (idx & 1) == 1 {
52+
out.push(b);
53+
b = 0;
54+
}
55+
}
56+
}
57+
58+
#[test]
59+
fn duplicate_crash3() {
60+
let mut a = Vec::new();
61+
extend_vec_from_hex("1479002d00000020323731363342740000004000000000000000000000000000000000000063630004636363639c00000000000000000000", &mut a);
62+
super::do_test(&a);
63+
}
64+
}

fuzz/fuzz_targets/roundtrip_miniscript_str.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,30 @@ fn main() {
3838
});
3939
}
4040
}
41+
42+
#[cfg(test)]
43+
mod tests {
44+
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
45+
let mut b = 0;
46+
for (idx, c) in hex.as_bytes().iter().enumerate() {
47+
b <<= 4;
48+
match *c {
49+
b'A'...b'F' => b |= c - b'A' + 10,
50+
b'a'...b'f' => b |= c - b'a' + 10,
51+
b'0'...b'9' => b |= c - b'0',
52+
_ => panic!("Bad hex"),
53+
}
54+
if (idx & 1) == 1 {
55+
out.push(b);
56+
b = 0;
57+
}
58+
}
59+
}
60+
61+
#[test]
62+
fn duplicate_crash() {
63+
let mut a = Vec::new();
64+
extend_vec_from_hex("1479002d00000020323731363342740000004000000000000000000000000000000000000063630004636363639c00000000000000000000", &mut a);
65+
super::do_test(&a);
66+
}
67+
}

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,8 @@ pub enum Error {
481481
AddrError(bitcoin::util::address::Error),
482482
/// A `CHECKMULTISIG` opcode was preceded by a number > 20
483483
CmsTooManyKeys(u32),
484+
/// A tapscript multi_a cannot support more than MAX_BLOCK_WEIGHT/32 keys
485+
MultiATooManyKeys(u32),
484486
/// Encountered unprintable character in descriptor
485487
Unprintable(u8),
486488
/// expected character while parsing descriptor; didn't find one
@@ -673,6 +675,9 @@ impl fmt::Display for Error {
673675
Error::PubKeyCtxError(ref pk, ref ctx) => {
674676
write!(f, "Pubkey error: {} under {} scriptcontext", pk, ctx)
675677
}
678+
Error::MultiATooManyKeys(k) => {
679+
write!(f, "MultiA too many keys {}", k)
680+
}
676681
}
677682
}
678683
}

src/miniscript/decode.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
//! Functionality to parse a Bitcoin Script into a `Miniscript`
1818
//!
1919
20+
use bitcoin::blockdata::constants::MAX_BLOCK_WEIGHT;
2021
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
2122
use std::marker::PhantomData;
2223
use std::{error, fmt};
@@ -489,6 +490,10 @@ pub fn parse<Ctx: ScriptContext>(
489490
},
490491
// MultiA
491492
Tk::NumEqual, Tk::Num(k) => {
493+
// Check size before allocating keys
494+
if k > MAX_BLOCK_WEIGHT/32 {
495+
return Err(Error::MultiATooManyKeys(MAX_BLOCK_WEIGHT/32))
496+
}
492497
let mut keys = Vec::with_capacity(k as usize); // atleast k capacity
493498
while tokens.peek() == Some(&Tk::CheckSigAdd) {
494499
match_token!(

0 commit comments

Comments
 (0)