Fix unbounded recursion in EBML/Matroska MasterElement and MP4 atoms (#1326)

Credits for fix and reporting go to https://github.com/ericliu-12.
This commit is contained in:
Urs Fleisch
2026-04-08 20:52:58 +02:00
committed by GitHub
parent 5d63187a8b
commit 193091fe2e
4 changed files with 37 additions and 5 deletions

View File

@ -21,6 +21,7 @@
#include "ebmlmasterelement.h"
#include "ebmlvoidelement.h"
#include "ebmlutils.h"
#include "tdebug.h"
#include "tfile.h"
using namespace TagLib;
@ -97,18 +98,34 @@ void EBML::MasterElement::setMinRenderSize(offset_t minimumSize)
minRenderSize = minimumSize;
}
bool EBML::MasterElement::read(File &file)
bool EBML::MasterElement::read(File &file, int depth)
{
static constexpr int MAX_EBML_DEPTH = 64;
if(depth > MAX_EBML_DEPTH) {
debug("EBML: Maximum nesting depth exceeded");
return false;
}
const offset_t maxOffset = file.tell() + dataSize;
std::unique_ptr<Element> element;
while((element = findNextElement(file, maxOffset))) {
if(!element->read(file))
return false;
if(auto master = dynamic_cast<MasterElement *>(element.get())) {
if(!master->read(file, depth + 1))
return false;
}
else {
if(!element->read(file))
return false;
}
elements.push_back(std::move(element));
}
return file.tell() == maxOffset;
}
bool EBML::MasterElement::read(File &file)
{
return read(file, 0);
}
ByteVector EBML::MasterElement::render()
{
ByteVector buffer = renderId();

View File

@ -55,6 +55,8 @@ namespace TagLib
void setMinRenderSize(offset_t minimumSize);
protected:
bool read(File &file, int depth);
offset_t offset;
offset_t padding = 0;
offset_t minRenderSize = 0;

View File

@ -51,7 +51,7 @@ public:
AtomList children;
};
MP4::Atom::Atom(File *file)
MP4::Atom::Atom(File *file, int depth)
: d(std::make_unique<AtomPrivate>(file->tell()))
{
d->children.setAutoDelete(true);
@ -109,8 +109,13 @@ MP4::Atom::Atom(File *file)
else if(d->name == "stsd") {
file->seek(8, File::Current);
}
static constexpr int MAX_MP4_ATOM_DEPTH = 64;
if(depth > MAX_MP4_ATOM_DEPTH) {
debug("MP4: Maximum nesting depth exceeded");
return;
}
while(file->tell() < d->offset + d->length) {
auto child = new MP4::Atom(file);
auto child = new MP4::Atom(file, depth + 1);
d->children.append(child);
if(child->d->length == 0)
return;
@ -122,6 +127,11 @@ MP4::Atom::Atom(File *file)
file->seek(d->offset + d->length);
}
MP4::Atom::Atom(File *file)
: Atom(file, 0)
{
}
MP4::Atom::~Atom() = default;
MP4::Atom *

View File

@ -89,6 +89,9 @@ namespace TagLib {
const ByteVector &name() const;
const AtomList &children() const;
protected:
Atom(File *file, int depth);
private:
class AtomPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE