diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index f6f6ab7a..18e4f3c1 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -28,6 +28,7 @@ #include "basicio.hpp" #include "config.h" #include "error.hpp" +#include "enforce.hpp" #include "futils.hpp" #include "image.hpp" #include "image_int.hpp" @@ -219,9 +220,13 @@ namespace Exiv2 if (box.length == 1) { DataBuf data(8); io_->read(data.pData_, data.size_); - result = (long) getULongLong(data.pData_, endian_); + const uint64_t sz = getULongLong(data.pData_, endian_); + // Check that `sz` is safe to cast to `long`. + enforce(sz <= static_cast(std::numeric_limits::max()), + Exiv2::kerCorruptedMetadata); + result = (long) sz; // sanity check - if (result < 8 || result+address > (long)io_->size()) { + if (result < 8 || result > (long)io_->size() - address) { result = (long)io_->size(); box.length = result; } else { @@ -231,6 +236,7 @@ namespace Exiv2 // read data in box and restore file position long restore = io_->tell(); + enforce(box.length >= 8, Exiv2::kerCorruptedMetadata); DataBuf data(box.length - 8); io_->read(data.pData_, data.size_); io_->seek(restore, BasicIo::beg); @@ -240,6 +246,7 @@ namespace Exiv2 uint32_t flags = 0; if (fullBox(box.type)) { + enforce(data.size_ - skip >= 4, Exiv2::kerCorruptedMetadata); flags = getLong(data.pData_ + skip, endian_); // version/flags version = (int8_t)flags >> 24; version &= 0x00ffffff; @@ -248,6 +255,7 @@ namespace Exiv2 switch (box.type) { case TAG_ftyp: { + enforce(data.size_ >= 4, Exiv2::kerCorruptedMetadata); fileType_ = getLong(data.pData_, endian_); if ( bTrace ) { out << "brand: " << toAscii(fileType_); @@ -261,6 +269,7 @@ namespace Exiv2 bLF = false; } + enforce(data.size_ - skip >= 2, Exiv2::kerCorruptedMetadata); int n = getShort(data.pData_ + skip, endian_); skip += 2; @@ -272,6 +281,7 @@ namespace Exiv2 // 8.11.6.2 case TAG_infe: { // .__._.__hvc1_ 2 0 0 1 0 1 0 0 104 118 99 49 0 + enforce(data.size_ - skip >= 8, Exiv2::kerCorruptedMetadata); /* getLong (data.pData_+skip,endian_) ; */ skip += 4; uint16_t ID = getShort(data.pData_ + skip, endian_); skip += 2; @@ -324,6 +334,7 @@ namespace Exiv2 // 8.11.3.1 case TAG_iloc: { + enforce(data.size_ - skip >= 2, Exiv2::kerCorruptedMetadata); uint8_t u = data.pData_[skip++]; uint16_t offsetSize = u >> 4; uint16_t lengthSize = u & 0xF; @@ -336,6 +347,7 @@ namespace Exiv2 #else skip++; #endif + enforce(data.size_ - skip >= (version < 2 ? 2 : 4), Exiv2::kerCorruptedMetadata); uint32_t itemCount = version < 2 ? getShort(data.pData_ + skip, endian_) : getLong(data.pData_ + skip, endian_); skip += version < 2 ? 2 : 4; @@ -349,6 +361,8 @@ namespace Exiv2 uint32_t base = skip; for (uint32_t i = 0; i < itemCount; i++) { skip = base + i * step; // move in 14, 16 or 18 byte steps + enforce(data.size_ - skip >= (version > 2 ? 4 : 2), Exiv2::kerCorruptedMetadata); + enforce(data.size_ - skip >= step, Exiv2::kerCorruptedMetadata); uint32_t ID = version > 2 ? getLong(data.pData_ + skip, endian_) : getShort(data.pData_ + skip, endian_); uint32_t offset = step==14 || step==16 ? getLong(data.pData_ + skip + step - 8, endian_) @@ -371,6 +385,7 @@ namespace Exiv2 } break; case TAG_ispe: { + enforce(data.size_ - skip >= 12, Exiv2::kerCorruptedMetadata); skip += 4; int width = getLong(data.pData_ + skip, endian_); skip += 4; diff --git a/tests/bugfixes/github/test_issue_1570.py b/tests/bugfixes/github/test_issue_1570.py index e0ec7854..6446d7ec 100644 --- a/tests/bugfixes/github/test_issue_1570.py +++ b/tests/bugfixes/github/test_issue_1570.py @@ -14,6 +14,7 @@ class BmffImageReadMetadataOutOfBoundsRead(metaclass=CaseMeta): commands = ["$exiv2 $filename"] stdout = [""] stderr = [ -"""$filename1: Could not write metadata to file: $kerCorruptedMetadata +"""Exiv2 exception in print action for file $filename: +$kerCorruptedMetadata """] retval = [1]