Skip to content

Commit c64e35a

Browse files
authored
Check for integer overflows in RawBmp::parse (#32)
* Check for integer overflows in RawBmp::parse * Don't allow images with zero width or height * Check for negative width and add tests * Reformat code
1 parent 58c8e3f commit c64e35a

8 files changed

Lines changed: 53 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
- [#28](https://github.com/embedded-graphics/tinybmp/pull/28) `Bpp::bits`, `RawBmp::image_data`, `RawBmp::header`, and `RawPixel::new` are now `const`.
2424
- [#28](https://github.com/embedded-graphics/tinybmp/pull/28) BMP files with incomplete image data are now detected by `Bmp::from_slice`.
2525

26+
### Fixed
27+
28+
- [#32](https://github.com/embedded-graphics/tinybmp/pull/32) Report error for images with `width <= 0` or `height == 0` instead of causing a panic.
29+
2630
## [0.3.3] - 2022-04-18
2731

2832
### Fixed

src/header/dib_header.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl DibHeader {
4848
};
4949

5050
// Fields common to all DIB variants
51-
let (dib_header_data, image_width) = le_u32(dib_header_data)?;
51+
let (dib_header_data, image_width) = le_i32(dib_header_data)?;
5252
let (dib_header_data, image_height) = le_i32(dib_header_data)?;
5353
let (dib_header_data, _color_planes) = le_u16(dib_header_data)?;
5454
let (dib_header_data, bpp) = Bpp::parse(dib_header_data)?;
@@ -91,6 +91,10 @@ impl DibHeader {
9191
colors_used
9292
};
9393

94+
if image_width <= 0 || image_height == 0 {
95+
return Err(ParseError::InvalidImageDimensions);
96+
}
97+
9498
let row_order = if image_height < 0 {
9599
RowOrder::TopDown
96100
} else {
@@ -101,7 +105,7 @@ impl DibHeader {
101105
input,
102106
Self {
103107
header_type,
104-
image_size: Size::new(image_width, image_height.unsigned_abs()),
108+
image_size: Size::new(image_width.unsigned_abs(), image_height.unsigned_abs()),
105109
image_data_len,
106110
bpp,
107111
channel_masks,

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,9 @@ pub enum ParseError {
365365

366366
/// Unsupported channel masks.
367367
UnsupportedChannelMasks,
368+
369+
/// Invalid image dimensions.
370+
InvalidImageDimensions,
368371
}
369372

370373
#[cfg(test)]

src/raw_bmp.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,21 @@ impl<'a> RawBmp<'a> {
4444

4545
let color_type = ColorType::from_header(&header)?;
4646

47-
let data_length = header.bytes_per_row() * header.image_size.height as usize;
48-
47+
let height = header
48+
.image_size
49+
.height
50+
.try_into()
51+
.map_err(|_| ParseError::InvalidImageDimensions)?;
52+
53+
let data_length = header
54+
.bytes_per_row()
55+
.checked_mul(height)
56+
.ok_or(ParseError::InvalidImageDimensions)?;
57+
58+
// The `get` is split into two calls to prevent an possible integer overflow.
4959
let image_data = &bytes
50-
.get(header.image_data_start..header.image_data_start + data_length)
60+
.get(header.image_data_start..)
61+
.and_then(|bytes| bytes.get(..data_length))
5162
.ok_or(ParseError::UnexpectedEndOfFile)?;
5263

5364
Ok(Self {

tests/error-height-0.bmp

86 Bytes
Binary file not shown.

tests/error-width-0.bmp

86 Bytes
Binary file not shown.

tests/error-width-negative.bmp

86 Bytes
Binary file not shown.

tests/errors.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use embedded_graphics::pixelcolor::Rgb888;
2+
use tinybmp::{Bmp, ParseError};
3+
4+
#[test]
5+
fn zero_width() {
6+
assert_eq!(
7+
Bmp::<Rgb888>::from_slice(include_bytes!("error-width-0.bmp")),
8+
Err(ParseError::InvalidImageDimensions)
9+
);
10+
}
11+
12+
#[test]
13+
fn negative_width() {
14+
assert_eq!(
15+
Bmp::<Rgb888>::from_slice(include_bytes!("error-width-negative.bmp")),
16+
Err(ParseError::InvalidImageDimensions)
17+
);
18+
}
19+
20+
#[test]
21+
fn zero_height() {
22+
assert_eq!(
23+
Bmp::<Rgb888>::from_slice(include_bytes!("error-height-0.bmp")),
24+
Err(ParseError::InvalidImageDimensions)
25+
);
26+
}

0 commit comments

Comments
 (0)