diff --git a/src/message/binary.rs b/src/message/binary.rs index 5ab9137..4f1c549 100644 --- a/src/message/binary.rs +++ b/src/message/binary.rs @@ -9,6 +9,25 @@ use bytes::{ Buf, }; +macro_rules! try_from { + (ref $into:ty, $from:expr $(; $fmt:literal)?) => { + { + let from = &$from; + #[inline] fn _type_name_of_val(_: &T) -> &'static str + { + ::std::any::type_name::() + } + <$into>::try_from(*from).wrap_err(eyre!("Failed to convert type")) + .with_section(|| ::std::any::type_name::<$into>().header("New type")) + .with_section(|| _type_name_of_val(from).header("Old type")) + .with_section(|| from.to_string().header("Value was")) + } + }; +} + +/// Check bit written/read from binary streams to check basic integrity. +pub const MESSAGE_HEADER_CHECK: [u8; 4] = (0xc0ffee00u32).to_be_bytes(); + impl SerializedMessage { /// Write this message to a buffer @@ -41,15 +60,22 @@ impl SerializedMessage (: $ser:expr) => { { let mut v = StackVec::new(); - serde_cbor::to_writer(&mut v, $ser)?; - buffer.put_u64(v.len().try_into()?); + #[inline] fn _type_name_of_val(_: &T) -> &'static str + { + ::std::any::type_name::() + } + let ser = $ser; + serde_cbor::to_writer(&mut v, $ser) + .wrap_err(eyre!("Failed to serialise value to temporary buffer")) + .with_section(|| _type_name_of_val(ser).header("Type was"))?; + buffer.put_u64(try_from!(ref u64, v.len())?); write!(&v[..]); } }; } - + write!(MESSAGE_HEADER_CHECK); write!(: &self.header); - buffer.put_u64(self.data.len().try_into()?); + buffer.put_u64(try_from!(ref u64, self.data.len())?); write!(self.data); write!(self.hash); write!(? self.enc_key); @@ -93,21 +119,21 @@ impl SerializedMessage Some(def) }, x => { - return Err(eyre!("Invalid optional-set bit: {}", x)); + return Err(eyre!("Invalid optional-set bit (should be 0 or 1)").with_section(|| x.header("Value was"))); } } } }; (: $ser:ty) => { { - let len = usize::try_from(bytes.get_u64())?; + let len = try_from!(ref usize, bytes.get_u64())?; if len > MAX_ALLOC_SIZE { return Err(eyre!("Invalid length read: {}", len) .with_section(|| format!("Max length read: {}", MAX_ALLOC_SIZE))) } alloc_local_bytes(len, |de| { read!(&mut de[..]); - serde_cbor::from_slice::<$ser>(&de[..]).wrap_err(eyre!("Failed to deserialise {} from reader", std::any::type_name::<$ser>())) + serde_cbor::from_slice::<$ser>(&de[..]).wrap_err(eyre!("Failed to deserialise CBOR from reader")).with_section(|| std::any::type_name::<$ser>().header("Type to deserialise was")) })? } @@ -120,13 +146,22 @@ impl SerializedMessage } } } - + let mut check = [0u8; MESSAGE_HEADER_CHECK.len()]; + read!(&mut check[..]); + if check != MESSAGE_HEADER_CHECK { + return Err(eyre!("Invalid check bit for message header")) + .with_section(|| u32::from_be_bytes(check).header("Expected")) + .with_section(|| u32::from_be_bytes(MESSAGE_HEADER_CHECK).header("Got")); + } + let header = read!(: SerHeader); - let data_len = usize::try_from(bytes.get_u64())?; + let data_len = try_from!(ref usize, bytes.get_u64())?; let mut data = Vec::with_capacity(std::cmp::min(data_len, MAX_ALLOC_SIZE)); //XXX: Redesign so we don't allocate OR try to read massive buffers by accident on corrupted/malformed messages read!(&mut data, data_len); if data.len()!=data_len { - return Err(eyre!("Failed to read {} bytes from buffer (got {})", data_len, data.len())); + return Err(eyre!("Failed to read body bytes from buffer")) + .with_section(|| format!("{} bytes", data_len).header("Tried to read")) + .with_section(|| format!("{} bytes", data.len()).header("Read only")); } let mut hash = sha256::Sha256Hash::default(); read!(&mut hash);