From 8fe8b8235b857fcaee6d16a9561e9659c5628fe4 Mon Sep 17 00:00:00 2001 From: Acts1631 <69813585+acts-1631@users.noreply.github.com> Date: Wed, 4 Nov 2026 11:17:34 -0500 Subject: [PATCH] Prevent FLAC picture length overflows (#1492) FLAC picture string and data lengths were checked with addition. On 32-bit builds, crafted lengths can wrap the cursor and cause a four-byte read before the ByteVector allocation. Use remaining-length checks in Picture::parse and make fixed-width ByteVector conversions reject offsets at or beyond the buffer. --- taglib/flac/flacpicture.cpp | 6 +++--- taglib/toolkit/tbytevector.cpp | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/taglib/flac/flacpicture.cpp b/taglib/flac/flacpicture.cpp index 73abd343..25b1ed20 100644 --- a/taglib/flac/flacpicture.cpp +++ b/taglib/flac/flacpicture.cpp @@ -72,7 +72,7 @@ bool FLAC::Picture::parse(const ByteVector &data) pos += 4; unsigned int mimeTypeLength = data.toUInt(pos); pos += 4; - if(pos + mimeTypeLength + 24 > data.size()) { + if(mimeTypeLength > data.size() - pos - 24) { debug("Invalid picture block."); return false; } @@ -80,7 +80,7 @@ bool FLAC::Picture::parse(const ByteVector &data) pos += mimeTypeLength; unsigned int descriptionLength = data.toUInt(pos); pos += 4; - if(pos + descriptionLength + 20 > data.size()) { + if(descriptionLength > data.size() - pos - 20) { debug("Invalid picture block."); return false; } @@ -96,7 +96,7 @@ bool FLAC::Picture::parse(const ByteVector &data) pos += 4; unsigned int dataLength = data.toUInt(pos); pos += 4; - if(pos + dataLength > data.size()) { + if(dataLength > data.size() - pos) { debug("Invalid picture block."); return false; } diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 6dd30dd7..874d46ea 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -134,8 +134,12 @@ T toNumber(const ByteVector &v, size_t offset, bool mostSignificantByteFirst) const bool isBigEndian = Utils::systemByteOrder() == Utils::BigEndian; const bool swap = mostSignificantByteFirst != isBigEndian; - if(offset + sizeof(T) > v.size()) - return toNumber(v, offset, v.size() - offset, mostSignificantByteFirst); + if(offset >= v.size()) + return toNumber(v, offset, 0, mostSignificantByteFirst); + + const size_t remaining = v.size() - offset; + if(sizeof(T) > remaining) + return toNumber(v, offset, remaining, mostSignificantByteFirst); // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. T tmp;