From 236d350f13878798f7726b515fa618e265514cba Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 8 Jan 2022 21:54:04 +0000 Subject: [PATCH] Fix overflow error when deserializing invalid Duration (#465) * Fix overflow error when deserializing invalid Duration * Use unwrap_err instead of match in test --- src/de/impls.rs | 8 ++++++-- src/error.rs | 10 ++++++++++ tests/basic_types.rs | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/de/impls.rs b/src/de/impls.rs index 4bd5b64..83cfab2 100644 --- a/src/de/impls.rs +++ b/src/de/impls.rs @@ -548,8 +548,12 @@ where impl Decode for Duration { fn decode(mut decoder: D) -> Result { - let secs = Decode::decode(&mut decoder)?; - let nanos = Decode::decode(&mut decoder)?; + const NANOS_PER_SEC: u64 = 1_000_000_000; + let secs: u64 = Decode::decode(&mut decoder)?; + let nanos: u32 = Decode::decode(&mut decoder)?; + if secs.checked_add(u64::from(nanos) / NANOS_PER_SEC).is_none() { + return Err(DecodeError::InvalidDuration { secs, nanos }); + } Ok(Duration::new(secs, nanos)) } } diff --git a/src/error.rs b/src/error.rs index 70465c0..db8a952 100644 --- a/src/error.rs +++ b/src/error.rs @@ -122,6 +122,16 @@ pub enum DecodeError { type_name: &'static str, }, + /// The decoder tried to decode a Duration and overflowed the number of seconds. + InvalidDuration { + /// The number of seconds in the duration. + secs: u64, + + /// The number of nanoseconds in the duration, which when converted to seconds and added to + /// `secs`, overflows a `u64`. + nanos: u32, + }, + /// The decoder tried to decode a `CStr` or `CString`, but the incoming data contained a 0 byte #[cfg(feature = "std")] CStrNulError { diff --git a/tests/basic_types.rs b/tests/basic_types.rs index 46d4c23..bc29ff3 100644 --- a/tests/basic_types.rs +++ b/tests/basic_types.rs @@ -219,3 +219,41 @@ fn test_array() { assert_eq!(input, output); assert_eq!(len, 10); } + +#[test] +fn test_duration_out_of_range() { + let mut input = [0u8; 14]; + + bincode::encode_into_slice(&(u64::MAX, u32::MAX), &mut input, Configuration::standard()) + .unwrap(); + + let result: Result<(std::time::Duration, usize), _> = + bincode::decode_from_slice(&mut input, Configuration::standard()); + + assert_eq!( + result.unwrap_err(), + bincode::error::DecodeError::InvalidDuration { + secs: u64::MAX, + nanos: u32::MAX + } + ); +} + +#[test] +fn test_duration_wrapping() { + let mut input = [0u8; 14]; + + bincode::encode_into_slice( + &(u64::MAX - 4, u32::MAX), + &mut input, + Configuration::standard(), + ) + .unwrap(); + + let (result, _): (std::time::Duration, _) = + bincode::decode_from_slice(&mut input, Configuration::standard()).unwrap(); + + assert_eq!(result.as_secs(), u64::MAX); + + assert_eq!(result.subsec_nanos(), 294967295); +}