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()
method to get a temporary reference.
*/
explicit QuickTimeVideo(BasicIo::UniquePtr io);
explicit QuickTimeVideo(BasicIo::UniquePtr io, size_t max_recursion_depth = 1000);
//@}
//! @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
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
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 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:
/*!
@ -123,7 +123,7 @@ class EXIV2API QuickTimeVideo : public Image {
@brief Interpret Tag which contain other sub-tags,
and save it in the respective XMP container.
*/
void multipleEntriesDecoder();
void multipleEntriesDecoder(size_t recursion_depth);
/*!
@brief Interpret Sample Description Tag, and save it
in the respective XMP container.
@ -140,7 +140,7 @@ class EXIV2API QuickTimeVideo : public Image {
in the respective XMP container.
@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
in the respective XMP container.
@ -202,6 +202,8 @@ class EXIV2API QuickTimeVideo : public Image {
//! Variable to store height and width of a video frame.
uint64_t height_ = 0;
uint64_t width_ = 0;
//! Prevent stack exhaustion due to excessively deep recursion.
const size_t max_recursion_depth_;
}; // QuickTimeVideo End

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

Loading…
Cancel
Save