From: Matt Corallo Date: Wed, 25 Jul 2018 19:28:25 +0000 (-0400) Subject: Add router_target to fuzzing which fuzzes router msgs + get_route X-Git-Tag: v0.0.12~368^2~1 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=0ce6e397a78e58c85aa4202467523d58b26ef406;p=rust-lightning Add router_target to fuzzing which fuzzes router msgs + get_route --- diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 14610540..22f4bdcc 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -42,6 +42,10 @@ path = "fuzz_targets/channel_target.rs" name = "full_stack_target" path = "fuzz_targets/full_stack_target.rs" +[[bin]] +name = "router_target" +path = "fuzz_targets/router_target.rs" + [[bin]] name = "chanmon_deser_target" path = "fuzz_targets/chanmon_deser_target.rs" diff --git a/fuzz/fuzz_targets/router_target.rs b/fuzz/fuzz_targets/router_target.rs new file mode 100644 index 00000000..13733adb --- /dev/null +++ b/fuzz/fuzz_targets/router_target.rs @@ -0,0 +1,219 @@ +extern crate bitcoin; +extern crate lightning; +extern crate secp256k1; + +use lightning::ln::channelmanager::ChannelDetails; +use lightning::ln::msgs; +use lightning::ln::msgs::{MsgDecodable, RoutingMessageHandler}; +use lightning::ln::router::{Router, RouteHint}; +use lightning::util::reset_rng_state; + +use secp256k1::key::PublicKey; +use secp256k1::Secp256k1; + +#[inline] +pub fn slice_to_be16(v: &[u8]) -> u16 { + ((v[0] as u16) << 8*1) | + ((v[1] as u16) << 8*0) +} + +#[inline] +pub fn slice_to_be32(v: &[u8]) -> u32 { + ((v[0] as u32) << 8*3) | + ((v[1] as u32) << 8*2) | + ((v[2] as u32) << 8*1) | + ((v[3] as u32) << 8*0) +} + +#[inline] +pub fn slice_to_be64(v: &[u8]) -> u64 { + ((v[0] as u64) << 8*7) | + ((v[1] as u64) << 8*6) | + ((v[2] as u64) << 8*5) | + ((v[3] as u64) << 8*4) | + ((v[4] as u64) << 8*3) | + ((v[5] as u64) << 8*2) | + ((v[6] as u64) << 8*1) | + ((v[7] as u64) << 8*0) +} + +#[inline] +pub fn do_test(data: &[u8]) { + reset_rng_state(); + + let mut read_pos = 0; + macro_rules! get_slice_nonadvancing { + ($len: expr) => { + { + if data.len() < read_pos + $len as usize { + return; + } + &data[read_pos..read_pos + $len as usize] + } + } + } + macro_rules! get_slice { + ($len: expr) => { + { + let res = get_slice_nonadvancing!($len); + read_pos += $len; + res + } + } + } + + macro_rules! decode_msg { + ($MsgType: path, $len: expr) => { + match <($MsgType)>::decode(get_slice!($len)) { + Ok(msg) => msg, + Err(e) => match e { + msgs::DecodeError::UnknownRealmByte => return, + msgs::DecodeError::BadPublicKey => return, + msgs::DecodeError::BadSignature => return, + msgs::DecodeError::BadText => return, + msgs::DecodeError::ExtraAddressesPerType => return, + msgs::DecodeError::BadLengthDescriptor => return, + msgs::DecodeError::ShortRead => panic!("We picked the length..."), + } + } + } + } + + macro_rules! decode_msg_with_len16 { + ($MsgType: path, $begin_len: expr, $excess: expr) => { + { + let extra_len = slice_to_be16(&get_slice_nonadvancing!($begin_len as usize + 2)[$begin_len..$begin_len + 2]); + decode_msg!($MsgType, $begin_len as usize + 2 + (extra_len as usize) + $excess) + } + } + } + + let secp_ctx = Secp256k1::new(); + macro_rules! get_pubkey { + () => { + match PublicKey::from_slice(&secp_ctx, get_slice!(33)) { + Ok(key) => key, + Err(_) => return, + } + } + } + + let our_pubkey = get_pubkey!(); + let router = Router::new(our_pubkey.clone()); + + loop { + match get_slice!(1)[0] { + 0 => { + let start_len = slice_to_be16(&get_slice_nonadvancing!(64 + 2)[64..64 + 2]) as usize; + let addr_len = slice_to_be16(&get_slice_nonadvancing!(64+start_len+2 + 74)[64+start_len+2 + 72..64+start_len+2 + 74]); + if addr_len > (37+1)*4 { + return; + } + let _ = router.handle_node_announcement(&decode_msg_with_len16!(msgs::NodeAnnouncement, 64, 288)); + }, + 1 => { + let _ = router.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4)); + }, + 2 => { + let _ = router.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128)); + }, + 3 => { + match get_slice!(1)[0] { + 0 => { + router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)}); + }, + 1 => { + let short_channel_id = slice_to_be64(get_slice!(8)); + router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed {short_channel_id}); + }, + _ => return, + } + }, + 4 => { + let target = get_pubkey!(); + let mut first_hops_vec = Vec::new(); + let first_hops = match get_slice!(1)[0] { + 0 => None, + 1 => { + let count = slice_to_be16(get_slice!(2)); + for _ in 0..count { + first_hops_vec.push(ChannelDetails { + channel_id: [0; 32], + short_channel_id: Some(slice_to_be64(get_slice!(8))), + remote_network_id: get_pubkey!(), + channel_value_satoshis: slice_to_be64(get_slice!(8)), + user_id: 0, + }); + } + Some(&first_hops_vec[..]) + }, + _ => return, + }; + let mut last_hops_vec = Vec::new(); + let last_hops = { + let count = slice_to_be16(get_slice!(2)); + for _ in 0..count { + last_hops_vec.push(RouteHint { + src_node_id: get_pubkey!(), + short_channel_id: slice_to_be64(get_slice!(8)), + fee_base_msat: slice_to_be64(get_slice!(8)), + fee_proportional_millionths: slice_to_be32(get_slice!(4)), + cltv_expiry_delta: slice_to_be16(get_slice!(2)), + htlc_minimum_msat: slice_to_be64(get_slice!(8)), + }); + } + &last_hops_vec[..] + }; + let _ = router.get_route(&target, first_hops, last_hops, slice_to_be64(get_slice!(8)), slice_to_be32(get_slice!(4))); + }, + _ => return, + } + } +} + +#[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| { + 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); + } +}