Fix data length indicator check for compressed ID3v2 frames (#1371)

This commit is contained in:
Urs Fleisch
2026-06-26 09:39:27 +02:00
committed by GitHub
parent e958fa0bfa
commit fa189f6cf7
6 changed files with 25 additions and 5 deletions

View File

@@ -295,7 +295,8 @@ ByteVector Frame::fieldData(const ByteVector &frameData) const
frameDataLength = SynchData::toUInt(frameData.mid(headerSize, 4));
frameDataOffset += 4;
}
if(frameData.size() >= headerSize &&
if(!d->header->compression() &&
frameData.size() >= headerSize &&
frameDataOffset + frameDataLength > frameData.size()) {
// The first check is needed because some "dual purpose" frame constructors
// call this method with only the frame ID, i.e. without a complete header.
@@ -309,7 +310,8 @@ ByteVector Frame::fieldData(const ByteVector &frameData) const
return ByteVector();
}
const ByteVector outData = zlib::decompress(frameData.mid(frameDataOffset));
const ByteVector outData = zlib::decompress(frameData.mid(frameDataOffset),
frameDataLength);
if(!outData.isEmpty() && frameDataLength != outData.size()) {
debug("frameDataLength does not match the data length returned by zlib");
}

View File

@@ -24,6 +24,7 @@
***************************************************************************/
#include "tzlib.h"
#include <climits>
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -50,7 +51,8 @@ bool zlib::isAvailable()
#endif
}
ByteVector zlib::decompress([[maybe_unused]] const ByteVector &data)
ByteVector zlib::decompress([[maybe_unused]] const ByteVector &data,
unsigned int maxLength)
{
#ifdef HAVE_ZLIB
@@ -90,6 +92,12 @@ ByteVector zlib::decompress([[maybe_unused]] const ByteVector &data)
}
outData.resize(outData.size() - stream.avail_out);
if(outData.size() > maxLength && maxLength != UINT_MAX) {
debug("zlib::decompress() - Too long compressed stream.");
outData.resize(maxLength);
break;
}
} while(stream.avail_out == 0);
inflateEnd(&stream);
@@ -102,3 +110,8 @@ ByteVector zlib::decompress([[maybe_unused]] const ByteVector &data)
#endif
}
ByteVector zlib::decompress([[maybe_unused]] const ByteVector &data)
{
return decompress(data, UINT_MAX);
}

View File

@@ -46,6 +46,11 @@ namespace TagLib {
*/
ByteVector decompress(const ByteVector &data);
/*!
* Decompress \a data by zlib, at most \a maxLength bytes.
*/
ByteVector decompress(const ByteVector &data, unsigned int maxLength);
} // namespace zlib
} // namespace TagLib

Binary file not shown.

Binary file not shown.

View File

@@ -1121,7 +1121,7 @@ public:
void testCompressedFrameWithBrokenLength()
{
MPEG::File f(TEST_FILE_PATH_C("compressed_id3_frame.mp3"), false);
MPEG::File f(TEST_FILE_PATH_C("compressed_id3_frame_invalid.mp3"), false);
CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("APIC"));
if(zlib::isAvailable()) {
@@ -1132,7 +1132,7 @@ public:
CPPUNIT_ASSERT_EQUAL(String("image/bmp"), frame->mimeType());
CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::Other, frame->type());
CPPUNIT_ASSERT_EQUAL(String(""), frame->description());
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(86414), frame->picture().size());
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(142), frame->picture().size());
}
else {
// Skip the test if ZLIB is not installed.