Skip to content

Commit

Permalink
Merge pull request #1825 from Exiv2/mergify/bp/main/pr-1814
Browse files Browse the repository at this point in the history
jp2image.cpp: check size before allocation to avoid out-of-memory errors (backport #1814)
  • Loading branch information
kevinbackhouse authored Aug 2, 2021
2 parents 0eacac6 + ffde235 commit 34aa899
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 18 deletions.
14 changes: 11 additions & 3 deletions src/jp2image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ static void boxes_check(size_t b,size_t m)
<< " length: " << box.length
<< std::endl;
#endif
enforce(box.length <= sizeof(box)+io_->size()-io_->tell() , Exiv2::kerCorruptedMetadata);

if (box.length == 0) return ;

Expand Down Expand Up @@ -348,6 +349,7 @@ static void boxes_check(size_t b,size_t m)
#ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::Jp2Image::readMetadata: Exif data found" << std::endl ;
#endif
enforce(box.length >= sizeof(box) + sizeof(uuid), kerCorruptedMetadata);
rawData.alloc(box.length - (sizeof(box) + sizeof(uuid)));
bufRead = io_->read(rawData.pData_, rawData.size_);
if (io_->error()) throw Error(kerFailedToReadImageData);
Expand Down Expand Up @@ -402,6 +404,7 @@ static void boxes_check(size_t b,size_t m)
#ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::Jp2Image::readMetadata: Iptc data found" << std::endl;
#endif
enforce(box.length >= sizeof(box) + sizeof(uuid), kerCorruptedMetadata);
rawData.alloc(box.length - (sizeof(box) + sizeof(uuid)));
bufRead = io_->read(rawData.pData_, rawData.size_);
if (io_->error()) throw Error(kerFailedToReadImageData);
Expand All @@ -421,6 +424,7 @@ static void boxes_check(size_t b,size_t m)
#ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::Jp2Image::readMetadata: Xmp data found" << std::endl;
#endif
enforce(box.length >= sizeof(box) + sizeof(uuid), kerCorruptedMetadata);
rawData.alloc(box.length - static_cast<uint32_t>(sizeof(box) + sizeof(uuid)));
bufRead = io_->read(rawData.pData_, rawData.size_);
if (io_->error())
Expand Down Expand Up @@ -497,7 +501,7 @@ static void boxes_check(size_t b,size_t m)
position = io_->tell();
box.length = getLong(reinterpret_cast<byte*>(&box.length), bigEndian);
box.type = getLong(reinterpret_cast<byte*>(&box.type), bigEndian);
enforce(box.length <= io_->size()-io_->tell() , Exiv2::kerCorruptedMetadata);
enforce(box.length <= sizeof(box)+io_->size()-io_->tell() , Exiv2::kerCorruptedMetadata);

if (bPrint) {
out << Internal::stringFormat("%8ld | %8ld | ", position - sizeof(box),
Expand All @@ -517,7 +521,7 @@ static void boxes_check(size_t b,size_t m)
while (io_->read(reinterpret_cast<byte*>(&subBox), sizeof(subBox)) == sizeof(subBox) &&
io_->tell() < position + static_cast<long>(box.length)) // don't read beyond the box!
{
int address = io_->tell() - sizeof(subBox);
const size_t address = io_->tell() - sizeof(subBox);
subBox.length = getLong(reinterpret_cast<byte*>(&subBox.length), bigEndian);
subBox.type = getLong(reinterpret_cast<byte*>(&subBox.type), bigEndian);

Expand All @@ -537,7 +541,10 @@ static void boxes_check(size_t b,size_t m)

if (subBox.type == kJp2BoxTypeColorHeader) {
long pad = 3; // don't know why there are 3 padding bytes
enforce(data.size_ >= pad, kerCorruptedMetadata);

// Bounds-check for the `getULong()` below, which reads 4 bytes, starting at `pad`.
enforce(data.size_ >= pad + 4, kerCorruptedMetadata);

if (bPrint) {
out << " | pad:";
for (int i = 0; i < 3; i++)
Expand Down Expand Up @@ -576,6 +583,7 @@ static void boxes_check(size_t b,size_t m)
}

DataBuf rawData;
enforce(box.length >= sizeof(uuid) + sizeof(box), kerCorruptedMetadata);
rawData.alloc(box.length - sizeof(uuid) - sizeof(box));
long bufRead = io_->read(rawData.pData_, rawData.size_);
if (io_->error())
Expand Down
Binary file added test/data/issue_1812_poc.jp2
Binary file not shown.
14 changes: 5 additions & 9 deletions tests/bugfixes/github/test_issue_1522.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,16 @@
class issue_1522_exif_asan(metaclass=system_tests.CaseMeta):
url = "https://github.com/Exiv2/exiv2/issues/1522"
filename = "$data_path/poc_1522.jp2"
commands = ["$exiv2 $filename"
commands = ["$exiv2 -q $filename"
,"$exiv2 -pS $filename"
]
retval = [ 253,1 ]
stderr = [ """Warning: Failed to decode Exif metadata.
$filename: No Exif data found in the file
retval = [ 1,1 ]
stderr = [ """$exiv2_exception_message $filename:
$kerCorruptedMetadata
""","""$exiv2_exception_message $filename:
$kerCorruptedMetadata
"""]
stdout = ["""File name : $filename
File size : 268 Bytes
MIME type : image/jp2
Image size : 0 x 0
""","""STRUCTURE OF JPEG2000 FILE: $filename
stdout = ["","""STRUCTURE OF JPEG2000 FILE: $filename
address | length | box | data
0 | 12 | jP |
12 | 25 | uuid | Exif: .
Expand Down
24 changes: 24 additions & 0 deletions tests/bugfixes/github/test_issue_1812.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-

from system_tests import CaseMeta, path, check_no_ASAN_UBSAN_errors


class OutOfMemoryInJp2ImageReadMetadata(metaclass=CaseMeta):
"""
Regression test for the bug described in:
https://github.com/Exiv2/exiv2/issues/1812
Due to a missing bounds check, this test triggers a 4GB memory
allocation. So the test will fail with a std::bad_alloc exception
if less than 4GB is available. On Linux, you can use `ulimit -v
4000000` to reduce the available memory to slightly less than 4GB.
"""
url = "https://github.com/Exiv2/exiv2/issues/1812"

filename = path("$data_path/issue_1812_poc.jp2")
commands = ["$exiv2 $filename"]
stdout = [""]
stderr = ["""$exiv2_exception_message $filename:
$kerCorruptedMetadata
"""]
retval = [1]
9 changes: 3 additions & 6 deletions tests/bugfixes/github/test_issue_ghsa_7569_phvm_vwc2.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,10 @@ class Jp2ImageDoWriteMetadataOutOfBoundsRead(metaclass=CaseMeta):

filename1 = path("$data_path/issue_ghsa_7569_phvm_vwc2_poc.jp2")
filename2 = path("$data_path/issue_ghsa_7569_phvm_vwc2_poc.exv")
commands = ["$exiv2 in $filename1"]
commands = ["$exiv2 -q in $filename1"]
stdout = [""]
stderr = [
"""Warning: Directory Thumbnail, entry 0x1000 has unknown Exif (TIFF) type 28928; setting type size 1.
Error: Directory Thumbnail: IFD entry 1 lies outside of the data buffer.
Warning: Directory Thumbnail, entry 0x1000 has unknown Exif (TIFF) type 28928; setting type size 1.
Error: Offset of directory Thumbnail, entry 0x1000 is out of bounds: Offset = 0x2020506a; truncating the entry
$filename1: Could not write metadata to file: $kerCorruptedMetadata
"""Exiv2 exception in insert action for file $filename1:
$kerCorruptedMetadata
"""]
retval = [1]

0 comments on commit 34aa899

Please sign in to comment.