diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 6d8f3870..d2a9ff5e 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -92,8 +92,8 @@ namespace Exiv2 @param start offset in file (default, io_->tell()) @ */ - void parseTiff(uint32_t root_tag, uint32_t length); - void parseTiff(uint32_t root_tag, uint32_t length,uint32_t start); + void parseTiff(uint32_t root_tag, uint64_t length); + void parseTiff(uint32_t root_tag, uint64_t length,uint64_t start); //@} //@{ @@ -103,7 +103,7 @@ namespace Exiv2 @param start offset in file @ */ - void parseXmp(uint32_t length,uint32_t start); + void parseXmp(uint64_t length,uint64_t start); //@} //! @name Manipulators diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index d3fe383d..552fbcb8 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -45,12 +45,6 @@ #include #include -struct BmffBoxHeader -{ - uint32_t length; - uint32_t type; -}; - #define TAG_ftyp 0x66747970 /**< "ftyp" File type box */ #define TAG_avif 0x61766966 /**< "avif" AVIF */ #define TAG_avio 0x6176696f /**< "avio" AVIF */ @@ -202,47 +196,40 @@ namespace Exiv2 bTrace = true ; #endif - BmffBoxHeader box = {0, 0}; - size_t hdrsize = sizeof(box); + // 8-byte buffer for parsing the box length and type. + byte hdrbuf[2 * sizeof(uint32_t)]; + + size_t hdrsize = sizeof(hdrbuf); enforce(hdrsize <= static_cast(pbox_end - address), Exiv2::kerCorruptedMetadata); - if (io_->read(reinterpret_cast(&box), sizeof(box)) != sizeof(box)) + if (io_->read(reinterpret_cast(&hdrbuf), sizeof(hdrbuf)) != sizeof(hdrbuf)) return result; - box.length = getLong(reinterpret_cast(&box.length), endian_); - box.type = getLong(reinterpret_cast(&box.type), endian_); + // The box length is encoded as a uint32_t by default, but the special value 1 means + // that it's a uint64_t. + uint64_t box_length = getLong(reinterpret_cast(&hdrbuf[0]), endian_); + uint32_t box_type = getLong(reinterpret_cast(&hdrbuf[sizeof(uint32_t)]), endian_); bool bLF = true; if ( bTrace ) { bLF = true; - out << indent(depth) << "Exiv2::BmffImage::boxHandler: " << toAscii(box.type) - << Internal::stringFormat(" %8ld->%u ", address, box.length); + out << indent(depth) << "Exiv2::BmffImage::boxHandler: " << toAscii(box_type) + << Internal::stringFormat(" %8ld->%u ", address, box_length); } - if (box.length == 1) { + if (box_length == 1) { // The box size is encoded as a uint64_t, so we need to read another 8 bytes. hdrsize += 8; enforce(hdrsize <= static_cast(pbox_end - address), Exiv2::kerCorruptedMetadata); DataBuf data(8); io_->read(data.pData_, data.size_); - 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 = static_cast(sz); - // sanity check - if (result < 8 || result > static_cast(io_->size()) - address) { - result = static_cast(io_->size()); - box.length = result; - } else { - box.length = static_cast(io_->size() - address); - } + box_length = getULongLong(data.pData_, endian_); } // read data in box and restore file position long restore = io_->tell(); - enforce(box.length >= hdrsize, Exiv2::kerCorruptedMetadata); - enforce(box.length - hdrsize <= static_cast(pbox_end - restore), Exiv2::kerCorruptedMetadata); - DataBuf data(box.length - hdrsize); + enforce(box_length >= hdrsize, Exiv2::kerCorruptedMetadata); + enforce(box_length - hdrsize <= static_cast(pbox_end - restore), Exiv2::kerCorruptedMetadata); + DataBuf data(box_length - hdrsize); const long box_end = restore + data.size_; io_->read(data.pData_, data.size_); io_->seek(restore, BasicIo::beg); @@ -251,7 +238,7 @@ namespace Exiv2 uint8_t version = 0; uint32_t flags = 0; - if (fullBox(box.type)) { + if (fullBox(box_type)) { enforce(data.size_ - skip >= 4, Exiv2::kerCorruptedMetadata); flags = getLong(data.pData_ + skip, endian_); // version/flags version = static_cast(flags) >> 24; @@ -259,7 +246,7 @@ namespace Exiv2 skip += 4; } - switch (box.type) { + switch (box_type) { case TAG_ftyp: { enforce(data.size_ >= 4, Exiv2::kerCorruptedMetadata); fileType_ = getLong(data.pData_, endian_); @@ -320,11 +307,11 @@ namespace Exiv2 bLF = false; } io_->seek(skip, BasicIo::cur); - while (io_->tell() < static_cast((address + box.length))) { + while (io_->tell() < static_cast((address + box_length))) { io_->seek(boxHandler(out,option,box_end,depth + 1), BasicIo::beg); } // post-process meta box to recover Exif and XMP - if (box.type == TAG_meta) { + if (box_type == TAG_meta) { if ( ilocs_.find(exifID_) != ilocs_.end()) { const Iloc& iloc = ilocs_.find(exifID_)->second; if ( bTrace ) { @@ -362,13 +349,13 @@ namespace Exiv2 uint32_t itemCount = version < 2 ? getShort(data.pData_ + skip, endian_) : getLong(data.pData_ + skip, endian_); skip += version < 2 ? 2 : 4; - if (itemCount && itemCount < box.length / 14 && offsetSize == 4 && lengthSize == 4 && - ((box.length - 16) % itemCount) == 0) { + if (itemCount && itemCount < box_length / 14 && offsetSize == 4 && lengthSize == 4 && + ((box_length - 16) % itemCount) == 0) { if ( bTrace ) { out << std::endl; bLF = false; } - long step = (box.length - 16) / itemCount; // length of data per item. + long step = (box_length - 16) / itemCount; // length of data per item. long base = skip; for (uint32_t i = 0; i < itemCount; i++) { skip = base + i * step; // move in 14, 16 or 18 byte steps @@ -416,8 +403,7 @@ namespace Exiv2 // 12.1.5.2 case TAG_colr: { if (data.size_ >= - static_cast(skip + 4 + - sizeof(box))) { // .____.HLino..__mntrR 2 0 0 0 0 12 72 76 105 110 111 2 16 ... + static_cast(skip + 4 + 8)) { // .____.HLino..__mntrR 2 0 0 0 0 12 72 76 105 110 111 2 16 ... // https://www.ics.uci.edu/~dan/class/267/papers/jpeg2000.pdf uint8_t meth = data.pData_[skip+0]; uint8_t prec = data.pData_[skip+1]; @@ -445,31 +431,31 @@ namespace Exiv2 bLF = false; } if (name == "cano") { - while (io_->tell() < static_cast(address + box.length)) { + while (io_->tell() < static_cast(address + box_length)) { io_->seek(boxHandler(out,option,box_end,depth + 1), BasicIo::beg); } } else if ( name == "xmp" ) { - parseXmp(box.length,io_->tell()); + parseXmp(box_length,io_->tell()); } } break; case TAG_cmt1: - parseTiff(Internal::Tag::root, box.length); + parseTiff(Internal::Tag::root, box_length); break; case TAG_cmt2: - parseTiff(Internal::Tag::cmt2, box.length); + parseTiff(Internal::Tag::cmt2, box_length); break; case TAG_cmt3: - parseTiff(Internal::Tag::cmt3, box.length); + parseTiff(Internal::Tag::cmt3, box_length); break; case TAG_cmt4: - parseTiff(Internal::Tag::cmt4, box.length); + parseTiff(Internal::Tag::cmt4, box_length); break; case TAG_exif: - parseTiff(Internal::Tag::root, box.length,address+8); + parseTiff(Internal::Tag::root, box_length,address+8); break; case TAG_xml: - parseXmp(box.length,io_->tell()); + parseXmp(box_length,io_->tell()); break; default: break ; /* do nothing */ @@ -477,17 +463,19 @@ namespace Exiv2 if ( bLF&& bTrace) out << std::endl; // return address of next box - result = (address + box.length); + result = (address + box_length); return result; } - void BmffImage::parseTiff(uint32_t root_tag, uint32_t length,uint32_t start) + void BmffImage::parseTiff(uint32_t root_tag, uint64_t length,uint64_t start) { // read and parse exif data long restore = io_->tell(); - DataBuf exif(length); - io_->seek(start,BasicIo::beg); + enforce(length <= std::numeric_limits::max(), kerCorruptedMetadata); + DataBuf exif(static_cast(length)); + enforce(start <= std::numeric_limits::max(), kerCorruptedMetadata); + io_->seek(static_cast(start),BasicIo::beg); if ( exif.size_ > 8 && io_->read(exif.pData_,exif.size_) == exif.size_ ) { // hunt for "II" or "MM" long eof = 0xffffffff; // impossible value for punt @@ -506,10 +494,11 @@ namespace Exiv2 io_->seek(restore,BasicIo::beg); } - void BmffImage::parseTiff(uint32_t root_tag, uint32_t length) + void BmffImage::parseTiff(uint32_t root_tag, uint64_t length) { if (length > 8) { - DataBuf data(length - 8); + enforce(length - 8 <= std::numeric_limits::max(), kerCorruptedMetadata); + DataBuf data(static_cast(length - 8)); long bufRead = io_->read(data.pData_, data.size_); if (io_->error()) @@ -523,15 +512,17 @@ namespace Exiv2 } } - void BmffImage::parseXmp(uint32_t length,uint32_t start) + void BmffImage::parseXmp(uint64_t length,uint64_t start) { if (length > 8) { long restore = io_->tell() ; - io_->seek(start,BasicIo::beg); + enforce(start <= std::numeric_limits::max(), kerCorruptedMetadata); + io_->seek(static_cast(start),BasicIo::beg); - DataBuf xmp(length+1); + enforce(length < std::numeric_limits::max(), kerCorruptedMetadata); + DataBuf xmp(static_cast(length+1)); xmp.pData_[length]=0 ; // ensure xmp is null terminated! - if ( io_->read(xmp.pData_, length) != length ) + if ( io_->read(xmp.pData_, length) != static_cast(length) ) throw Error(kerInputDataReadFailed); if ( io_->error() ) throw Error(kerFailedToReadImageData);