From 1b8504a3f3f46736abb886121718bde07321f2b2 Mon Sep 17 00:00:00 2001 From: Yuntai Kyong Date: Sat, 1 Sep 2018 16:18:56 +0900 Subject: [PATCH] Implement Writer/Reader with additional variants in DecodeError --- fuzz/fuzz_targets/channel_target.rs | 4 + fuzz/fuzz_targets/router_target.rs | 2 + src/ln/msgs.rs | 16 ++ src/ln/peer_handler.rs | 3 + src/util/mod.rs | 7 + src/util/ser.rs | 327 ++++++++++++++++++++++++++++ 6 files changed, 359 insertions(+) create mode 100644 src/util/ser.rs diff --git a/fuzz/fuzz_targets/channel_target.rs b/fuzz/fuzz_targets/channel_target.rs index 7b3b7df1..d2a4fbca 100644 --- a/fuzz/fuzz_targets/channel_target.rs +++ b/fuzz/fuzz_targets/channel_target.rs @@ -131,6 +131,8 @@ pub fn do_test(data: &[u8]) { msgs::DecodeError::ExtraAddressesPerType => return, msgs::DecodeError::BadLengthDescriptor => return, msgs::DecodeError::ShortRead => panic!("We picked the length..."), + msgs::DecodeError::InvalidValue => panic!("Writeable not used yet..."), + msgs::DecodeError::Io(_) => panic!("Writeable not used yet..."), } } } @@ -154,6 +156,8 @@ pub fn do_test(data: &[u8]) { msgs::DecodeError::ExtraAddressesPerType => return, msgs::DecodeError::BadLengthDescriptor => return, msgs::DecodeError::ShortRead => panic!("We picked the length..."), + msgs::DecodeError::InvalidValue => panic!("Writeable not used yet..."), + msgs::DecodeError::Io(_) => panic!("Writeable not used yet..."), } } } diff --git a/fuzz/fuzz_targets/router_target.rs b/fuzz/fuzz_targets/router_target.rs index 6476f812..4669f1f8 100644 --- a/fuzz/fuzz_targets/router_target.rs +++ b/fuzz/fuzz_targets/router_target.rs @@ -131,6 +131,8 @@ pub fn do_test(data: &[u8]) { msgs::DecodeError::ExtraAddressesPerType => return, msgs::DecodeError::BadLengthDescriptor => return, msgs::DecodeError::ShortRead => panic!("We picked the length..."), + msgs::DecodeError::InvalidValue => panic!("Writeable not used yet..."), + msgs::DecodeError::Io(_) => panic!("Writeable not used yet..."), } } } diff --git a/src/ln/msgs.rs b/src/ln/msgs.rs index 1d0ea1c6..795d1173 100644 --- a/src/ln/msgs.rs +++ b/src/ln/msgs.rs @@ -43,6 +43,10 @@ pub enum DecodeError { /// A length descriptor in the packet didn't describe the later data correctly /// (currently only generated in node_announcement) BadLengthDescriptor, + /// Error from std::io + Io(::std::io::Error), + /// Invalid value found when decoding + InvalidValue, } pub trait MsgDecodable: Sized { fn decode(v: &[u8]) -> Result; @@ -519,6 +523,8 @@ impl Error for DecodeError { DecodeError::ShortRead => "Packet extended beyond the provided bytes", DecodeError::ExtraAddressesPerType => "More than one address of a single type", DecodeError::BadLengthDescriptor => "A length descriptor in the packet didn't describe the later data correctly", + DecodeError::Io(ref e) => e.description(), + DecodeError::InvalidValue => "Invalid value in the bytes", } } } @@ -534,6 +540,16 @@ impl fmt::Debug for HandleError { } } +impl From<::std::io::Error> for DecodeError { + fn from(e: ::std::io::Error) -> Self { + if e.kind() == ::std::io::ErrorKind::UnexpectedEof { + DecodeError::ShortRead + } else { + DecodeError::Io(e) + } + } +} + macro_rules! secp_pubkey { ( $ctx: expr, $slice: expr ) => { match PublicKey::from_slice($ctx, $slice) { diff --git a/src/ln/peer_handler.rs b/src/ln/peer_handler.rs index 8a422885..5d5641bb 100644 --- a/src/ln/peer_handler.rs +++ b/src/ln/peer_handler.rs @@ -363,6 +363,9 @@ impl PeerManager { continue; }, msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError{ no_connection_possible: false }), + msgs::DecodeError::Io(_) => return Err(PeerHandleError{ no_connection_possible: false }), + msgs::DecodeError::InvalidValue => return Err(PeerHandleError{ no_connection_possible: false }), + msgs::DecodeError::InvalidLength => return Err(PeerHandleError{ no_connection_possible: false }), } } }; diff --git a/src/util/mod.rs b/src/util/mod.rs index 571a4dbe..30882585 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -21,4 +21,11 @@ pub(crate) mod test_utils; #[macro_use] pub(crate) mod macro_logger; +#[cfg(feature = "fuzztarget")] +#[macro_use] +pub mod ser; +#[cfg(not(feature = "fuzztarget"))] +#[macro_use] +pub(crate) mod ser; + pub mod logger; diff --git a/src/util/ser.rs b/src/util/ser.rs new file mode 100644 index 00000000..0a247d41 --- /dev/null +++ b/src/util/ser.rs @@ -0,0 +1,327 @@ +use std::result::Result; +use std::io::{Read, Write}; +use std::collections::HashMap; +use std::hash::Hash; +use std::mem; + +use secp256k1::{Secp256k1, Signature}; +use secp256k1::key::PublicKey; +use bitcoin::util::hash::Sha256dHash; +use bitcoin::blockdata::script::Script; +use std::marker::Sized; +use ln::msgs::DecodeError; + +use util::byte_utils::{be64_to_array, be32_to_array, be16_to_array, slice_to_be16, slice_to_be32, slice_to_be64}; + +const MAX_BUF_SIZE: usize = 16 * 1024; + +pub struct Writer { writer: W } +pub struct Reader { reader: R } + +pub trait Writeable { + fn write(&self, writer: &mut Writer) -> Result<(), DecodeError>; +} + +pub trait Readable + where Self: Sized, + R: Read +{ + fn read(reader: &mut Reader) -> Result; +} + +impl Writer { + pub fn new(writer: W) -> Writer { + return Writer { writer } + } + pub fn into_inner(self) -> W { self.writer } + pub fn get_ref(&self) -> &W { &self.writer } + fn write_u64(&mut self, v: u64) -> Result<(), DecodeError> { + Ok(self.writer.write_all(&be64_to_array(v))?) + } + fn write_u32(&mut self, v: u32) -> Result<(), DecodeError> { + Ok(self.writer.write_all(&be32_to_array(v))?) + } + fn write_u16(&mut self, v: u16) -> Result<(), DecodeError> { + Ok(self.writer.write_all(&be16_to_array(v))?) + } + fn write_u8(&mut self, v: u8) -> Result<(), DecodeError> { + Ok(self.writer.write_all(&[v])?) + } + fn write_bool(&mut self, v: bool) -> Result<(), DecodeError> { + Ok(self.writer.write_all(&[if v {1} else {0}])?) + } + pub fn write_all(&mut self, v: &[u8]) -> Result<(), DecodeError> { + Ok(self.writer.write_all(v)?) + } +} + +impl Reader { + pub fn new(reader: R) -> Reader { + return Reader { reader } + } + pub fn into_inner(self) -> R { self.reader } + pub fn get_ref(&self) -> &R { &self.reader } + + fn read_u64(&mut self) -> Result { + let mut buf = [0; 8]; + self.reader.read_exact(&mut buf)?; + Ok(slice_to_be64(&buf)) + } + + fn read_u32(&mut self) -> Result { + let mut buf = [0; 4]; + self.reader.read_exact(&mut buf)?; + Ok(slice_to_be32(&buf)) + } + + fn read_u16(&mut self) -> Result { + let mut buf = [0; 2]; + self.reader.read_exact(&mut buf)?; + Ok(slice_to_be16(&buf)) + } + + fn read_u8(&mut self) -> Result { + let mut buf = [0; 1]; + self.reader.read_exact(&mut buf)?; + Ok(buf[0]) + } + fn read_bool(&mut self) -> Result { + let mut buf = [0; 1]; + self.reader.read_exact(&mut buf)?; + if buf[0] != 0 && buf[0] != 1 { + return Err(DecodeError::InvalidValue); + } + Ok(buf[0] == 1) + } + pub fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), DecodeError> { + Ok(self.reader.read_exact(buf)?) + } + pub fn read_to_end(&mut self, buf: &mut Vec) -> Result { + Ok(self.reader.read_to_end(buf)?) + } +} + +macro_rules! impl_writeable_primitive { + ($val_type:ty, $meth_write:ident, $meth_read:ident) => { + impl Writeable for $val_type { + #[inline] + fn write(&self, writer: &mut Writer) -> Result<(), DecodeError> { + writer.$meth_write(*self) + } + } + impl Readable for $val_type { + #[inline] + fn read(reader: &mut Reader) -> Result<$val_type, DecodeError> { + reader.$meth_read() + } + } + } +} + +impl_writeable_primitive!(u64, write_u64, read_u64); +impl_writeable_primitive!(u32, write_u32, read_u32); +impl_writeable_primitive!(u16, write_u16, read_u16); +impl_writeable_primitive!(u8, write_u8, read_u8); +impl_writeable_primitive!(bool, write_bool, read_bool); + +// u8 arrays +macro_rules! impl_array { + ( $size:expr ) => ( + impl Writeable for [u8; $size] + where W: Write + { + #[inline] + fn write(&self, w: &mut Writer) -> Result<(), DecodeError> { + w.write_all(self)?; + Ok(()) + } + } + + impl Readable for [u8; $size] + where R: Read + { + #[inline] + fn read(r: &mut Reader) -> Result { + let mut buf = [0u8; $size]; + r.read_exact(&mut buf)?; + Ok(buf) + } + } + ); +} + +//TODO: performance issue with [u8; size] with impl_array!() +impl_array!(32); // for channel id & hmac +impl_array!(33); // for PublicKey +impl_array!(64); // for Signature +impl_array!(1300); // for OnionPacket.hop_data + +// HashMap +impl Writeable for HashMap + where W: Write, + K: Writeable + Eq + Hash, + V: Writeable +{ + #[inline] + fn write(&self, w: &mut Writer) -> Result<(), DecodeError> { + (self.len() as u16).write(w)?; + for (key, value) in self.iter() { + key.write(w)?; + value.write(w)?; + } + Ok(()) + } +} + +impl Readable for HashMap + where R: Read, + K: Readable + Eq + Hash, + V: Readable +{ + #[inline] + fn read(r: &mut Reader) -> Result { + let len: u16 = Readable::read(r)?; + let mut ret = HashMap::with_capacity(len as usize); + for _ in 0..len { + ret.insert(K::read(r)?, V::read(r)?); + } + Ok(ret) + } +} + +// Vectors +impl> Writeable for Vec { + #[inline] + fn write(&self, w: &mut Writer) -> Result<(), DecodeError> { + let byte_size = (self.len() as usize) + .checked_mul(mem::size_of::()) + .ok_or(DecodeError::BadLengthDescriptor)?; + if byte_size > MAX_BUF_SIZE { + return Err(DecodeError::BadLengthDescriptor); + } + (self.len() as u16).write(w)?; + // performance with Vec + for e in self.iter() { + e.write(w)?; + } + Ok(()) + } +} + +impl> Readable for Vec { + #[inline] + fn read(r: &mut Reader) -> Result { + let len: u16 = Readable::read(r)?; + let byte_size = (len as usize) + .checked_mul(mem::size_of::()) + .ok_or(DecodeError::BadLengthDescriptor)?; + if byte_size > MAX_BUF_SIZE { + return Err(DecodeError::BadLengthDescriptor); + } + let mut ret = Vec::with_capacity(len as usize); + for _ in 0..len { ret.push(T::read(r)?); } + Ok(ret) + } +} + +impl Writeable for Script { + fn write(&self, w: &mut Writer) -> Result<(), DecodeError> { + self.to_bytes().to_vec().write(w) + } +} + +impl Readable for Script { + fn read(r: &mut Reader) -> Result { + let len = >::read(r)? as usize; + let mut buf = vec![0; len]; + r.read_exact(&mut buf)?; + Ok(Script::from(buf)) + } +} + +impl Writeable for Option