MP4: reject undersized table atoms (#1390)

MP4 chapter parsing subtracted table headers from atom lengths without
checking that the headers were present. A short atom could wrap the
read length and allocate the remainder of a large file.

Validate table sizes before reading their payloads and before updating
chunk offsets while saving.
This commit is contained in:
Acts1631
2026-08-02 16:47:17 +02:00
committed by GitHub
parent 04993427d7
commit fd97c86bcb
3 changed files with 30 additions and 4 deletions
+6
View File
@@ -77,6 +77,8 @@ namespace
for(const auto &atom : stco) {
if(atom->offset() > offset)
atom->addToOffset(delta);
if(atom->length() < 16)
continue;
file->seek(atom->offset() + 12);
ByteVector data = file->readBlock(atom->length() - 12);
unsigned int count = data.toUInt();
@@ -96,6 +98,8 @@ namespace
for(const auto &atom : co64) {
if(atom->offset() > offset)
atom->addToOffset(delta);
if(atom->length() < 20)
continue;
file->seek(atom->offset() + 12);
ByteVector data = file->readBlock(atom->length() - 12);
unsigned int count = data.toUInt();
@@ -117,6 +121,8 @@ namespace
for(const auto &atom : tfhd) {
if(atom->offset() > offset)
atom->addToOffset(delta);
if(atom->length() < 24)
continue;
file->seek(atom->offset() + 9);
ByteVector data = file->readBlock(atom->length() - 9);
if(const unsigned int flags = data.toUInt(0, 3, true);
+15 -4
View File
@@ -88,6 +88,8 @@ namespace
for(const auto &atom : stco) {
if(atom->offset() > offset)
atom->addToOffset(delta);
if(atom->length() < 16)
continue;
file->seek(atom->offset() + 12);
ByteVector data = file->readBlock(atom->length() - 12);
unsigned int count = data.toUInt();
@@ -107,6 +109,8 @@ namespace
for(const auto &atom : co64) {
if(atom->offset() > offset)
atom->addToOffset(delta);
if(atom->length() < 20)
continue;
file->seek(atom->offset() + 12);
ByteVector data = file->readBlock(atom->length() - 12);
unsigned int count = data.toUInt();
@@ -128,6 +132,8 @@ namespace
for(const auto &atom : tfhd) {
if(atom->offset() > offset)
atom->addToOffset(delta);
if(atom->length() < 24)
continue;
file->seek(atom->offset() + 9);
ByteVector data = file->readBlock(atom->length() - 9);
if(const unsigned int flags = data.toUInt(0, 3, true);
@@ -740,7 +746,7 @@ namespace
{
std::vector<SttsEntry> entries;
const MP4::Atom *stts = chapterTrak->find("mdia", "minf", "stbl", "stts");
if(!stts)
if(!stts || stts->length() < 12)
return entries;
file->seek(stts->offset() + 12); // skip header(8) + version/flags(4)
@@ -765,7 +771,7 @@ namespace
{
std::vector<unsigned int> offsets;
const MP4::Atom *stco = chapterTrak->find("mdia", "minf", "stbl", "stco");
if(!stco)
if(!stco || stco->length() < 12)
return offsets;
file->seek(stco->offset() + 12);
@@ -794,7 +800,7 @@ namespace
{
SampleSizeInfo info;
const MP4::Atom *stsz = chapterTrak->find("mdia", "minf", "stbl", "stsz");
if(!stsz)
if(!stsz || stsz->length() < 12)
return info;
file->seek(stsz->offset() + 12);
@@ -837,7 +843,8 @@ namespace
};
std::vector<StscEntry> stscEntries;
if(const MP4::Atom *stsc = chapterTrak->find("mdia", "minf", "stbl", "stsc")) {
if(const MP4::Atom *stsc = chapterTrak->find("mdia", "minf", "stbl", "stsc");
stsc && stsc->length() >= 12) {
file->seek(stsc->offset() + 12);
if(const ByteVector data = file->readBlock(stsc->length() - 12);
data.size() >= 4) {
@@ -969,6 +976,8 @@ namespace
return false;
for(const auto &stco : moov->findall("stco", true)) {
if(stco->length() < 16)
continue;
file->seek(stco->offset() + 12);
ByteVector data = file->readBlock(stco->length() - 12);
if(data.size() < 4)
@@ -985,6 +994,8 @@ namespace
}
for(const auto &co64 : moov->findall("co64", true)) {
if(co64->length() < 20)
continue;
file->seek(co64->offset() + 12);
ByteVector data = file->readBlock(co64->length() - 12);
if(data.size() < 4)
+9
View File
@@ -195,6 +195,9 @@ MP4::Tag::updateOffsets(offset_t delta, offset_t offset)
if(atom->offset() > offset) {
atom->addToOffset(delta);
}
if(atom->length() < 16) {
continue;
}
d->file->seek(atom->offset() + 12);
ByteVector data = d->file->readBlock(atom->length() - 12);
unsigned int count = data.toUInt();
@@ -216,6 +219,9 @@ MP4::Tag::updateOffsets(offset_t delta, offset_t offset)
if(atom->offset() > offset) {
atom->addToOffset(delta);
}
if(atom->length() < 20) {
continue;
}
d->file->seek(atom->offset() + 12);
ByteVector data = d->file->readBlock(atom->length() - 12);
unsigned int count = data.toUInt();
@@ -239,6 +245,9 @@ MP4::Tag::updateOffsets(offset_t delta, offset_t offset)
if(atom->offset() > offset) {
atom->addToOffset(delta);
}
if(atom->length() < 24) {
continue;
}
d->file->seek(atom->offset() + 9);
ByteVector data = d->file->readBlock(atom->length() - 9);
if(const unsigned int flags = data.toUInt(0, 3, true);