From a15d61947142d11094d0cb948d28f7c0033fd567 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 29 May 2021 16:21:43 +0100 Subject: [PATCH 1/9] Fix OOM in Jpeg decoding buffer allocation --- src/decoder/mod.rs | 8 ++++++++ tests/decode_images.rs | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 1f5c321..dc05d37 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1382,6 +1382,14 @@ impl Decoder { )); } + if offsets[0] as usize > self.limits.intermediate_buffer_size + || bytes + .iter() + .any(|&x| x as usize > self.limits.intermediate_buffer_size) + { + return Err(TiffError::LimitsExceeded); + } + let mut res_img = Vec::with_capacity(offsets[0] as usize); for (idx, offset) in offsets.iter().enumerate() { diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 59bcca0..d2e8543 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -385,3 +385,22 @@ fn test_stripped_image_overflow() { unexpected => panic!("Unexpected error {}", unexpected), } } + +#[test] +fn oom() { + let image = [ + 73, 73, 42, 0, 8, 0, 0, 0, 8, 0, 0, 1, 4, 0, 1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 40, 1, 0, 0, + 0, 158, 0, 0, 251, 3, 1, 3, 0, 1, 0, 0, 0, 7, 0, 0, 0, 6, 1, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, + 17, 1, 4, 0, 1, 0, 0, 0, 3, 77, 0, 0, 1, 1, 3, 0, 1, 0, 0, 0, 3, 128, 0, 0, 22, 1, 4, 0, 1, + 0, 0, 0, 40, 0, 0, 0, 23, 1, 4, 0, 1, 0, 0, 0, 178, 48, 178, 178, 178, 178, 162, 178, + ]; + + let mut decoder = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap(); + + let err = decoder.read_image().unwrap_err(); + + match err { + tiff::TiffError::LimitsExceeded => {} + unexpected => panic!("Unexpected error {}", unexpected), + } +} From 5b7814c994e9081e51be6511cebba2cf98ececfa Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 29 May 2021 16:47:38 +0100 Subject: [PATCH 2/9] Check for OOM when creating LZWReader --- src/decoder/mod.rs | 21 +++++++++++++-------- tests/decode_images.rs | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index dc05d37..12a11e5 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1116,6 +1116,7 @@ impl Decoder { length, buffer.len(), buffer.byte_len(), + self.limits.intermediate_buffer_size, )?; // Read into output buffer. @@ -1180,6 +1181,7 @@ impl Decoder { compressed_length, tile_samples, byte_len, + self.limits.intermediate_buffer_size, )?; for row in 0..(tile_length - padding_down) { @@ -1224,17 +1226,20 @@ impl Decoder { compressed_length: u64, samples: usize, // Expected chunk length in samples byte_len: usize, // Byte length of the samples in result buffer + intermediate_buffer_size: usize, ) -> TiffResult> { Ok(match compression_method { CompressionMethod::None => Box::new(reader), - CompressionMethod::LZW => Box::new( - LZWReader::new( - reader, - usize::try_from(compressed_length)?, - samples * byte_len, - )? - .1, - ), + CompressionMethod::LZW => { + let clen = usize::try_from(compressed_length)?; + + if samples * byte_len > intermediate_buffer_size || clen > intermediate_buffer_size + { + return Err(TiffError::LimitsExceeded); + } + + Box::new(LZWReader::new(reader, clen, samples * byte_len)?.1) + } CompressionMethod::PackBits => { Box::new(PackBitsReader::new(reader, usize::try_from(compressed_length)?)?.1) } diff --git a/tests/decode_images.rs b/tests/decode_images.rs index d2e8543..33dc9b5 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -404,3 +404,22 @@ fn oom() { unexpected => panic!("Unexpected error {}", unexpected), } } + +#[test] +fn oom_2() { + let image = [ + 73, 73, 42, 0, 8, 0, 0, 0, 8, 0, 0, 1, 4, 0, 1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 40, 1, 0, 0, + 0, 158, 0, 0, 251, 3, 1, 3, 0, 1, 0, 0, 0, 5, 0, 0, 0, 6, 1, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 17, 1, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 0, 1, 0, 0, 0, 3, 128, 0, 0, 22, 1, 4, 0, 1, + 0, 0, 0, 40, 0, 0, 0, 23, 1, 4, 0, 1, 0, 0, 0, 48, 178, 178, 178, 0, 1, 0, 13, 13, + ]; + + let mut decoder = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap(); + + let err = decoder.read_image().unwrap_err(); + + match err { + tiff::TiffError::LimitsExceeded => {} + unexpected => panic!("Unexpected error {}", unexpected), + } +} From 03b6ed413b8d2a09ac855d2de2b9eb6aa202356a Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 29 May 2021 17:04:26 +0100 Subject: [PATCH 3/9] Fix out of bounds subtraction with invalid JPEG table --- src/decoder/mod.rs | 12 +++++++++++- src/decoder/stream.rs | 6 ++++++ tests/decode_images.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 12a11e5..61af67e 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1372,7 +1372,17 @@ impl Decoder { let jpeg_tables: Option> = match self.find_tag(Tag::JPEGTables) { Ok(None) => None, - Ok(_) => Some(self.get_tag_u8_vec(Tag::JPEGTables)?), + Ok(_) => { + let vec = self.get_tag_u8_vec(Tag::JPEGTables)?; + + if vec.len() < 2 { + return Err(TiffError::FormatError( + TiffFormatError::InvalidTagValueType(Tag::JPEGTables), + )); + } + + Some(vec) + } Err(e) => return Err(e), }; diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 294a1c8..c73e08c 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -225,6 +225,12 @@ impl JpegReader { match jpeg_tables { Some(tables) => { + assert!( + tables.len() >= 2, + "jpeg_tables, if given, must be at least 2 bytes long. Got {:?}", + tables + ); + let mut jpeg_data = tables.clone(); let truncated_length = jpeg_data.len() - 2; jpeg_data.truncate(truncated_length); diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 33dc9b5..e13273b 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -423,3 +423,29 @@ fn oom_2() { unexpected => panic!("Unexpected error {}", unexpected), } } + +#[test] +fn invalid_jpeg_tag() { + use tiff::tags; + use tiff::{TiffError, TiffFormatError}; + + let image = [ + 73, 73, 42, 0, 8, 0, 0, 0, 15, 0, 0, 254, 44, 1, 0, 0, 0, 0, 0, 32, 0, 0, 0, 1, 4, 0, 1, 0, + 0, 0, 0, 1, 0, 0, 91, 1, 1, 0, 0, 0, 0, 0, 242, 4, 0, 0, 0, 22, 0, 56, 77, 0, 77, 1, 0, 0, + 73, 42, 0, 1, 4, 0, 1, 0, 0, 0, 4, 0, 8, 0, 0, 1, 4, 0, 1, 0, 0, 0, 158, 0, 0, 251, 3, 1, + 3, 0, 1, 0, 0, 0, 7, 0, 0, 0, 6, 1, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, 17, 1, 4, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 3, 0, 1, 0, 0, 0, 0, 0, 0, 4, 61, 1, 18, 0, 1, 0, 0, 0, 202, 0, 0, 0, 17, + 1, 100, 0, 129, 0, 0, 0, 0, 0, 0, 0, 232, 254, 252, 255, 254, 255, 255, 255, 1, 29, 0, 0, + 22, 1, 3, 0, 1, 0, 0, 0, 16, 0, 0, 0, 23, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 123, 73, 254, 0, + 73, + ]; + + let mut decoder = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap(); + + let err = decoder.read_image().unwrap_err(); + + match err { + TiffError::FormatError(TiffFormatError::InvalidTagValueType(tags::Tag::JPEGTables)) => {} + unexpected => panic!("Unexpected error {}", unexpected), + } +} From 65a1fbe8ae1af569feeb69ad024a916d55345b24 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 29 May 2021 18:08:32 +0100 Subject: [PATCH 4/9] Test for short JPEG tag --- src/decoder/mod.rs | 9 ++++++++- src/decoder/stream.rs | 6 ++++++ tests/decode_images.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 61af67e..406d765 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1409,7 +1409,14 @@ impl Decoder { for (idx, offset) in offsets.iter().enumerate() { self.goto_offset(*offset)?; - let jpeg_reader = JpegReader::new(&mut self.reader, bytes[idx], &jpeg_tables)?; + let length = bytes[idx]; + + if jpeg_tables.is_some() && length < 2 { + return Err(TiffError::FormatError( + TiffFormatError::InvalidTagValueType(Tag::JPEGTables), + )); + } + let jpeg_reader = JpegReader::new(&mut self.reader, length, &jpeg_tables)?; let mut decoder = jpeg::Decoder::new(jpeg_reader); match decoder.decode() { diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index c73e08c..c1c990d 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -231,6 +231,12 @@ impl JpegReader { tables ); + assert!( + length >= 2, + "if jpeg_tables is given, length must be at least 2 bytes long, got {}", + length + ); + let mut jpeg_data = tables.clone(); let truncated_length = jpeg_data.len() - 2; jpeg_data.truncate(truncated_length); diff --git a/tests/decode_images.rs b/tests/decode_images.rs index e13273b..2bc8851 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -449,3 +449,29 @@ fn invalid_jpeg_tag() { unexpected => panic!("Unexpected error {}", unexpected), } } + +#[test] +fn invalid_jpeg_tag_2() { + use tiff::tags; + use tiff::{TiffError, TiffFormatError}; + + let image = [ + 73, 73, 42, 0, 8, 0, 0, 0, 16, 0, 254, 0, 4, 0, 1, 0, 0, 0, 0, 0, 0, 242, 0, 1, 4, 0, 1, 0, + 0, 0, 0, 129, 16, 0, 1, 1, 4, 0, 1, 0, 0, 0, 214, 0, 0, 248, 253, 1, 3, 0, 1, 0, 0, 0, 64, + 0, 0, 0, 3, 1, 3, 0, 1, 0, 0, 0, 7, 0, 0, 0, 6, 1, 3, 0, 1, 0, 0, 0, 1, 0, 0, 64, 14, 1, 0, + 2, 0, 0, 148, 0, 206, 0, 0, 0, 17, 1, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 22, 1, 4, 0, 17, 0, 0, 201, 1, 0, 0, 0, 23, 1, 2, 0, 20, 0, 0, 0, 194, 0, 0, 0, + 91, 1, 7, 0, 5, 0, 0, 0, 64, 0, 0, 0, 237, 254, 65, 255, 255, 255, 255, 255, 1, 0, 0, 0, + 22, 1, 4, 0, 1, 0, 0, 0, 42, 0, 0, 0, 23, 1, 255, 255, 255, 255, 255, 36, 36, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 36, 73, 73, 0, 42, 36, 36, 36, 36, 0, 0, 8, 0, + ]; + + let mut decoder = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap(); + + let err = decoder.read_image().unwrap_err(); + + match err { + TiffError::FormatError(TiffFormatError::InvalidTagValueType(tags::Tag::JPEGTables)) => {} + unexpected => panic!("Unexpected error {}", unexpected), + } +} From f0666aebbf667474e2946fb63f4696147a46f5e3 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 29 May 2021 22:52:42 +0100 Subject: [PATCH 5/9] Fix overflow when calculating strip height for multiple images --- src/decoder/mod.rs | 14 +++++++++++--- tests/decode_images.rs | 23 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 406d765..a396ad0 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1468,10 +1468,18 @@ impl Decoder { let sized_width = usize::try_from(self.width)?; let sized_height = usize::try_from(self.height)?; - // Ignore potential vertical padding on the bottommost strip - let strip_height = cmp::min(rows_per_strip, sized_height - index * rows_per_strip); + let strip_height_without_padding = index + .checked_mul(rows_per_strip) + .and_then(|x| sized_height.checked_sub(x)) + .ok_or(TiffError::IntSizeError)?; - let buffer_size = sized_width * strip_height * self.bits_per_sample.len(); + // Ignore potential vertical padding on the bottommost strip + let strip_height = rows_per_strip.min(strip_height_without_padding); + + let buffer_size = sized_width + .checked_mul(strip_height) + .and_then(|x| x.checked_mul(self.bits_per_sample.len())) + .ok_or(TiffError::LimitsExceeded)?; if buffer.len() < buffer_size { return Err(TiffError::FormatError( diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 2bc8851..12f204f 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -475,3 +475,26 @@ fn invalid_jpeg_tag_2() { unexpected => panic!("Unexpected error {}", unexpected), } } + +#[test] +fn multiple_images_strip_height() { + use tiff::TiffError; + + let image = [ + 73, 73, 42, 0, 8, 0, 0, 0, 8, 0, 0, 1, 4, 0, 1, 0, 0, 0, 2, 0, 0, 0, 61, 1, 9, 0, 46, 22, + 128, 0, 0, 0, 0, 1, 6, 1, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 17, 1, 4, 0, 27, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 3, 0, 1, 0, 0, 0, 17, 1, 0, 231, 22, 1, 1, 0, 1, 0, 0, 0, 130, 0, 0, 0, 23, 1, 4, + 0, 14, 0, 0, 0, 0, 0, 0, 0, 133, 133, 133, 77, 77, 77, 0, 0, 22, 128, 0, 255, 255, 255, + 255, 255, + ]; + + let mut decoder = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap(); + + let _ = decoder.read_image().unwrap(); + let err = decoder.read_image().unwrap_err(); + + match err { + TiffError::IntSizeError => {} + unexpected => panic!("Unexpected error {}", unexpected), + } +} From 1774b362d33932792eb283386f85dfcca99e27b7 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Thu, 15 Jul 2021 18:08:40 +0100 Subject: [PATCH 6/9] x --- fuzz/fuzz_targets/decode_image.rs | 6 +++++- src/decoder/mod.rs | 5 +++++ tests/decode_images.rs | 32 +++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/fuzz/fuzz_targets/decode_image.rs b/fuzz/fuzz_targets/decode_image.rs index 47feb95..25e92da 100644 --- a/fuzz/fuzz_targets/decode_image.rs +++ b/fuzz/fuzz_targets/decode_image.rs @@ -15,7 +15,7 @@ fuzz_target!(|data: &[u8]| { decoder = decoder.with_limits(limits); - loop { + for _ in 0..128 { if let Err(_) = decoder.read_image() { break; } @@ -23,5 +23,9 @@ fuzz_target!(|data: &[u8]| { if !decoder.more_images() { break; } + + if let Err(_) = decoder.next_image() { + break; + } } }); diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index a396ad0..5d3169a 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -728,6 +728,11 @@ impl Decoder { self.byte_order } + fn read_ifd_offset_nonrepeating(&mut self) -> TiffResult { + let result = self.read_ifd_offset()?; + Ok(result) + } + #[inline] pub fn read_ifd_offset(&mut self) -> Result { if self.bigtiff { diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 12f204f..3e7f35c 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -498,3 +498,35 @@ fn multiple_images_strip_height() { unexpected => panic!("Unexpected error {}", unexpected), } } + +#[test] +fn timeout() { + use tiff::TiffError; + + let image = [ + 73, 73, 42, 0, 8, 0, 0, 0, 16, 0, 254, 0, 4, 0, 1, 68, 0, 0, 0, 2, 0, 32, 254, 252, 0, 109, + 0, 129, 0, 0, 0, 32, 0, 58, 0, 1, 4, 0, 1, 0, 6, 0, 0, 0, 8, 0, 0, 1, 73, 73, 42, 0, 8, 0, + 0, 0, 8, 0, 0, 1, 4, 0, 1, 0, 0, 0, 21, 0, 0, 0, 61, 1, 255, 128, 9, 0, 0, 8, 0, 1, 113, 2, + 3, 1, 3, 0, 1, 0, 0, 0, 5, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 112, 0, 0, 36, 0, 0, + 0, 112, 56, 200, 0, 5, 0, 0, 64, 0, 0, 1, 0, 4, 0, 0, 0, 2, 0, 6, 1, 3, 0, 1, 0, 0, 0, 0, + 0, 0, 4, 17, 1, 1, 0, 93, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 3, 6, 0, 231, 22, 1, + 1, 0, 1, 0, 0, 0, 2, 64, 118, 36, 23, 1, 1, 0, 43, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 4, 0, 8, + 0, 0, 73, 73, 42, 0, 8, 0, 0, 0, 0, 0, 32, + ]; + + let mut decoder = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap(); + + loop { + decoder.next_image().unwrap(); + assert!(decoder.more_images()); + } + + /* + let err = decoder.read_image().unwrap_err(); + + match err { + TiffError::IntSizeError => {} + unexpected => panic!("Unexpected error {}", unexpected), + } + */ +} From 885d762def10f6f11dea68dc295562540f40d15a Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Wed, 8 Sep 2021 18:08:10 +0100 Subject: [PATCH 7/9] Implement cycle checking in IFD offsets --- src/decoder/mod.rs | 14 ++++++++++---- src/error.rs | 2 ++ tests/decode_images.rs | 19 +++++-------------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index bc073a3..f39c531 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::convert::TryFrom; use std::io::{self, Read, Seek}; use std::{cmp, ops::Range}; @@ -378,6 +378,7 @@ where strip_decoder: Option, tile_decoder: Option, tile_attributes: Option, + seen_ifds: HashSet, } trait Wrapping { @@ -544,6 +545,7 @@ impl Decoder { strip_decoder: None, tile_decoder: None, tile_attributes: None, + seen_ifds: HashSet::new(), } .init() } @@ -640,7 +642,7 @@ impl Decoder { )) } } - self.next_ifd = match self.read_ifd_offset()? { + self.next_ifd = match self.read_ifd_offset_nonrepeating()? { 0 => None, n => Some(n), }; @@ -738,7 +740,11 @@ impl Decoder { fn read_ifd_offset_nonrepeating(&mut self) -> TiffResult { let result = self.read_ifd_offset()?; - Ok(result) + if self.seen_ifds.insert(result) { + Ok(result) + } else { + Err(TiffError::FormatError(TiffFormatError::CycleInOffsets)) + } } #[inline] @@ -899,7 +905,7 @@ impl Decoder { }; dir.insert(tag, entry); } - self.next_ifd = match self.read_ifd_offset()? { + self.next_ifd = match self.read_ifd_offset_nonrepeating()? { 0 => None, n => Some(n), }; diff --git a/src/error.rs b/src/error.rs index 67e5f08..ea6819d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -64,6 +64,7 @@ pub enum TiffFormatError { Format(String), RequiredTagEmpty(Tag), StripTileTagConflict, + CycleInOffsets, #[doc(hidden)] /// Do not match against this variant. It may get removed. __NonExhaustive, @@ -115,6 +116,7 @@ impl fmt::Display for TiffFormatError { Format(ref val) => write!(fmt, "Invalid format: {:?}.", val), RequiredTagEmpty(ref val) => write!(fmt, "Required tag {:?} was empty.", val), StripTileTagConflict => write!(fmt, "File should contain either (StripByteCounts and StripOffsets) or (TileByteCounts and TileOffsets), other combination was found."), + CycleInOffsets => write!(fmt, "File contained a cycle in the list of IFDs"), __NonExhaustive => unreachable!(), } } diff --git a/tests/decode_images.rs b/tests/decode_images.rs index f528601..7e33d17 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -498,7 +498,7 @@ fn multiple_images_strip_height() { #[test] fn timeout() { - use tiff::TiffError; + use tiff::{TiffError, TiffFormatError}; let image = [ 73, 73, 42, 0, 8, 0, 0, 0, 16, 0, 254, 0, 4, 0, 1, 68, 0, 0, 0, 2, 0, 32, 254, 252, 0, 109, @@ -511,21 +511,12 @@ fn timeout() { 0, 0, 73, 73, 42, 0, 8, 0, 0, 0, 0, 0, 32, ]; - let mut decoder = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap(); + let error = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap_err(); - loop { - decoder.next_image().unwrap(); - assert!(decoder.more_images()); + match error { + TiffError::FormatError(TiffFormatError::CycleInOffsets) => {} + e => panic!("Unexpected error {:?}", e), } - - /* - let err = decoder.read_image().unwrap_err(); - - match err { - TiffError::IntSizeError => {} - unexpected => panic!("Unexpected error {}", unexpected), - } - */ } #[test] From 1c5800daa08ee56b7580a0fa2f9bac2fd0bf0066 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 18 Sep 2021 12:14:17 +0100 Subject: [PATCH 8/9] Infinitely try to read off images rather than only trying 128 --- fuzz/fuzz_targets/decode_image.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/fuzz_targets/decode_image.rs b/fuzz/fuzz_targets/decode_image.rs index 25e92da..51a0892 100644 --- a/fuzz/fuzz_targets/decode_image.rs +++ b/fuzz/fuzz_targets/decode_image.rs @@ -15,7 +15,7 @@ fuzz_target!(|data: &[u8]| { decoder = decoder.with_limits(limits); - for _ in 0..128 { + loop { if let Err(_) = decoder.read_image() { break; } From b065539c078fc27cbf15232e1f47d06d29c54c18 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 18 Sep 2021 14:42:53 +0100 Subject: [PATCH 9/9] Add fuzzing instructions to readme, bump CI version to 1.48 --- .github/workflows/rust.yml | 4 ++-- README.md | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 65fcb70..e444b18 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust: ["1.34.2", stable, beta, nightly] + rust: ["1.48", stable, beta, nightly] command: [build, test] steps: - uses: actions/checkout@v2 @@ -20,7 +20,7 @@ jobs: - name: test run: > cargo test --tests --benches --no-default-features --features "$FEATURES" - if: ${{ matrix.rust != '1.34.2' }} + if: ${{ matrix.rust != '1.48' }} env: FEATURES: ${{ matrix.features }} rustfmt: diff --git a/README.md b/README.md index ce32891..a5fc0a5 100644 --- a/README.md +++ b/README.md @@ -44,3 +44,11 @@ Formats and interpretations not listed above or with empty entries are unsupport - Baseline tags - `ExtraSamples` - Extension tags + +## Fuzzing + +This crate uses [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz) in order to test the image parser. + +After installing it with `cargo install cargo-fuzz` on a nightly rustc, the +fuzzing harness can be run with recommended settings using +`cargo fuzz run decode_image -snone -- -timeout=5`.