diff --git a/Cargo.toml b/Cargo.toml index 06cd7c4..8608cd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "brotli" -version = "0.3.4" +version = "0.3.5" authors = ["Thomas Pickert "] license = "Apache-2.0" repository = "https://github.com/ende76/brotli-rs" diff --git a/README.md b/README.md index c0592d6..07a5b33 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,11 @@ Compression provides a -struct to wrap a Brotli-compressed stream. A consu ## Changelog +###v0.3.4 -> v0.3.5 +---------------- + +Fixed a case where an invalid insert-and-copy-length-code would produce a panic. (Thanks, [Corey](https://github.com/frewsxcv)!). + ###v0.3.1 -> v0.3.4 ---------------- diff --git a/src/lib.rs b/src/lib.rs index bf7218f..2b8f117 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -306,24 +306,25 @@ enum State { #[derive(Debug, Clone, PartialEq)] enum DecompressorError { - UnexpectedEOF, + CodeLengthsChecksum, + ExpectedEndOfStream, + ExceededExpectedBytes, + InvalidInsertAndCopyLengthCode, + InvalidLengthInStaticDictionary, + InvalidMSkipLen, + InvalidTransformId, NonZeroFillBit, NonZeroReservedBit, NonZeroTrailerBit, NonZeroTrailerNibble, - ExpectedEndOfStream, - InvalidMSkipLen, - ParseErrorInsertAndCopyLength, - ParseErrorInsertLiterals, ParseErrorContextMap, - ParseErrorDistanceCode, - ExceededExpectedBytes, ParseErrorComplexPrefixCodeLengths, + ParseErrorDistanceCode, + ParseErrorInsertAndCopyLength, + ParseErrorInsertLiterals, RingBufferError, RunLengthExceededSizeOfContextMap, - InvalidTransformId, - InvalidLengthInStaticDictionary, - CodeLengthsChecksum, + UnexpectedEOF, } impl Display for DecompressorError { @@ -336,24 +337,25 @@ impl Display for DecompressorError { impl Error for DecompressorError { fn description(&self) -> &str { match *self { - DecompressorError::UnexpectedEOF => "Encountered unexpected EOF", + DecompressorError::CodeLengthsChecksum => "Code length check sum did not add up to 32 in complex prefix code", + DecompressorError::ExpectedEndOfStream => "Expected end-of-stream, but stream did not end", + DecompressorError::ExceededExpectedBytes => "More uncompressed bytes than expected in meta-block", + DecompressorError::InvalidInsertAndCopyLengthCode => "Encountered invalid value for insert-and-copy-length code", + DecompressorError::InvalidLengthInStaticDictionary => "Encountered invalid length in reference to static dictionary", + DecompressorError::InvalidMSkipLen => "Most significant byte of MSKIPLEN was zero", + DecompressorError::InvalidTransformId => "Encountered invalid transform id in reference to static dictionary", DecompressorError::NonZeroFillBit => "Enocuntered non-zero fill bit", DecompressorError::NonZeroReservedBit => "Enocuntered non-zero reserved bit", DecompressorError::NonZeroTrailerBit => "Enocuntered non-zero bit trailing the stream", DecompressorError::NonZeroTrailerNibble => "Enocuntered non-zero nibble trailing", - DecompressorError::ExpectedEndOfStream => "Expected end-of-stream, but stream did not end", - DecompressorError::InvalidMSkipLen => "Most significant byte of MSKIPLEN was zero", - DecompressorError::ParseErrorInsertAndCopyLength => "Error parsing Insert And Copy Length", - DecompressorError::ParseErrorInsertLiterals => "Error parsing Insert Literals", - DecompressorError::ParseErrorDistanceCode => "Error parsing DistanceCode", - DecompressorError::ExceededExpectedBytes => "More uncompressed bytes than expected in meta-block", DecompressorError::ParseErrorContextMap => "Error parsing context map", DecompressorError::ParseErrorComplexPrefixCodeLengths => "Error parsing code lengths for complex prefix code", + DecompressorError::ParseErrorDistanceCode => "Error parsing DistanceCode", + DecompressorError::ParseErrorInsertAndCopyLength => "Error parsing Insert And Copy Length", + DecompressorError::ParseErrorInsertLiterals => "Error parsing Insert Literals", DecompressorError::RingBufferError => "Error accessing distance ring buffer", DecompressorError::RunLengthExceededSizeOfContextMap => "Run length excceeded declared length of context map", - DecompressorError::InvalidTransformId => "Encountered invalid transform id in reference to static dictionary", - DecompressorError::InvalidLengthInStaticDictionary => "Encountered invalid length in reference to static dictionary", - DecompressorError::CodeLengthsChecksum => "Code length check sum did not add up to 32 in complex prefix code", + DecompressorError::UnexpectedEOF => "Encountered unexpected EOF", } } } @@ -1271,7 +1273,7 @@ impl Decompressor { Some(512...575) => (8, 16), Some(576...639) => (16, 8), Some(640...703) => (16, 16), - _ => unreachable!(), + _ => return Err(DecompressorError::InvalidInsertAndCopyLengthCode), }; insert_length_code += 0x07 & (self.meta_block.insert_and_copy_length.unwrap() as u8 >> 3); @@ -2275,24 +2277,7 @@ impl Read for Decompressor { fn read(&mut self, buf: &mut [u8]) -> io::Result { if self.buf.is_empty() { match self.decompress() { - Err(e @ DecompressorError::UnexpectedEOF) | - Err(e @ DecompressorError::NonZeroFillBit) | - Err(e @ DecompressorError::NonZeroReservedBit) | - Err(e @ DecompressorError::NonZeroTrailerBit) | - Err(e @ DecompressorError::NonZeroTrailerNibble) | - Err(e @ DecompressorError::ExpectedEndOfStream) | - Err(e @ DecompressorError::InvalidMSkipLen) | - Err(e @ DecompressorError::ParseErrorInsertAndCopyLength) | - Err(e @ DecompressorError::ParseErrorInsertLiterals) | - Err(e @ DecompressorError::ParseErrorContextMap) | - Err(e @ DecompressorError::ParseErrorDistanceCode) | - Err(e @ DecompressorError::ExceededExpectedBytes) | - Err(e @ DecompressorError::ParseErrorComplexPrefixCodeLengths) | - Err(e @ DecompressorError::RingBufferError) | - Err(e @ DecompressorError::RunLengthExceededSizeOfContextMap) | - Err(e @ DecompressorError::InvalidTransformId) | - Err(e @ DecompressorError::InvalidLengthInStaticDictionary) | - Err(e @ DecompressorError::CodeLengthsChecksum) => return Err(io::Error::new(io::ErrorKind::InvalidData, e.description())), + Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e.description())), Ok(_) => {}, } } diff --git a/src/main.rs b/src/main.rs index 800a92d..550b0e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,9 @@ extern crate brotli; -fn main() { - use std::io::Read; - use brotli::Decompressor; +use std::io::Read; +use brotli::Decompressor; +fn main() { let mut input = vec![]; - let result = Decompressor::new(&b"\xb1".to_vec() as &[u8]).read_to_end(&mut input); - - println!("result = {:?}", result); -} - + let _ = Decompressor::new(&b"\x1b\x30\x30\x30\x24\x30\xe2\xd9\x30\x30".to_vec() as &[u8]).read_to_end(&mut input); +} \ No newline at end of file diff --git a/tests/lib.rs b/tests/lib.rs index 69a637a..e3cfcf5 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -328,7 +328,7 @@ fn should_reject_frewsxcv_00() { #[should_panic(expected = "unexpected EOF")] /// frewsxcv: fuzzer-test /// exposes uncaught panic in read() implementation -/// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/2 +/// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/3 fn should_reject_frewsxcv_01() { use std::io::Read; use brotli::Decompressor; @@ -342,6 +342,24 @@ fn should_reject_frewsxcv_01() { } } +#[test] +#[should_panic(expected = "invalid value for insert-and-copy-length code")] +/// frewsxcv: fuzzer-test +/// exposes panic in "unreachable" branch in insert-and-copy-length decoding +/// found and reported by Corey Farwell – https://github.com/ende76/brotli-rs/issues/4 +fn should_reject_frewsxcv_02() { + use std::io::Read; + use brotli::Decompressor; + + let mut input = vec![]; + let result = Decompressor::new(&b"\x1b\x30\x30\x30\x24\x30\xe2\xd9\x30\x30".to_vec() as &[u8]).read_to_end(&mut input); + + match result { + Err(e) => panic!("{:?}", e), + _ => {}, + } +} + fn inverse_move_to_front_transform(v: &mut[u8]) { let mut mtf: Vec = vec![0; 256]; let v_len = v.len();