diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index 515006e..474db41 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -154,7 +154,7 @@ impl Entry { ) } - pub fn val(&self, decoder: &mut super::Decoder) + pub fn val(&self, limits: &super::Limits, decoder: &mut super::Decoder) -> TiffResult { let bo = decoder.byte_order(); match (self.type_, self.count) { @@ -170,6 +170,10 @@ impl Entry { ])) }, (Type::SHORT, n) => { + // each value is ~8 bytes + if n as u64*8 > limits.decoding_buffer_size { + return Err(TiffError::LimitsExceeded) + } let mut v = Vec::with_capacity(n as usize); try!(decoder.goto_offset(try!(self.r(bo).read_u32()))); for _ in 0 .. n { @@ -179,6 +183,10 @@ impl Entry { }, (Type::LONG, 1) => Ok(Unsigned(try!(self.r(bo).read_u32()))), (Type::LONG, n) => { + // each value is ~8 bytes + if n as u64*8 > limits.decoding_buffer_size { + return Err(TiffError::LimitsExceeded) + } let mut v = Vec::with_capacity(n as usize); try!(decoder.goto_offset(try!(self.r(bo).read_u32()))); for _ in 0 .. n { @@ -193,6 +201,10 @@ impl Entry { Ok(Rational(numerator, denominator)) }, (Type::RATIONAL, n) => { + // each value is ~8 bytes + if n as u64*8 > limits.decoding_buffer_size { + return Err(TiffError::LimitsExceeded) + } let mut v = Vec::with_capacity(n as usize); try!(decoder.goto_offset(try!(self.r(bo).read_u32()))); for _ in 0 .. n { @@ -203,6 +215,9 @@ impl Entry { Ok(List(v)) }, (Type::ASCII, n) => { + if n as u64 > limits.decoding_buffer_size { + return Err(TiffError::LimitsExceeded) + } try!(decoder.goto_offset(try!(self.r(bo).read_u32()))); let string = try!(decoder.read_string(n as usize)); Ok(Ascii(string)) diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 1cd8542..e206e2c 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -28,6 +28,24 @@ pub enum DecodingResult { } impl DecodingResult { + fn new_u8(size: usize, limits: &Limits) -> TiffResult { + if size as u64 > limits.decoding_buffer_size { + Err(TiffError::LimitsExceeded) + } + else { + Ok(DecodingResult::U8(vec![0; size])) + } + } + + fn new_u16(size: usize, limits: &Limits) -> TiffResult { + if size as u64*2 > limits.decoding_buffer_size { + Err(TiffError::LimitsExceeded) + } + else { + Ok(DecodingResult::U16(vec![0; size])) + } + } + pub fn to_buffer(&mut self, start: usize) -> DecodingBuffer { match self { DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]), @@ -95,6 +113,28 @@ struct StripDecodeState { strip_bytes: Vec, } +/// Decoding limits +#[derive(Clone, Debug)] +pub struct Limits { + /// The maximum size of any `DecodingResult` in bytes, the default is + /// 256MiB. If the entire image is decoded at once, then this will + /// be the maximum size of the image. If it is decoded one strip at a + /// time, this will be the maximum size of a strip. + decoding_buffer_size: u64, + /// The maximum size of any ifd value in bytes, the default is + /// 1MiB. + ifd_value_size: u64, +} + +impl Default for Limits { + fn default() -> Limits { + Limits { + decoding_buffer_size: 256*1024*1024, + ifd_value_size: 1024*1024, + } + } +} + /// The representation of a TIFF decoder /// /// Currently does not support decoding of interlaced images @@ -102,6 +142,7 @@ struct StripDecodeState { pub struct Decoder where R: Read + Seek { reader: SmartReader, byte_order: ByteOrder, + limits: Limits, next_ifd: Option, ifd: Option, width: u32, @@ -167,6 +208,7 @@ impl Decoder { Decoder { reader: SmartReader::wrap(r, ByteOrder::LittleEndian), byte_order: ByteOrder::LittleEndian, + limits: Default::default(), next_ifd: None, ifd: None, width: 0, @@ -179,6 +221,11 @@ impl Decoder { }.init() } + pub fn with_limits(mut self, limits: Limits) -> Decoder { + self.limits = limits; + self + } + pub fn dimensions(&mut self) -> TiffResult<(u32, u32)> { Ok((self.width, self.height)) } @@ -373,7 +420,9 @@ impl Decoder { Some(entry) => entry.clone(), }; - Ok(Some(try!(entry.val(self)))) + let limits = self.limits.clone(); + + Ok(Some(try!(entry.val(&limits, self)))) } /// Tries to retrieve a tag and convert it to the desired type. @@ -542,8 +591,8 @@ impl Decoder { let buffer_size = self.width as usize * strip_height * self.bits_per_sample.iter().count(); let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) { - n if n <= 8 => DecodingResult::U8(vec![0; buffer_size]), - n if n <= 16 => DecodingResult::U16(vec![0; buffer_size]), + n if n <= 8 => DecodingResult::new_u8(buffer_size, &self.limits)?, + n if n <= 16 => DecodingResult::new_u16(buffer_size, &self.limits)?, n => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedBitsPerChannel(n))), }; @@ -563,8 +612,8 @@ impl Decoder { let buffer_size = self.width as usize * self.height as usize * self.bits_per_sample.iter().count(); let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) { - n if n <= 8 => DecodingResult::U8(vec![0; buffer_size]), - n if n <= 16 => DecodingResult::U16(vec![0; buffer_size]), + n if n <= 8 => DecodingResult::new_u8(buffer_size, &self.limits)?, + n if n <= 16 => DecodingResult::new_u16(buffer_size, &self.limits)?, n => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedBitsPerChannel(n))), }; diff --git a/src/error.rs b/src/error.rs index 07776cd..d26d91b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,6 +18,9 @@ pub enum TiffError { /// An I/O Error occurred while decoding the image IoError(io::Error), + + /// The Limits of the Decoder is exceeded, + LimitsExceeded, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -89,6 +92,7 @@ impl fmt::Display for TiffError { TiffError::UnsupportedError(ref f) => write!(fmt, "The Decoder does not support the \ image format `{}`", f), TiffError::IoError(ref e) => e.fmt(fmt), + TiffError::LimitsExceeded => write!(fmt, "The Decoder limits are exceeded"), } } } @@ -99,6 +103,7 @@ impl Error for TiffError { TiffError::FormatError(..) => "Format error", TiffError::UnsupportedError(..) => "Unsupported error", TiffError::IoError(..) => "IO error", + TiffError::LimitsExceeded => "Decoder limits exceeded", } }