Skip to content

Commit

Permalink
Limit decoded images to 2^26 pixels by default
Browse files Browse the repository at this point in the history
  • Loading branch information
zealousidealroll committed Sep 6, 2018
1 parent fc46e33 commit a7d1af1
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 2 deletions.
48 changes: 47 additions & 1 deletion src/decoder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,63 @@ impl OutputInfo {
}
}

#[derive(Clone, Copy, Debug)]
pub struct Limits {
/// max number of pixels: `width * height` (default: 67M = 2<sup>26</sup>)
pub pixels: u64,
}

impl Default for Limits {
fn default() -> Limits {
Limits {
pixels: 1 << 26,
}
}
}

/// PNG Decoder
pub struct Decoder<R: Read> {
/// Reader
r: R,
/// Output transformations
transform: Transformations,
/// Images that are considered too big
limits: Limits,
}

impl<R: Read> Decoder<R> {
pub fn new(r: R) -> Decoder<R> {
Decoder::new_with_limits(r, Limits::default())
}

pub fn new_with_limits(r: R, l: Limits) -> Decoder<R> {
Decoder {
r: r,
transform: ::Transformations::EXPAND | ::Transformations::SCALE_16 | ::Transformations::STRIP_16,

limits: l,
}
}

/// Images that are considered too big
///
/// ```
/// use std::fs::File;
/// use png::{Decoder, Limits};
/// // This image is 32x32 pixels, so it's more than four pixels in size.
/// let mut limits = Limits::default();
/// limits.pixels = 4;
/// let mut decoder = Decoder::new_with_limits(File::open("tests/pngsuite/basi0g01.png", limits).unwrap());
/// assert!(decoder.read_info().is_err());
/// // This image is 32x32 pixels, so it's exactly 1024 pixels in size.
/// let mut limits = Limits::default();
/// limits.pixels = 1024;
/// let mut decoder = Decoder::new_with_limits(File::open("tests/pngsuite/basi0g01.png", limits).unwrap());
/// assert!(decoder.read_info().is_ok());
/// ```
pub fn set_limits(&mut self, limits: Limits) {
self.limits = limits;
}

/// Reads all meta data until the first IDAT chunk
pub fn read_info(self) -> Result<(OutputInfo, Reader<R>), DecodingError> {
let mut r = Reader::new(self.r, StreamingDecoder::new(), self.transform);
Expand All @@ -85,6 +125,12 @@ impl<R: Read> Decoder<R> {
line_size: r.output_line_size(info.width),
}
};
let (width, height, pixels) = (info.width as u64, info.height as u64, self.limits.pixels);
if width.checked_mul(height).map(|p| p > pixels).unwrap_or(true) {
// DecodingError::Other is used for backwards compatibility.
// In the next major version, add a variant for this.
return Err(DecodingError::Other(borrow::Cow::Borrowed("pixels limit exceeded")));
}
Ok((info, r))
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ mod common;
mod utils;

pub use common::*;
pub use decoder::{Decoder, Reader, OutputInfo, StreamingDecoder, Decoded, DecodingError};
pub use decoder::{Decoder, Reader, OutputInfo, StreamingDecoder, Decoded, DecodingError, Limits};
#[cfg(feature = "png-encoding")]
pub use encoder::{Encoder, Writer, EncodingError};

Expand Down

0 comments on commit a7d1af1

Please sign in to comment.