Permalink
Browse files

Fix a heap OOB read in DecodeChunk. Fixes #60

  • Loading branch information...
syoyo committed Jan 11, 2018
1 parent 1d5d3cf commit 852e6b25b48b9ce5d73d4dd0fb0162386f7f3ced
@@ -721,3 +721,26 @@ TEST_CASE("Regression: Issue61", "[fuzzing]") {
FreeEXRHeader(&header);
//FreeEXRImage(&image);
}
TEST_CASE("Regression: Issue60", "[fuzzing]") {
EXRVersion exr_version;
std::string filepath = "./regression/poc-5b66774a7498c635334ad386be0c3b359951738ac47f14878a3346d1c6ea0fe5_min";
int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
REQUIRE(TINYEXR_SUCCESS == ret);
REQUIRE(false == exr_version.tiled);
REQUIRE(false == exr_version.non_image);
REQUIRE(false == exr_version.multipart);
EXRVersion version;
EXRHeader header;
EXRImage image;
InitEXRHeader(&header);
InitEXRImage(&image);
const char* err;
ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
REQUIRE(TINYEXR_SUCCESS == false);
FreeEXRHeader(&header);
//FreeEXRImage(&image);
}
@@ -10412,7 +10412,7 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
const std::vector<tinyexr::tinyexr_uint64> &offsets,
const unsigned char *head) {
const unsigned char *head, const size_t size) {
int num_channels = exr_header->num_channels;
int num_scanline_blocks = 1;
@@ -10453,6 +10453,11 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
// 16 byte: tile coordinates
// 4 byte : data size
// ~ : data(uncompressed or compressed)
if (offsets[tile_idx] + sizeof(int) * 5 > size) {
return TINYEXR_ERROR_INVALID_DATA;
}
size_t data_size = size - (offsets[tile_idx] + sizeof(int) * 5);
const unsigned char *data_ptr =
reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]);
@@ -10471,7 +10476,10 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
memcpy(&data_len, data_ptr + 16,
sizeof(int)); // 16 = sizeof(tile_coordinates)
tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
assert(data_len >= 4);
if (data_len < 4 || size_t(data_len) > data_size) {
return TINYEXR_ERROR_INVALID_DATA;
}
// Move to data addr: 20 = 16 + 4;
data_ptr += 20;
@@ -10508,18 +10516,29 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
#endif
for (int y = 0; y < static_cast<int>(num_blocks); y++) {
size_t y_idx = static_cast<size_t>(y);
const unsigned char *data_ptr =
reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
if (offsets[y_idx] + sizeof(int) * 2 > size) {
return TINYEXR_ERROR_INVALID_DATA;
}
// 4 byte: scan line
// 4 byte: data size
// ~ : pixel data(uncompressed or compressed)
size_t data_size = size - (offsets[y_idx] + sizeof(int) * 2);
const unsigned char *data_ptr =
reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
int line_no;
memcpy(&line_no, data_ptr, sizeof(int));
int data_len;
memcpy(&data_len, data_ptr + 4, sizeof(int));
tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
if (size_t(data_len) > data_size) {
return TINYEXR_ERROR_INVALID_DATA;
}
int end_line_no = (std::min)(line_no + num_scanline_blocks,
(exr_header->data_window[3] + 1));
@@ -10712,7 +10731,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
}
}
return DecodeChunk(exr_image, exr_header, offsets, head);
return DecodeChunk(exr_image, exr_header, offsets, head, size);
}
} // namespace tinyexr
@@ -12453,7 +12472,7 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
}
int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table,
memory);
memory, size);
if (ret != TINYEXR_SUCCESS) {
return ret;
}

0 comments on commit 852e6b2

Please sign in to comment.