Skip to content

Commit

Permalink
FIX: properly handled error for invalid insert-and-copy-length code #4
Browse files Browse the repository at this point in the history
  • Loading branch information
ende76 committed Oct 26, 2015
1 parent 52713b6 commit d489de7
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 49 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "brotli"
version = "0.3.4"
version = "0.3.5"
authors = ["Thomas Pickert <ende.mail@web.de>"]
license = "Apache-2.0"
repository = "https://github.com/ende76/brotli-rs"
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ Compression provides a <Read>-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
----------------

Expand Down
63 changes: 24 additions & 39 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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",
}
}
}
Expand Down Expand Up @@ -1271,7 +1273,7 @@ impl<R: Read> Decompressor<R> {
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);
Expand Down Expand Up @@ -2275,24 +2277,7 @@ impl<R: Read> Read for Decompressor<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
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(_) => {},
}
}
Expand Down
13 changes: 5 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -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);
}
20 changes: 19 additions & 1 deletion tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<u8> = vec![0; 256];
let v_len = v.len();
Expand Down

0 comments on commit d489de7

Please sign in to comment.