From f4ee585eb382eeb7ea1db16458438c637de48349 Mon Sep 17 00:00:00 2001 From: oyvindln Date: Thu, 22 Dec 2022 18:48:13 +0100 Subject: [PATCH] fix(inflate): Reject input with too many litlen codes as per spec/zlib fixes #130 --- miniz_oxide/src/inflate/core.rs | 25 +++++++++++++++++++++---- miniz_oxide/tests/test.rs | 12 ++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/miniz_oxide/src/inflate/core.rs b/miniz_oxide/src/inflate/core.rs index 66424a63..f8ef7338 100644 --- a/miniz_oxide/src/inflate/core.rs +++ b/miniz_oxide/src/inflate/core.rs @@ -261,6 +261,7 @@ impl Default for DecompressorOxide { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[non_exhaustive] enum State { Start = 0, ReadZlibCmf, @@ -292,6 +293,7 @@ enum State { // Failure states. BlockTypeUnexpected, BadCodeSizeSum, + BadDistOrLiteralTableLength, BadTotalSymbols, BadZlibHeader, DistanceOutOfBounds, @@ -307,6 +309,7 @@ impl State { match self { BlockTypeUnexpected => true, BadCodeSizeSum => true, + BadDistOrLiteralTableLength => true, BadTotalSymbols => true, BadZlibHeader => true, DistanceOutOfBounds => true, @@ -1279,7 +1282,18 @@ pub fn decompress( } else { memset(&mut r.tables[HUFFLEN_TABLE].code_size[..], 0); l.counter = 0; - Action::Jump(ReadHufflenTableCodeSize) + // Check that the litlen and distance are within spec. + // litlen table should be <=286 acc to the RFC and + // additionally zlib rejects dist table sizes larger than 30. + // NOTE this the final sizes after adding back predefined values, not + // raw value in the data. + // See miniz_oxide issue #130 and https://github.com/madler/zlib/issues/82. + if r.table_sizes[LITLEN_TABLE] <= 286 && r.table_sizes[DIST_TABLE] <= 30 { + Action::Jump(ReadHufflenTableCodeSize) + } + else { + Action::Jump(BadDistOrLiteralTableLength) + } } }), @@ -1634,7 +1648,8 @@ pub fn decompress( DoneForever => break TINFLStatus::Done, // Anything else indicates failure. - // BadZlibHeader | BadRawLength | BlockTypeUnexpected | DistanceOutOfBounds | + // BadZlibHeader | BadRawLength | BadDistOrLiteralTableLength | BlockTypeUnexpected | + // DistanceOutOfBounds | // BadTotalSymbols | BadCodeSizeDistPrevLookup | BadCodeSizeSum | InvalidLitlen | // InvalidDist | InvalidCodeLen _ => break TINFLStatus::Failed, @@ -1836,18 +1851,20 @@ mod test { // Bad check bits. cr(&[0x78, 0x98], F, State::BadZlibHeader, true); + // Too many code lengths. (From inflate library issues) cr( b"M\xff\xffM*\xad\xad\xad\xad\xad\xad\xad\xcd\xcd\xcdM", F, - State::BadTotalSymbols, + State::BadDistOrLiteralTableLength, false, ); + // Bad CLEN (also from inflate library issues) cr( b"\xdd\xff\xff*M\x94ffffffffff", F, - State::BadTotalSymbols, + State::BadDistOrLiteralTableLength, false, ); diff --git a/miniz_oxide/tests/test.rs b/miniz_oxide/tests/test.rs index e689fb52..043149d2 100644 --- a/miniz_oxide/tests/test.rs +++ b/miniz_oxide/tests/test.rs @@ -209,6 +209,18 @@ fn issue_119_inflate_with_exact_limit() { ); } +#[test] +fn issue_130_reject_invalid_table_sizes() { + let input = get_test_file_data("tests/test_data/issue_130_table_size.bin"); + + + let result = decompress_to_vec_zlib(input.as_slice()); + println!("{:?}", result); + assert!(result.is_err()); + let error = result.unwrap_err(); + assert_eq!(error.status, TINFLStatus::Failed); +} + /* #[test] fn large_file() {