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
notriddle committed Sep 1, 2018
1 parent fc46e33 commit 5b3b6ea
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 2 deletions.
52 changes: 51 additions & 1 deletion src/decoder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,67 @@ impl OutputInfo {
}
}

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

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

impl Limits {
pub fn set_pixels(&mut self, pixels: u64) {
self.pixels = pixels;
}
}

/// 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 {
r: r,
transform: ::Transformations::EXPAND | ::Transformations::SCALE_16 | ::Transformations::STRIP_16,

limits: Limits::default(),
}
}

/// 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.set_pixels(4);
/// let mut decoder = Decoder::new(File::open("tests/pngsuite/basi0g01.png").unwrap());
/// decoder.set_limits(limits);
/// 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.set_pixels(1024);
/// let mut decoder = Decoder::new(File::open("tests/pngsuite/basi0g01.png").unwrap());
/// decoder.set_limits(limits);
/// 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 +129,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 5b3b6ea

Please sign in to comment.