Fix T71960: Malformed .bmp files lead to crash

Add a boundary check, avoiding access past actual data.

Ideally would need to report error to the user somehow,
but it doesn't seem to be easy to do.

This is a minimal safe patch. The proper complete fix is
being worked on by Jesse.

Differential Revision: https://developer.blender.org/D10357
This commit is contained in:
Sergey Sharybin 2021-02-08 12:26:50 +01:00 committed by Pablo Dobarro
parent b3c00f97be
commit 834d3e15ce
1 changed files with 18 additions and 3 deletions

View File

@ -111,6 +111,14 @@ bool imb_is_a_bmp(const uchar *buf, size_t size)
return checkbmp(buf, size);
}
static size_t imb_bmp_calc_row_size_in_bytes(size_t x, size_t depth)
{
if (depth <= 8) {
return (depth * x + 31) / 32 * 4;
}
return (depth >> 3) * x;
}
ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
ImBuf *ibuf = NULL;
@ -130,7 +138,8 @@ ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
bmp = mem + LITTLE_LONG(*(int *)(mem + 10));
const size_t pixel_data_offset = LITTLE_LONG(*(int *)(mem + 10));
bmp = mem + pixel_data_offset;
if (CHECK_HEADER_FIELD_BMP(mem)) {
/* skip fileheader */
@ -150,6 +159,13 @@ ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[
xppm = LITTLE_LONG(bmi.biXPelsPerMeter);
yppm = LITTLE_LONG(bmi.biYPelsPerMeter);
const size_t row_size_in_bytes = imb_bmp_calc_row_size_in_bytes(x, depth);
const size_t num_expected_data_bytes = row_size_in_bytes * y;
const size_t num_actual_data_bytes = size - pixel_data_offset;
if (num_actual_data_bytes < num_expected_data_bytes) {
return NULL;
}
if (depth <= 8) {
ibuf_depth = 24;
}
@ -179,7 +195,6 @@ ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[
rect = (uchar *)ibuf->rect;
if (depth <= 8) {
const int rowsize = (depth * x + 31) / 32 * 4;
const char(*palette)[4] = (void *)(mem + skip);
const int startmask = ((1 << depth) - 1) << 8;
for (size_t i = y; i > 0; i--) {
@ -212,7 +227,7 @@ ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[
}
}
/* Advance to the next row */
bmp += (rowsize - nbytes);
bmp += (row_size_in_bytes - nbytes);
}
}
else if (depth == 16) {