Add `recursion_depth` parameter to ensure that the recursion doesn't go too deep.
main
Kevin Backhouse 1 year ago
parent d748390cc0
commit 99ee18cef7
No known key found for this signature in database
GPG Key ID: 9DD01852EE40366E

@ -52,7 +52,7 @@ class EXIV2API QuickTimeVideo : public Image {
instance after it is passed to this method. Use the Image::io() instance after it is passed to this method. Use the Image::io()
method to get a temporary reference. method to get a temporary reference.
*/ */
explicit QuickTimeVideo(BasicIo::UniquePtr io); explicit QuickTimeVideo(BasicIo::UniquePtr io, size_t max_recursion_depth = 1000);
//@} //@}
//! @name Manipulators //! @name Manipulators
@ -71,7 +71,7 @@ class EXIV2API QuickTimeVideo : public Image {
@brief Check for a valid tag and decode the block at the current IO @brief Check for a valid tag and decode the block at the current IO
position. Calls tagDecoder() or skips to next tag, if required. position. Calls tagDecoder() or skips to next tag, if required.
*/ */
void decodeBlock(std::string const& entered_from = ""); void decodeBlock(size_t recursion_depth, std::string const& entered_from = "");
/*! /*!
@brief Interpret tag information, and call the respective function @brief Interpret tag information, and call the respective function
to save it in the respective XMP container. Decodes a Tag to save it in the respective XMP container. Decodes a Tag
@ -80,7 +80,7 @@ class EXIV2API QuickTimeVideo : public Image {
@param buf Data buffer which contains tag ID. @param buf Data buffer which contains tag ID.
@param size Size of the data block used to store Tag Information. @param size Size of the data block used to store Tag Information.
*/ */
void tagDecoder(Exiv2::DataBuf& buf, size_t size); void tagDecoder(Exiv2::DataBuf& buf, size_t size, size_t recursion_depth);
private: private:
/*! /*!
@ -123,7 +123,7 @@ class EXIV2API QuickTimeVideo : public Image {
@brief Interpret Tag which contain other sub-tags, @brief Interpret Tag which contain other sub-tags,
and save it in the respective XMP container. and save it in the respective XMP container.
*/ */
void multipleEntriesDecoder(); void multipleEntriesDecoder(size_t recursion_depth);
/*! /*!
@brief Interpret Sample Description Tag, and save it @brief Interpret Sample Description Tag, and save it
in the respective XMP container. in the respective XMP container.
@ -140,7 +140,7 @@ class EXIV2API QuickTimeVideo : public Image {
in the respective XMP container. in the respective XMP container.
@param size Size of the data block used to store Tag Information. @param size Size of the data block used to store Tag Information.
*/ */
void userDataDecoder(size_t size); void userDataDecoder(size_t size, size_t recursion_depth);
/*! /*!
@brief Interpret Preview Tag, and save it @brief Interpret Preview Tag, and save it
in the respective XMP container. in the respective XMP container.
@ -202,6 +202,8 @@ class EXIV2API QuickTimeVideo : public Image {
//! Variable to store height and width of a video frame. //! Variable to store height and width of a video frame.
uint64_t height_ = 0; uint64_t height_ = 0;
uint64_t width_ = 0; uint64_t width_ = 0;
//! Prevent stack exhaustion due to excessively deep recursion.
const size_t max_recursion_depth_;
}; // QuickTimeVideo End }; // QuickTimeVideo End

@ -538,8 +538,11 @@ namespace Exiv2 {
using namespace Exiv2::Internal; using namespace Exiv2::Internal;
QuickTimeVideo::QuickTimeVideo(BasicIo::UniquePtr io) : QuickTimeVideo::QuickTimeVideo(BasicIo::UniquePtr io, size_t max_recursion_depth) :
Image(ImageType::qtime, mdNone, std::move(io)), timeScale_(1), currentStream_(Null) { Image(ImageType::qtime, mdNone, std::move(io)),
timeScale_(1),
currentStream_(Null),
max_recursion_depth_(max_recursion_depth) {
} // QuickTimeVideo::QuickTimeVideo } // QuickTimeVideo::QuickTimeVideo
std::string QuickTimeVideo::mimeType() const { std::string QuickTimeVideo::mimeType() const {
@ -569,12 +572,14 @@ void QuickTimeVideo::readMetadata() {
xmpData_["Xmp.video.MimeType"] = mimeType(); xmpData_["Xmp.video.MimeType"] = mimeType();
while (continueTraversing_) while (continueTraversing_)
decodeBlock(); decodeBlock(0);
xmpData_["Xmp.video.AspectRatio"] = getAspectRatio(width_, height_); xmpData_["Xmp.video.AspectRatio"] = getAspectRatio(width_, height_);
} // QuickTimeVideo::readMetadata } // QuickTimeVideo::readMetadata
void QuickTimeVideo::decodeBlock(std::string const& entered_from) { void QuickTimeVideo::decodeBlock(size_t recursion_depth, std::string const& entered_from) {
enforce(recursion_depth < max_recursion_depth_, Exiv2::ErrorCode::kerCorruptedMetadata);
const long bufMinSize = 4; const long bufMinSize = 4;
DataBuf buf(bufMinSize + 1); DataBuf buf(bufMinSize + 1);
uint64_t size = 0; uint64_t size = 0;
@ -613,7 +618,7 @@ void QuickTimeVideo::decodeBlock(std::string const& entered_from) {
if (newsize > buf.size()) { if (newsize > buf.size()) {
buf.resize(newsize); buf.resize(newsize);
} }
tagDecoder(buf, newsize); tagDecoder(buf, newsize, recursion_depth + 1);
} // QuickTimeVideo::decodeBlock } // QuickTimeVideo::decodeBlock
static std::string readString(BasicIo& io, size_t size) { static std::string readString(BasicIo& io, size_t size) {
@ -624,14 +629,15 @@ static std::string readString(BasicIo& io, size_t size) {
return Exiv2::toString(str.data()); return Exiv2::toString(str.data());
} }
void QuickTimeVideo::tagDecoder(Exiv2::DataBuf& buf, size_t size) { void QuickTimeVideo::tagDecoder(Exiv2::DataBuf& buf, size_t size, size_t recursion_depth) {
enforce(recursion_depth < max_recursion_depth_, Exiv2::ErrorCode::kerCorruptedMetadata);
assert(buf.size() > 4); assert(buf.size() > 4);
if (ignoreList(buf)) if (ignoreList(buf))
discard(size); discard(size);
else if (dataIgnoreList(buf)) { else if (dataIgnoreList(buf)) {
decodeBlock(Exiv2::toString(buf.data())); decodeBlock(recursion_depth + 1, Exiv2::toString(buf.data()));
} else if (equalsQTimeTag(buf, "ftyp")) } else if (equalsQTimeTag(buf, "ftyp"))
fileTypeDecoder(size); fileTypeDecoder(size);
@ -654,10 +660,10 @@ void QuickTimeVideo::tagDecoder(Exiv2::DataBuf& buf, size_t size) {
videoHeaderDecoder(size); videoHeaderDecoder(size);
else if (equalsQTimeTag(buf, "udta")) else if (equalsQTimeTag(buf, "udta"))
userDataDecoder(size); userDataDecoder(size, recursion_depth + 1);
else if (equalsQTimeTag(buf, "dref")) else if (equalsQTimeTag(buf, "dref"))
multipleEntriesDecoder(); multipleEntriesDecoder(recursion_depth + 1);
else if (equalsQTimeTag(buf, "stsd")) else if (equalsQTimeTag(buf, "stsd"))
sampleDesc(size); sampleDesc(size);
@ -836,7 +842,8 @@ void QuickTimeVideo::CameraTagsDecoder(size_t size_external) {
io_->seek(cur_pos + size_external, BasicIo::beg); io_->seek(cur_pos + size_external, BasicIo::beg);
} // QuickTimeVideo::CameraTagsDecoder } // QuickTimeVideo::CameraTagsDecoder
void QuickTimeVideo::userDataDecoder(size_t size_external) { void QuickTimeVideo::userDataDecoder(size_t size_external, size_t recursion_depth) {
enforce(recursion_depth < max_recursion_depth_, Exiv2::ErrorCode::kerCorruptedMetadata);
size_t cur_pos = io_->tell(); size_t cur_pos = io_->tell();
const TagVocabulary* td; const TagVocabulary* td;
const TagVocabulary* tv; const TagVocabulary* tv;
@ -866,7 +873,7 @@ void QuickTimeVideo::userDataDecoder(size_t size_external) {
break; break;
if (equalsQTimeTag(buf, "DcMD") || equalsQTimeTag(buf, "NCDT")) if (equalsQTimeTag(buf, "DcMD") || equalsQTimeTag(buf, "NCDT"))
userDataDecoder(size - 8); userDataDecoder(size - 8, recursion_depth + 1);
else if (equalsQTimeTag(buf, "NCTG")) else if (equalsQTimeTag(buf, "NCTG"))
NikonTagsDecoder(size - 8); NikonTagsDecoder(size - 8);
@ -898,7 +905,7 @@ void QuickTimeVideo::userDataDecoder(size_t size_external) {
} }
else if (td) else if (td)
tagDecoder(buf, size - 8); tagDecoder(buf, size - 8, recursion_depth + 1);
} }
io_->seek(cur_pos + size_external, BasicIo::beg); io_->seek(cur_pos + size_external, BasicIo::beg);
@ -1272,7 +1279,8 @@ void QuickTimeVideo::imageDescDecoder() {
xmpData_["Xmp.video.BitDepth"] = static_cast<int>(buf.read_uint8(0)); xmpData_["Xmp.video.BitDepth"] = static_cast<int>(buf.read_uint8(0));
} // QuickTimeVideo::imageDescDecoder } // QuickTimeVideo::imageDescDecoder
void QuickTimeVideo::multipleEntriesDecoder() { void QuickTimeVideo::multipleEntriesDecoder(size_t recursion_depth) {
enforce(recursion_depth < max_recursion_depth_, Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf buf(4 + 1); DataBuf buf(4 + 1);
io_->readOrThrow(buf.data(), 4); io_->readOrThrow(buf.data(), 4);
io_->readOrThrow(buf.data(), 4); io_->readOrThrow(buf.data(), 4);
@ -1281,7 +1289,7 @@ void QuickTimeVideo::multipleEntriesDecoder() {
noOfEntries = buf.read_uint32(0, bigEndian); noOfEntries = buf.read_uint32(0, bigEndian);
for (uint32_t i = 0; i < noOfEntries && continueTraversing_; i++) { for (uint32_t i = 0; i < noOfEntries && continueTraversing_; i++) {
decodeBlock(); decodeBlock(recursion_depth + 1);
} }
} // QuickTimeVideo::multipleEntriesDecoder } // QuickTimeVideo::multipleEntriesDecoder

Loading…
Cancel
Save