mirror of
https://github.com/taglib/taglib.git
synced 2026-07-12 22:31:35 -04:00
[Matroska] Check element length before constructing
By checking the Element size against the maximum offset we can find out of bounds elements early and not try to read them at all. This is useful for the next patch. Signed-off-by: Anthony Brandon <anthony.brandon@gmail.com>
This commit is contained in:
committed by
Urs Fleisch
parent
2185b47d5f
commit
13239fde26
@@ -41,7 +41,7 @@ using namespace TagLib;
|
||||
#define RETURN_ELEMENT_FOR_CASE(eid) \
|
||||
case (eid): return make_unique_element<eid>(id, sizeLength, dataSize, offset)
|
||||
|
||||
std::unique_ptr<EBML::Element> EBML::Element::factory(File &file)
|
||||
std::unique_ptr<EBML::Element> EBML::Element::factory(File &file, offset_t maxOffset)
|
||||
{
|
||||
// Get the element ID
|
||||
const offset_t offset = file.tell();
|
||||
@@ -56,6 +56,13 @@ std::unique_ptr<EBML::Element> EBML::Element::factory(File &file)
|
||||
if(!sizeLength)
|
||||
return nullptr;
|
||||
|
||||
if(const offset_t currentOffset = file.tell();
|
||||
static_cast<offset_t>(dataSize) > maxOffset - currentOffset) {
|
||||
debug(Utils::formatString("EBML: datasize too great: %lu > (%lld - %lld)",
|
||||
dataSize, maxOffset, currentOffset));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Return the subclass
|
||||
// The enum switch without default will give us a warning if an ID is missing
|
||||
auto id = static_cast<Id>(uintId);
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace TagLib
|
||||
int64_t getDataSize() const;
|
||||
ByteVector renderId() const;
|
||||
virtual ByteVector render();
|
||||
static std::unique_ptr<Element> factory(File &file);
|
||||
static std::unique_ptr<Element> factory(File &file, offset_t maxOffset);
|
||||
static unsigned int readId(File &file);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -45,7 +45,7 @@ std::unique_ptr<ElementType> readElementAt(File &file,
|
||||
}
|
||||
|
||||
file.seek(offset);
|
||||
auto element = EBML::Element::factory(file);
|
||||
auto element = EBML::Element::factory(file, maxOffset);
|
||||
if(!element || element->getId() != Id) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ std::unique_ptr<EBML::Element> EBML::findElement(File &file, Element::Id id, off
|
||||
{
|
||||
std::unique_ptr<Element> element;
|
||||
while(file.tell() < maxOffset) {
|
||||
element = Element::factory(file);
|
||||
element = Element::factory(file, maxOffset);
|
||||
if(!element || element->getId() == id)
|
||||
return element;
|
||||
element->skipData(file);
|
||||
@@ -45,7 +45,7 @@ std::unique_ptr<EBML::Element> EBML::findElement(File &file, Element::Id id, off
|
||||
|
||||
std::unique_ptr<EBML::Element> EBML::findNextElement(File &file, offset_t maxOffset)
|
||||
{
|
||||
return file.tell() < maxOffset ? Element::factory(file) : nullptr;
|
||||
return file.tell() < maxOffset ? Element::factory(file, maxOffset) : nullptr;
|
||||
}
|
||||
|
||||
template <int maxSizeLength>
|
||||
|
||||
@@ -368,7 +368,7 @@ void Matroska::File::read(bool readProperties, Properties::ReadStyle readStyle)
|
||||
|
||||
// Find the EBML Header
|
||||
const auto head = EBML::element_cast<EBML::Element::Id::EBMLHeader>(
|
||||
EBML::Element::factory(*this));
|
||||
EBML::Element::factory(*this, fileLength));
|
||||
if(!head || head->getId() != EBML::Element::Id::EBMLHeader) {
|
||||
debug("Failed to find EBML head");
|
||||
setValid(false);
|
||||
@@ -381,7 +381,7 @@ void Matroska::File::read(bool readProperties, Properties::ReadStyle readStyle)
|
||||
head->skipData(*this);
|
||||
}
|
||||
|
||||
offset_t maxOffset = fileLength - tell();
|
||||
offset_t maxOffset = fileLength;
|
||||
if (readStyle == Properties::ReadStyle::Fast && maxOffset > FAST_SCAN_LIMIT) {
|
||||
maxOffset = FAST_SCAN_LIMIT;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user