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] 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]