Skip to content

Commit

Permalink
Validate size of uncompressed alpha chunks and other fixes (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
fintelia authored Jan 1, 2024
1 parent 67a0f4e commit 5e680cc
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 38 deletions.
16 changes: 0 additions & 16 deletions fuzz/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,8 +571,8 @@ impl<R: Read + Seek> WebPDecoder<R> {
.clone();
let alpha_chunk = read_alpha_chunk(
&mut range_reader(&mut self.r, range.start..range.end)?,
self.width,
self.height,
self.width as u16,
self.height as u16,
)?;

for y in 0..frame.height {
Expand Down Expand Up @@ -632,6 +632,9 @@ impl<R: Read + Seek> WebPDecoder<R> {
let frame_y = extended::read_3_bytes(&mut self.r)? * 2;
let frame_width = extended::read_3_bytes(&mut self.r)? + 1;
let frame_height = extended::read_3_bytes(&mut self.r)? + 1;
if frame_width > 16384 || frame_height > 16384 {
return Err(DecodingError::ImageTooLarge);
}
if frame_x + frame_width > self.width || frame_y + frame_height > self.height {
return Err(DecodingError::FrameOutsideImage);
}
Expand Down Expand Up @@ -688,7 +691,8 @@ impl<R: Read + Seek> WebPDecoder<R> {
// read alpha
let next_chunk_start = self.r.stream_position()? + chunk_size_rounded as u64;
let mut reader = (&mut self.r).take(chunk_size as u64);
let alpha_chunk = read_alpha_chunk(&mut reader, frame_width, frame_height)?;
let alpha_chunk =
read_alpha_chunk(&mut reader, frame_width as u16, frame_height as u16)?;

// read opaque
self.r.seek(io::SeekFrom::Start(next_chunk_start))?;
Expand Down
23 changes: 6 additions & 17 deletions src/extended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::lossless::LosslessDecoder;
use crate::decoder::DecodingError;
use byteorder::ReadBytesExt;
use std::convert::TryInto;
use std::io::{self, Read};
use std::io::Read;

#[derive(Debug, Clone)]
pub(crate) struct WebPExtendedInfo {
Expand Down Expand Up @@ -264,8 +264,8 @@ pub(crate) enum FilteringMethod {

pub(crate) fn read_alpha_chunk<R: Read>(
reader: &mut R,
width: u32,
height: u32,
width: u16,
height: u16,
) -> Result<AlphaChunk, DecodingError> {
let info_byte = reader.read_u8()?;

Expand Down Expand Up @@ -298,27 +298,16 @@ pub(crate) fn read_alpha_chunk<R: Read>(
_ => return Err(DecodingError::InvalidCompressionMethod),
};

let mut framedata = Vec::new();
reader.read_to_end(&mut framedata)?;

let data = if lossless_compression {
let cursor = io::Cursor::new(framedata);

let mut decoder = LosslessDecoder::new(cursor);
//this is a potential problem for large images; would require rewriting lossless decoder to
//use u32 for width and height
let width: u16 = width.try_into().map_err(|_| DecodingError::ImageTooLarge)?;
let height: u16 = height
.try_into()
.map_err(|_| DecodingError::ImageTooLarge)?;
let mut decoder = LosslessDecoder::new(reader);
let frame = decoder.decode_frame(Some((width, height)))?;

let mut data = vec![0u8; usize::from(width) * usize::from(height)];

frame.fill_green(&mut data);

data
} else {
let mut framedata = vec![0; width as usize * height as usize];
reader.read_exact(&mut framedata)?;
framedata
};

Expand Down
2 changes: 1 addition & 1 deletion src/lossless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ impl<R: Read> LosslessDecoder<R> {
}

/// Adjusts the color map since it's subtraction coded
fn adjust_color_map(color_map: &mut Vec<u32>) {
fn adjust_color_map(color_map: &mut [u32]) {
for i in 1..color_map.len() {
color_map[i] = add_pixels(color_map[i], color_map[i - 1]);
}
Expand Down
2 changes: 1 addition & 1 deletion src/vp8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1307,7 +1307,7 @@ impl<R: Read> Vp8Decoder<R> {

self.top = init_top_macroblocks(self.frame.width as usize);
// Almost always the first macro block, except when non exists (i.e. `width == 0`)
self.left = self.top.get(0).cloned().unwrap_or_default();
self.left = self.top.first().cloned().unwrap_or_default();

self.mbwidth = (self.frame.width + 15) / 16;
self.mbheight = (self.frame.height + 15) / 16;
Expand Down

0 comments on commit 5e680cc

Please sign in to comment.