Implement cycle checking in IFD offsets

This commit is contained in:
5225225 committed 2021-09-08 18:08:10 +01:00
1 parent 2c9e02d347
commit 885d762def
3 files changed
+16 -17

No files matched your search

+9 -3
View File
@@ -1,4 +1,4 @@
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::io::{self, Read, Seek}; use std::io::{self, Read, Seek};
use std::{cmp, ops::Range}; use std::{cmp, ops::Range};
@@ -378,6 +378,7 @@ where
strip_decoder: Option<StripDecodeState>, strip_decoder: Option<StripDecodeState>,
tile_decoder: Option<TileDecodeState>, tile_decoder: Option<TileDecodeState>,
tile_attributes: Option<TileAttributes>, tile_attributes: Option<TileAttributes>,
seen_ifds: HashSet<u64>,
} }
trait Wrapping { trait Wrapping {
@@ -544,6 +545,7 @@ impl<R: Read + Seek> Decoder<R> {
strip_decoder: None, strip_decoder: None,
tile_decoder: None, tile_decoder: None,
tile_attributes: None, tile_attributes: None,
seen_ifds: HashSet::new(),
} }
.init() .init()
} }
@@ -640,7 +642,7 @@ impl<R: Read + Seek> Decoder<R> {
)) ))
} }
} }
self.next_ifd = match self.read_ifd_offset()? { self.next_ifd = match self.read_ifd_offset_nonrepeating()? {
0 => None, 0 => None,
n => Some(n), n => Some(n),
}; };
@@ -738,7 +740,11 @@ impl<R: Read + Seek> Decoder<R> {
fn read_ifd_offset_nonrepeating(&mut self) -> TiffResult<u64> { fn read_ifd_offset_nonrepeating(&mut self) -> TiffResult<u64> {
let result = self.read_ifd_offset()?; let result = self.read_ifd_offset()?;
if self.seen_ifds.insert(result) {
Ok(result) Ok(result)
} else {
Err(TiffError::FormatError(TiffFormatError::CycleInOffsets))
}
} }
#[inline] #[inline]
@@ -899,7 +905,7 @@ impl<R: Read + Seek> Decoder<R> {
}; };
dir.insert(tag, entry); dir.insert(tag, entry);
} }
self.next_ifd = match self.read_ifd_offset()? { self.next_ifd = match self.read_ifd_offset_nonrepeating()? {
0 => None, 0 => None,
n => Some(n), n => Some(n),
}; };
+2
View File
@@ -64,6 +64,7 @@ pub enum TiffFormatError {
Format(String), Format(String),
RequiredTagEmpty(Tag), RequiredTagEmpty(Tag),
StripTileTagConflict, StripTileTagConflict,
CycleInOffsets,
#[doc(hidden)] #[doc(hidden)]
/// Do not match against this variant. It may get removed. /// Do not match against this variant. It may get removed.
__NonExhaustive, __NonExhaustive,
@@ -115,6 +116,7 @@ impl fmt::Display for TiffFormatError {
Format(ref val) => write!(fmt, "Invalid format: {:?}.", val), Format(ref val) => write!(fmt, "Invalid format: {:?}.", val),
RequiredTagEmpty(ref val) => write!(fmt, "Required tag {:?} was empty.", 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."), 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!(), __NonExhaustive => unreachable!(),
} }
} }
+5 -14
View File
@@ -498,7 +498,7 @@ fn multiple_images_strip_height() {
#[test] #[test]
fn timeout() { fn timeout() {
use tiff::TiffError; use tiff::{TiffError, TiffFormatError};
let image = [ 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, 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, 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 { match error {
decoder.next_image().unwrap(); TiffError::FormatError(TiffFormatError::CycleInOffsets) => {}
assert!(decoder.more_images()); e => panic!("Unexpected error {:?}", e),
} }
/*
let err = decoder.read_image().unwrap_err();
match err {
TiffError::IntSizeError => {}
unexpected => panic!("Unexpected error {}", unexpected),
}
*/
} }
#[test] #[test]