diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index ae69ac1b..a496302f 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -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"); } diff --git a/taglib/toolkit/tzlib.cpp b/taglib/toolkit/tzlib.cpp index 2e055b8b..5172c916 100644 --- a/taglib/toolkit/tzlib.cpp +++ b/taglib/toolkit/tzlib.cpp @@ -24,6 +24,7 @@ ***************************************************************************/ #include "tzlib.h" +#include #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); +} diff --git a/taglib/toolkit/tzlib.h b/taglib/toolkit/tzlib.h index 38df4c73..7601c625 100644 --- a/taglib/toolkit/tzlib.h +++ b/taglib/toolkit/tzlib.h @@ -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 diff --git a/tests/data/compressed_id3_frame.mp3 b/tests/data/compressed_id3_frame.mp3 index 824d036f..15a7c6f4 100644 Binary files a/tests/data/compressed_id3_frame.mp3 and b/tests/data/compressed_id3_frame.mp3 differ diff --git a/tests/data/compressed_id3_frame_invalid.mp3 b/tests/data/compressed_id3_frame_invalid.mp3 new file mode 100644 index 00000000..824d036f Binary files /dev/null and b/tests/data/compressed_id3_frame_invalid.mp3 differ diff --git a/tests/test_id3v2.cpp b/tests/test_id3v2.cpp index cac2b952..9087b54e 100644 --- a/tests/test_id3v2.cpp +++ b/tests/test_id3v2.cpp @@ -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(86414), frame->picture().size()); + CPPUNIT_ASSERT_EQUAL(static_cast(142), frame->picture().size()); } else { // Skip the test if ZLIB is not installed.