Skip to content

Commit 852e6b2

Browse files
committed
Fix a heap OOB read in DecodeChunk. Fixes #60
1 parent 1d5d3cf commit 852e6b2

File tree

3 files changed

+48
-6
lines changed

3 files changed

+48
-6
lines changed

test/unit/tester.cc

+23
Original file line numberDiff line numberDiff line change
@@ -721,3 +721,26 @@ TEST_CASE("Regression: Issue61", "[fuzzing]") {
721721
FreeEXRHeader(&header);
722722
//FreeEXRImage(&image);
723723
}
724+
725+
TEST_CASE("Regression: Issue60", "[fuzzing]") {
726+
EXRVersion exr_version;
727+
std::string filepath = "./regression/poc-5b66774a7498c635334ad386be0c3b359951738ac47f14878a3346d1c6ea0fe5_min";
728+
int ret = ParseEXRVersionFromFile(&exr_version, filepath.c_str());
729+
REQUIRE(TINYEXR_SUCCESS == ret);
730+
REQUIRE(false == exr_version.tiled);
731+
REQUIRE(false == exr_version.non_image);
732+
REQUIRE(false == exr_version.multipart);
733+
734+
EXRVersion version;
735+
EXRHeader header;
736+
EXRImage image;
737+
InitEXRHeader(&header);
738+
InitEXRImage(&image);
739+
740+
const char* err;
741+
ret = ParseEXRHeaderFromFile(&header, &exr_version, filepath.c_str(), &err);
742+
REQUIRE(TINYEXR_SUCCESS == false);
743+
744+
FreeEXRHeader(&header);
745+
//FreeEXRImage(&image);
746+
}

tinyexr.h

+25-6
Original file line numberDiff line numberDiff line change
@@ -10412,7 +10412,7 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
1041210412

1041310413
static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
1041410414
const std::vector<tinyexr::tinyexr_uint64> &offsets,
10415-
const unsigned char *head) {
10415+
const unsigned char *head, const size_t size) {
1041610416
int num_channels = exr_header->num_channels;
1041710417

1041810418
int num_scanline_blocks = 1;
@@ -10453,6 +10453,11 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
1045310453
// 16 byte: tile coordinates
1045410454
// 4 byte : data size
1045510455
// ~ : data(uncompressed or compressed)
10456+
if (offsets[tile_idx] + sizeof(int) * 5 > size) {
10457+
return TINYEXR_ERROR_INVALID_DATA;
10458+
}
10459+
10460+
size_t data_size = size - (offsets[tile_idx] + sizeof(int) * 5);
1045610461
const unsigned char *data_ptr =
1045710462
reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]);
1045810463

@@ -10471,7 +10476,10 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
1047110476
memcpy(&data_len, data_ptr + 16,
1047210477
sizeof(int)); // 16 = sizeof(tile_coordinates)
1047310478
tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
10474-
assert(data_len >= 4);
10479+
10480+
if (data_len < 4 || size_t(data_len) > data_size) {
10481+
return TINYEXR_ERROR_INVALID_DATA;
10482+
}
1047510483

1047610484
// Move to data addr: 20 = 16 + 4;
1047710485
data_ptr += 20;
@@ -10508,18 +10516,29 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
1050810516
#endif
1050910517
for (int y = 0; y < static_cast<int>(num_blocks); y++) {
1051010518
size_t y_idx = static_cast<size_t>(y);
10511-
const unsigned char *data_ptr =
10512-
reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
10519+
10520+
if (offsets[y_idx] + sizeof(int) * 2 > size) {
10521+
return TINYEXR_ERROR_INVALID_DATA;
10522+
}
10523+
1051310524
// 4 byte: scan line
1051410525
// 4 byte: data size
1051510526
// ~ : pixel data(uncompressed or compressed)
10527+
size_t data_size = size - (offsets[y_idx] + sizeof(int) * 2);
10528+
const unsigned char *data_ptr =
10529+
reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
10530+
1051610531
int line_no;
1051710532
memcpy(&line_no, data_ptr, sizeof(int));
1051810533
int data_len;
1051910534
memcpy(&data_len, data_ptr + 4, sizeof(int));
1052010535
tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
1052110536
tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
1052210537

10538+
if (size_t(data_len) > data_size) {
10539+
return TINYEXR_ERROR_INVALID_DATA;
10540+
}
10541+
1052310542
int end_line_no = (std::min)(line_no + num_scanline_blocks,
1052410543
(exr_header->data_window[3] + 1));
1052510544

@@ -10712,7 +10731,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
1071210731
}
1071310732
}
1071410733

10715-
return DecodeChunk(exr_image, exr_header, offsets, head);
10734+
return DecodeChunk(exr_image, exr_header, offsets, head, size);
1071610735
}
1071710736

1071810737
} // namespace tinyexr
@@ -12453,7 +12472,7 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
1245312472
}
1245412473

1245512474
int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table,
12456-
memory);
12475+
memory, size);
1245712476
if (ret != TINYEXR_SUCCESS) {
1245812477
return ret;
1245912478
}

0 commit comments

Comments
 (0)