Skip to content

Commit 6438f10

Browse files
committed
Improve Miniscript robustness
1 parent 3610c1d commit 6438f10

File tree

4 files changed

+39
-2
lines changed

4 files changed

+39
-2
lines changed

src/expression.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use std::str::FromStr;
2020
use errstr;
2121
use Error;
2222

23+
use MAX_RECURSION_DEPTH;
24+
2325
#[derive(Debug)]
2426
/// A token of the form `x(...)` or `x`
2527
pub struct Tree<'a> {
@@ -34,7 +36,14 @@ pub trait FromTree: Sized {
3436
}
3537

3638
impl<'a> Tree<'a> {
37-
fn from_slice(mut sl: &'a str) -> Result<(Tree<'a>, &'a str), Error> {
39+
fn from_slice(sl: &'a str) -> Result<(Tree<'a>, &'a str), Error> {
40+
Self::from_slice_helper(sl, 0u32)
41+
}
42+
43+
fn from_slice_helper(mut sl: &'a str, depth: u32) -> Result<(Tree<'a>, &'a str), Error> {
44+
if depth >= MAX_RECURSION_DEPTH {
45+
return Err(Error::MaxRecursiveDepthExceeded);
46+
}
3847
enum Found {
3948
Nothing,
4049
Lparen(usize),
@@ -87,7 +96,7 @@ impl<'a> Tree<'a> {
8796

8897
sl = &sl[n + 1..];
8998
loop {
90-
let (arg, new_sl) = Tree::from_slice(sl)?;
99+
let (arg, new_sl) = Tree::from_slice_helper(sl, depth + 1)?;
91100
ret.args.push(arg);
92101

93102
if new_sl.is_empty() {

src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,10 @@ pub enum Error {
331331
///Incorrect Script pubkey Hash for the descriptor. This is used for both
332332
/// `Sh` and `Wsh` descriptors
333333
IncorrectScriptHash,
334+
/// Recursion depth exceeded when parsing policy/miniscript from string
335+
MaxRecursiveDepthExceeded,
336+
/// Recursion depth exceeded when parsing policy/miniscript from string
337+
ScriptSizeTooLarge,
334338
}
335339

336340
#[doc(hidden)]
@@ -361,6 +365,11 @@ impl error::Error for Error {
361365
}
362366
}
363367

368+
// https://github.com/sipa/miniscript/pull/5 for discussion on this number
369+
const MAX_RECURSION_DEPTH: u32 = 402;
370+
// https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
371+
const MAX_SCRIPT_SIZE: u32 = 10000;
372+
364373
impl fmt::Display for Error {
365374
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
366375
match *self {
@@ -413,6 +422,16 @@ impl fmt::Display for Error {
413422
Error::IncorrectPubkeyHash => {
414423
f.write_str("Incorrect pubkey hash for given descriptor pkh/wpkh")
415424
}
425+
Error::MaxRecursiveDepthExceeded => write!(
426+
f,
427+
"Recusive depth over {} not permitted",
428+
MAX_RECURSION_DEPTH
429+
),
430+
Error::ScriptSizeTooLarge => write!(
431+
f,
432+
"Standardness rules imply bitcoin than {} bytes",
433+
MAX_SCRIPT_SIZE
434+
),
416435
}
417436
}
418437
}

src/miniscript/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ impl<Pk: MiniscriptKey> Miniscript<Pk> {
128128
impl Miniscript<bitcoin::PublicKey> {
129129
/// Attempt to parse a script into a Miniscript representation
130130
pub fn parse(script: &script::Script) -> Result<Miniscript<bitcoin::PublicKey>, Error> {
131+
// Transactions more than 100Kb are non-standard
132+
if script.len() > 10000 {}
131133
let tokens = lex(script)?;
132134
let mut iter = TokenIter::new(tokens);
133135

0 commit comments

Comments
 (0)