diff --git a/eth2/utils/ssz/src/decode.rs b/eth2/utils/ssz/src/decode.rs index fc1198964..4db68e27f 100644 --- a/eth2/utils/ssz/src/decode.rs +++ b/eth2/utils/ssz/src/decode.rs @@ -101,7 +101,7 @@ impl<'a> SszDecoderBuilder<'a> { Ok(()) } - fn apply_offsets(&mut self) -> Result<(), DecodeError> { + fn finalize(&mut self) -> Result<(), DecodeError> { if !self.offsets.is_empty() { // Check to ensure the first offset points to the byte immediately following the // fixed-length bytes. @@ -124,13 +124,21 @@ impl<'a> SszDecoderBuilder<'a> { if let Some(last) = self.offsets.last() { self.items[last.position] = &self.bytes[last.offset..] } + } else { + // If the container is fixed-length, ensure there are no excess bytes. + if self.items_index != self.bytes.len() { + return Err(DecodeError::InvalidByteLength { + len: self.bytes.len(), + expected: self.items_index, + }); + } } Ok(()) } pub fn build(mut self) -> Result, DecodeError> { - self.apply_offsets()?; + self.finalize()?; Ok(SszDecoder { items: self.items }) } diff --git a/eth2/utils/ssz/tests/tests.rs b/eth2/utils/ssz/tests/tests.rs index 5a880492d..94632203b 100644 --- a/eth2/utils/ssz/tests/tests.rs +++ b/eth2/utils/ssz/tests/tests.rs @@ -106,6 +106,22 @@ mod round_trip { } } + #[test] + fn fixed_len_excess_bytes() { + let fixed = FixedLen { a: 1, b: 2, c: 3 }; + + let mut bytes = fixed.as_ssz_bytes(); + bytes.append(&mut vec![0]); + + assert_eq!( + FixedLen::from_ssz_bytes(&bytes), + Err(DecodeError::InvalidByteLength { + len: 15, + expected: 14, + }) + ); + } + #[test] fn vec_of_fixed_len_struct() { let items: Vec = vec![ @@ -138,6 +154,22 @@ mod round_trip { ); } + #[test] + fn variable_len_excess_bytes() { + let variable = VariableLen { + a: 1, + b: vec![2], + c: 3, + }; + + let mut bytes = variable.as_ssz_bytes(); + bytes.append(&mut vec![0]); + + // The error message triggered is not so helpful, it's caught by a side-effect. Just + // checking there is _some_ error is fine. + assert!(VariableLen::from_ssz_bytes(&bytes).is_err()); + } + #[test] fn first_offset_skips_byte() { let bytes = vec![