From 0a3deeac75618c4820f04aff270fa62a27c48682 Mon Sep 17 00:00:00 2001 From: Acts1631 <69813585+acts-1631@users.noreply.github.com> Date: Thu, 20 Aug 2026 23:43:54 -0400 Subject: [PATCH] Reject QuickTime chapter samples outside their data bounds (#1427) A malformed QuickTime chapter track can set stsz's default sample size to a value larger than the available sample data. MP4::File::qtChapters() passes that value through QtChapterList::read() to readTextSample(), allowing a small file to cause gigabytes of allocations and terminate the application. Check each resolved sample against the file end and the next sample offset before reading it. Samples that do not fit are rejected without allocating the attacker-controlled size. --- taglib/mp4/mp4qtchapterlist.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/taglib/mp4/mp4qtchapterlist.cpp b/taglib/mp4/mp4qtchapterlist.cpp index 0573c283..98572ce3 100644 --- a/taglib/mp4/mp4qtchapterlist.cpp +++ b/taglib/mp4/mp4qtchapterlist.cpp @@ -991,6 +991,25 @@ namespace return String(data.mid(2, textLen), String::UTF8); } + bool sampleFits(TagLib::File *file, const std::vector &offsets, + unsigned int sampleIndex, unsigned int sampleSize) + { + const offset_t offset = offsets[sampleIndex]; + const offset_t fileLength = file->length(); + if(offset < 0 || offset > fileLength || + static_cast(sampleSize) > fileLength - offset) + return false; + + if(sampleIndex + 1 < offsets.size()) { + const offset_t nextOffset = offsets[sampleIndex + 1]; + if(nextOffset <= offset || + static_cast(sampleSize) > nextOffset - offset) + return false; + } + + return true; + } + // -- Remove helpers ------------------------------------------------------- //! Removes the tref atom from the audio track. @@ -1250,6 +1269,9 @@ bool MP4::QtChapterList::read(TagLib::File *file) if(sampleSize == 0 && sampleIndex < sizeInfo.perSampleSizes.size()) sampleSize = sizeInfo.perSampleSizes[sampleIndex]; + if(!sampleFits(file, offsets, sampleIndex, sampleSize)) + return false; + String title = readTextSample(file, offsets[sampleIndex], sampleSize); const auto startTimeMs = static_cast(