From 0a13a11bad3c9c9a2a6f88db2981ccbfcad43bb0 Mon Sep 17 00:00:00 2001 From: Acts1631 <69813585+acts-1631@users.noreply.github.com> Date: Tue, 18 Aug 2026 01:07:33 -0400 Subject: [PATCH] Xiph: bound comment field lengths (#1424) Xiph comment lengths are read from the file. Without checking them against the remaining packet, a wrapped length can reset the parser position and make each field iteration copy the same payload. Reject truncated vendor and field data before advancing the parser. --- taglib/ogg/xiphcomment.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/taglib/ogg/xiphcomment.cpp b/taglib/ogg/xiphcomment.cpp index 8218b7aa..8efc06c5 100644 --- a/taglib/ogg/xiphcomment.cpp +++ b/taglib/ogg/xiphcomment.cpp @@ -427,14 +427,28 @@ void Ogg::XiphComment::parse(const ByteVector &data) // The first thing in the comment data is the vendor ID length, followed by a // UTF8 string with the vendor ID. + if(data.size() < 8) { + debug("Ogg::XiphComment::parse() - Comment data is too short."); + return; + } + unsigned int pos = 0; const unsigned int vendorLength = data.toUInt(0, false); pos += 4; + if(vendorLength > data.size() - pos) { + debug("Ogg::XiphComment::parse() - Vendor ID exceeds comment data."); + return; + } d->vendorID = String(data.mid(pos, vendorLength), String::UTF8); pos += vendorLength; + if(data.size() - pos < 4) { + debug("Ogg::XiphComment::parse() - Missing comment field count."); + return; + } + // Next the number of fields in the comment vector. const unsigned int commentFields = data.toUInt(pos, false); @@ -451,17 +465,18 @@ void Ogg::XiphComment::parse(const ByteVector &data) // Each comment field is in the format "KEY=value" in a UTF8 string and has // 4 bytes before the text starts that gives the length. + if(data.size() - pos < 4) + break; + const unsigned int commentLength = data.toUInt(pos, false); pos += 4; + if(commentLength > data.size() - pos) + break; + const ByteVector entry = data.mid(pos, commentLength); pos += commentLength; - // Don't go past data end - - if(pos > data.size()) - break; - // Check for field separator const int sep = entry.find('=');