Skip to content

Commit cc7459c

Browse files
committed
Fix fuzz crashes (fixes #89)
* fix `thresh` and `multi` descriptors with no arguments * fix roundtrip_concrete roundtrip for "older(03)" * fix roundtrip_descriptor for "c:pk_k" ("pk" alias)
1 parent 96105bb commit cc7459c

File tree

6 files changed

+69
-3
lines changed

6 files changed

+69
-3
lines changed

fuzz/fuzz_targets/roundtrip_descriptor.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ fn do_test(data: &[u8]) {
99
let s = String::from_utf8_lossy(data);
1010
if let Ok(desc) = Descriptor::<DummyKey>::from_str(&s) {
1111
let output = desc.to_string();
12-
assert_eq!(s, output);
12+
let normalize_aliases = s.replace("c:pk_k(", "pk(");
13+
assert_eq!(normalize_aliases, output);
1314
}
1415
}
1516

@@ -58,4 +59,11 @@ mod tests {
5859
extend_vec_from_hex("00", &mut a);
5960
super::do_test(&a);
6061
}
62+
63+
#[test]
64+
fn test_cpkk_alias() {
65+
let mut a = Vec::new();
66+
extend_vec_from_hex("633a706b5f6b2829", &mut a); // c:pk_k()
67+
super::do_test(&a);
68+
}
6169
}

fuzz/fuzz_targets/roundtrip_policy.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,11 @@ mod tests {
6464
extend_vec_from_hex("00", &mut a);
6565
super::do_test(&a);
6666
}
67+
68+
#[test]
69+
fn duplicate_crash_2() {
70+
let mut a = Vec::new();
71+
extend_vec_from_hex("746872657368", &mut a); // thresh
72+
super::do_test(&a);
73+
}
6774
}

src/descriptor/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,4 +896,22 @@ mod tests {
896896

897897
assert_eq!(check, &Instruction::Op(OP_CSV))
898898
}
899+
900+
#[test]
901+
fn empty_multi() {
902+
let descriptor = Descriptor::<bitcoin::PublicKey>::from_str("multi");
903+
assert_eq!(
904+
descriptor.unwrap_err().to_string(),
905+
"unexpected «no arguments given»"
906+
)
907+
}
908+
909+
#[test]
910+
fn empty_thresh() {
911+
let descriptor = Descriptor::<bitcoin::PublicKey>::from_str("thresh");
912+
assert_eq!(
913+
descriptor.unwrap_err().to_string(),
914+
"unexpected «no arguments given»"
915+
)
916+
}
899917
}

src/expression.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ impl<'a> Tree<'a> {
127127

128128
/// Parse a string as a u32, for timelocks or thresholds
129129
pub fn parse_num(s: &str) -> Result<u32, Error> {
130+
if s.len() > 1 {
131+
let ch = s.chars().next().unwrap();
132+
if ch < '1' || ch > '9' {
133+
return Err(Error::Unexpected(
134+
"Number must start with a digit 1-9".to_string(),
135+
));
136+
}
137+
}
130138
u32::from_str(s).map_err(|_| errstr(s))
131139
}
132140

@@ -172,3 +180,19 @@ where
172180
Err(errstr(term.name))
173181
}
174182
}
183+
184+
#[cfg(test)]
185+
mod tests {
186+
187+
use super::parse_num;
188+
189+
#[test]
190+
fn test_parse_num() {
191+
assert!(parse_num("0").is_ok());
192+
assert!(parse_num("00").is_err());
193+
assert!(parse_num("0000").is_err());
194+
assert!(parse_num("06").is_err());
195+
assert!(parse_num("+6").is_err());
196+
assert!(parse_num("-6").is_err());
197+
}
198+
}

src/miniscript/astelem.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,11 @@ where
429429
Ok(expr)
430430
}
431431
("thresh", n) => {
432+
if n == 0 {
433+
return Err(errstr("no arguments given"));
434+
}
432435
let k = expression::terminal(&top.args[0], expression::parse_num)? as usize;
433-
if n == 0 || k > n - 1 {
436+
if k > n - 1 {
434437
return Err(errstr("higher threshold than there are subexpressions"));
435438
}
436439
if n == 1 {
@@ -445,8 +448,11 @@ where
445448
Ok(Terminal::Thresh(k, subs?))
446449
}
447450
("multi", n) => {
451+
if n == 0 {
452+
return Err(errstr("no arguments given"));
453+
}
448454
let k = expression::terminal(&top.args[0], expression::parse_num)? as usize;
449-
if n == 0 || k > n - 1 {
455+
if k > n - 1 {
450456
return Err(errstr("higher threshold than there were keys in multi"));
451457
}
452458

src/policy/semantic.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,9 @@ where
254254
Ok(Policy::Or(subs))
255255
}
256256
("thresh", nsubs) => {
257+
if nsubs == 0 {
258+
return Err(errstr("thresh without args"));
259+
}
257260
if !top.args[0].args.is_empty() {
258261
return Err(errstr(top.args[0].args[0].name));
259262
}

0 commit comments

Comments
 (0)