Skip to content

Commit

Permalink
Fix a heap OOB read in DecodeChunk. Fixes #60
Browse files Browse the repository at this point in the history
  • Loading branch information
syoyo committed Jan 11, 2018
1 parent 1d5d3cf commit 852e6b2
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 6 deletions.
Binary file not shown.
23 changes: 23 additions & 0 deletions test/unit/tester.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
31 changes: 25 additions & 6 deletions tinyexr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]);

Expand All @@ -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;
Expand Down Expand Up @@ -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));

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 852e6b2

Please sign in to comment.