diff --git a/util/rlp/src/error.rs b/util/rlp/src/error.rs index 6b15ea8a6d2..5113fdc17df 100644 --- a/util/rlp/src/error.rs +++ b/util/rlp/src/error.rs @@ -30,6 +30,8 @@ pub enum DecoderError { RlpInvalidIndirection, /// Declared length is inconsistent with data specified after. RlpInconsistentLengthAndData, + /// Declared length is invalid and results in overflow + RlpInvalidLength, /// Custom rlp decoding error. Custom(&'static str), } diff --git a/util/rlp/src/untrusted_rlp.rs b/util/rlp/src/untrusted_rlp.rs index 16714fe985e..41149606caf 100644 --- a/util/rlp/src/untrusted_rlp.rs +++ b/util/rlp/src/untrusted_rlp.rs @@ -371,7 +371,8 @@ impl<'a> BasicDecoder<'a> { } let len = decode_usize(&bytes[1..begin_of_value])?; - let last_index_of_value = begin_of_value + len; + let last_index_of_value = begin_of_value.checked_add(len) + .ok_or(DecoderError::RlpInvalidLength)?; if bytes.len() < last_index_of_value { return Err(DecoderError::RlpInconsistentLengthAndData); } @@ -385,7 +386,7 @@ impl<'a> BasicDecoder<'a> { #[cfg(test)] mod tests { - use UntrustedRlp; + use {UntrustedRlp, DecoderError}; #[test] fn test_rlp_display() { @@ -394,4 +395,12 @@ mod tests { let rlp = UntrustedRlp::new(&data); assert_eq!(format!("{}", rlp), "[\"0x05\", \"0x010efbef67941f79b2\", \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\", \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"]"); } + + #[test] + fn length_overflow() { + let bs = [0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5]; + let rlp = UntrustedRlp::new(&bs); + let res: Result = rlp.as_val(); + assert_eq!(Err(DecoderError::RlpInvalidLength), res); + } }