Merge pull request #139 from 5225225/value-bytes-overflow
Check for various arithmetic overflows
This commit is contained in:
3 files changed
+119
-17
No files matched your search
+20
-13
@@ -349,19 +349,26 @@ impl Entry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let bo = decoder.byte_order();
|
let bo = decoder.byte_order();
|
||||||
let value_bytes = self.count
|
|
||||||
* match self.type_ {
|
let tag_size = match self.type_ {
|
||||||
Type::BYTE | Type::SBYTE | Type::ASCII | Type::UNDEFINED => 1,
|
Type::BYTE | Type::SBYTE | Type::ASCII | Type::UNDEFINED => 1,
|
||||||
Type::SHORT | Type::SSHORT => 2,
|
Type::SHORT | Type::SSHORT => 2,
|
||||||
Type::LONG | Type::SLONG | Type::FLOAT | Type::IFD => 4,
|
Type::LONG | Type::SLONG | Type::FLOAT | Type::IFD => 4,
|
||||||
Type::LONG8
|
Type::LONG8
|
||||||
| Type::SLONG8
|
| Type::SLONG8
|
||||||
| Type::DOUBLE
|
| Type::DOUBLE
|
||||||
| Type::RATIONAL
|
| Type::RATIONAL
|
||||||
| Type::SRATIONAL
|
| Type::SRATIONAL
|
||||||
| Type::IFD8 => 8,
|
| Type::IFD8 => 8,
|
||||||
Type::__NonExhaustive => unreachable!(),
|
Type::__NonExhaustive => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let value_bytes = match self.count.checked_mul(tag_size) {
|
||||||
|
Some(n) => n,
|
||||||
|
None => {
|
||||||
|
return Err(TiffError::LimitsExceeded);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Case 2: there is one value.
|
// Case 2: there is one value.
|
||||||
if self.count == 1 {
|
if self.count == 1 {
|
||||||
|
|||||||
+21
-4
@@ -1277,7 +1277,13 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((self.height + rows_per_strip - 1) / rows_per_strip)
|
// rows_per_strip - 1 can never fail since we know it's at least 1
|
||||||
|
let height = match self.height.checked_add(rows_per_strip - 1) {
|
||||||
|
Some(h) => h,
|
||||||
|
None => return Err(TiffError::IntSizeError),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(height / rows_per_strip)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of tiles in image
|
/// Number of tiles in image
|
||||||
@@ -1544,7 +1550,13 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn result_buffer(&self, width: usize, height: usize) -> TiffResult<DecodingResult> {
|
fn result_buffer(&self, width: usize, height: usize) -> TiffResult<DecodingResult> {
|
||||||
let buffer_size = width * height * self.bits_per_sample.len();
|
let buffer_size = match width
|
||||||
|
.checked_mul(height)
|
||||||
|
.and_then(|x| x.checked_mul(self.bits_per_sample.len()))
|
||||||
|
{
|
||||||
|
Some(s) => s,
|
||||||
|
None => return Err(TiffError::LimitsExceeded),
|
||||||
|
};
|
||||||
|
|
||||||
let max_sample_bits = self.bits_per_sample.iter().cloned().max().unwrap_or(8);
|
let max_sample_bits = self.bits_per_sample.iter().cloned().max().unwrap_or(8);
|
||||||
match self.sample_format.first().unwrap_or(&SampleFormat::Uint) {
|
match self.sample_format.first().unwrap_or(&SampleFormat::Uint) {
|
||||||
@@ -1646,8 +1658,13 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
let rows_per_strip =
|
let rows_per_strip =
|
||||||
usize::try_from(self.get_tag_u32(Tag::RowsPerStrip).unwrap_or(self.height))?;
|
usize::try_from(self.get_tag_u32(Tag::RowsPerStrip).unwrap_or(self.height))?;
|
||||||
|
|
||||||
let samples_per_strip =
|
let samples_per_strip = match usize::try_from(self.width)?
|
||||||
usize::try_from(self.width)? * rows_per_strip * self.bits_per_sample.len();
|
.checked_mul(rows_per_strip)
|
||||||
|
.and_then(|x| x.checked_mul(self.bits_per_sample.len()))
|
||||||
|
{
|
||||||
|
Some(s) => s,
|
||||||
|
None => return Err(TiffError::LimitsExceeded),
|
||||||
|
};
|
||||||
|
|
||||||
let mut result =
|
let mut result =
|
||||||
self.result_buffer(usize::try_from(self.width)?, usize::try_from(self.height)?)?;
|
self.result_buffer(usize::try_from(self.width)?, usize::try_from(self.height)?)?;
|
||||||
|
|||||||
@@ -307,3 +307,81 @@ fn test_div_zero() {
|
|||||||
unexpected => panic!("Unexpected error {}", unexpected),
|
unexpected => panic!("Unexpected error {}", unexpected),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_too_many_value_bytes() {
|
||||||
|
let image = [
|
||||||
|
73, 73, 43, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 8, 0, 0, 0,
|
||||||
|
23, 0, 12, 0, 0, 65, 4, 0, 1, 6, 0, 0, 1, 16, 0, 1, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, 59, 73, 84, 186, 202, 83, 240, 66, 1, 53, 22, 56, 47,
|
||||||
|
0, 0, 0, 0, 0, 0, 1, 222, 4, 0, 58, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 4, 0, 0, 100, 0,
|
||||||
|
0, 89, 89, 89, 89, 89, 89, 89, 89, 96, 1, 20, 89, 89, 89, 89, 18,
|
||||||
|
];
|
||||||
|
|
||||||
|
let error = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap_err();
|
||||||
|
|
||||||
|
match error {
|
||||||
|
tiff::TiffError::LimitsExceeded => {}
|
||||||
|
unexpected => panic!("Unexpected error {}", unexpected),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bad_strip_count() {
|
||||||
|
let image = [
|
||||||
|
73, 73, 42, 0, 8, 0, 0, 0, 8, 0, 0, 1, 4, 0, 1, 0, 0, 0, 100, 0, 0, 0, 1, 1, 4, 0, 1, 0, 0,
|
||||||
|
0, 158, 0, 0, 251, 3, 1, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, 6, 1, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
17, 1, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 246, 16, 0, 0, 22, 1, 4, 0, 1,
|
||||||
|
0, 0, 0, 40, 0, 251, 255, 23, 1, 4, 0, 1, 0, 0, 0, 48, 178, 178, 178, 178, 178, 178, 178,
|
||||||
|
178, 178, 178,
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut decoder = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap();
|
||||||
|
|
||||||
|
let err = decoder.read_image().unwrap_err();
|
||||||
|
|
||||||
|
match err {
|
||||||
|
tiff::TiffError::IntSizeError => {}
|
||||||
|
unexpected => panic!("Unexpected error {}", unexpected),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_too_big_buffer_size() {
|
||||||
|
let image = [
|
||||||
|
73, 73, 42, 0, 8, 0, 0, 0, 8, 0, 0, 1, 4, 0, 1, 0, 0, 0, 99, 255, 255, 254, 1, 1, 4, 0, 1,
|
||||||
|
0, 0, 0, 158, 0, 0, 251, 3, 1, 3, 255, 254, 255, 255, 0, 1, 0, 0, 0, 6, 1, 3, 0, 1, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 17, 1, 4, 0, 9, 0, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 2, 0, 0, 0, 63, 0, 0, 0,
|
||||||
|
22, 1, 4, 0, 1, 0, 0, 0, 44, 0, 0, 0, 23, 1, 4, 0, 0, 0, 0, 0, 0, 0, 2, 1, 3, 1, 0, 178,
|
||||||
|
178,
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut decoder = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap();
|
||||||
|
|
||||||
|
let err = decoder.read_image().unwrap_err();
|
||||||
|
|
||||||
|
match err {
|
||||||
|
tiff::TiffError::LimitsExceeded => {}
|
||||||
|
unexpected => panic!("Unexpected error {}", unexpected),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stripped_image_overflow() {
|
||||||
|
let image = [
|
||||||
|
73, 73, 42, 0, 8, 0, 0, 0, 8, 0, 0, 1, 4, 0, 1, 0, 0, 0, 100, 0, 0, 148, 1, 1, 4, 0, 1, 0,
|
||||||
|
0, 0, 158, 0, 0, 251, 3, 1, 3, 255, 254, 255, 255, 0, 1, 0, 0, 0, 6, 1, 3, 0, 1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 17, 1, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 2, 0, 0, 0, 63, 0, 0, 0, 22,
|
||||||
|
1, 4, 0, 1, 0, 0, 0, 44, 0, 248, 255, 23, 1, 4, 0, 1, 0, 0, 0, 178, 178, 178, 0, 1, 178,
|
||||||
|
178, 178,
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut decoder = tiff::decoder::Decoder::new(std::io::Cursor::new(&image)).unwrap();
|
||||||
|
|
||||||
|
let err = decoder.read_image().unwrap_err();
|
||||||
|
|
||||||
|
match err {
|
||||||
|
tiff::TiffError::LimitsExceeded => {}
|
||||||
|
unexpected => panic!("Unexpected error {}", unexpected),
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user