From be9b5cc93a3535023fc2bacc1f3dda3364c83bf0 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 8 Dec 2015 11:11:50 +0900 Subject: [PATCH] More robust checks for invalid MPEG frame headers. --- taglib/mpeg/mpegheader.cpp | 79 ++++++++++++++++++++------------- taglib/mpeg/mpegproperties.cpp | 30 ++++++++----- tests/data/invalid-frames.mp3 | Bin 0 -> 8192 bytes tests/test_mpeg.cpp | 14 ++++++ 4 files changed, 81 insertions(+), 42 deletions(-) create mode 100644 tests/data/invalid-frames.mp3 diff --git a/taglib/mpeg/mpegheader.cpp b/taglib/mpeg/mpegheader.cpp index 01cc6c57..05177f3e 100644 --- a/taglib/mpeg/mpegheader.cpp +++ b/taglib/mpeg/mpegheader.cpp @@ -23,8 +23,6 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include - #include #include #include @@ -68,20 +66,21 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -MPEG::Header::Header(const ByteVector &data) +MPEG::Header::Header(const ByteVector &data) : + d(new HeaderPrivate()) { - d = new HeaderPrivate; parse(data); } -MPEG::Header::Header(const Header &h) : d(h.d) +MPEG::Header::Header(const Header &h) : + d(h.d) { d->ref(); } MPEG::Header::~Header() { - if (d->deref()) + if(d->deref()) delete d; } @@ -164,39 +163,54 @@ MPEG::Header &MPEG::Header::operator=(const Header &h) void MPEG::Header::parse(const ByteVector &data) { - if(data.size() < 4 || static_cast(data[0]) != 0xff) { + if(data.size() < 4) { + debug("MPEG::Header::parse() -- data is too short for an MPEG frame header."); + return; + } + + // Check for the MPEG synch bytes. + + if(static_cast(data[0]) != 0xFF) { debug("MPEG::Header::parse() -- First byte did not match MPEG synch."); return; } - std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt())); - - // Check for the second byte's part of the MPEG synch - - if(!flags[23] || !flags[22] || !flags[21]) { + if((static_cast(data[1]) & 0xE0) != 0xE0) { debug("MPEG::Header::parse() -- Second byte did not match MPEG synch."); return; } // Set the MPEG version - if(!flags[20] && !flags[19]) + const int versionBits = (static_cast(data[1]) >> 3) & 0x03; + + if(versionBits == 0) d->version = Version2_5; - else if(flags[20] && !flags[19]) + else if(versionBits == 2) d->version = Version2; - else if(flags[20] && flags[19]) + else if(versionBits == 3) d->version = Version1; + else { + debug("MPEG::Header::parse() -- Invalid MPEG version bits."); + return; + } // Set the MPEG layer - if(!flags[18] && flags[17]) - d->layer = 3; - else if(flags[18] && !flags[17]) - d->layer = 2; - else if(flags[18] && flags[17]) - d->layer = 1; + const int layerBits = (static_cast(data[1]) >> 1) & 0x03; - d->protectionEnabled = !flags[16]; + if(layerBits == 1) + d->layer = 3; + else if(layerBits == 2) + d->layer = 2; + else if(layerBits == 3) + d->layer = 1; + else { + debug("MPEG::Header::parse() -- Invalid MPEG layer bits."); + return; + } + + d->protectionEnabled = (static_cast(data[1] & 0x01) == 0); // Set the bitrate @@ -219,9 +233,14 @@ void MPEG::Header::parse(const ByteVector &data) // The bitrate index is encoded as the first 4 bits of the 3rd byte, // i.e. 1111xxxx - int i = static_cast(data[2]) >> 4; + const int bitrateIndex = (static_cast(data[2]) >> 4) & 0x0F; - d->bitrate = bitrates[versionIndex][layerIndex][i]; + d->bitrate = bitrates[versionIndex][layerIndex][bitrateIndex]; + + if(d->bitrate == 0) { + debug("MPEG::Header::parse() -- Invalid bit rate."); + return; + } // Set the sample rate @@ -233,9 +252,9 @@ void MPEG::Header::parse(const ByteVector &data) // The sample rate index is encoded as two bits in the 3nd byte, i.e. xxxx11xx - i = static_cast(data[2]) >> 2 & 0x03; + const int samplerateIndex = (static_cast(data[2]) >> 2) & 0x03; - d->sampleRate = sampleRates[d->version][i]; + d->sampleRate = sampleRates[d->version][samplerateIndex]; if(d->sampleRate == 0) { debug("MPEG::Header::parse() -- Invalid sample rate."); @@ -245,13 +264,13 @@ void MPEG::Header::parse(const ByteVector &data) // The channel mode is encoded as a 2 bit value at the end of the 3nd byte, // i.e. xxxxxx11 - d->channelMode = static_cast((static_cast(data[3]) & 0xC0) >> 6); + d->channelMode = static_cast((static_cast(data[3]) >> 6) & 0x03); // TODO: Add mode extension for completeness - d->isOriginal = flags[2]; - d->isCopyrighted = flags[3]; - d->isPadded = flags[9]; + d->isOriginal = ((static_cast(data[3]) & 0x04) != 0); + d->isCopyrighted = ((static_cast(data[3]) & 0x08) != 0); + d->isPadded = ((static_cast(data[2]) & 0x02) != 0); // Samples per frame diff --git a/taglib/mpeg/mpegproperties.cpp b/taglib/mpeg/mpegproperties.cpp index 9fece404..989c9065 100644 --- a/taglib/mpeg/mpegproperties.cpp +++ b/taglib/mpeg/mpegproperties.cpp @@ -155,27 +155,33 @@ bool MPEG::Properties::isOriginal() const void MPEG::Properties::read(File *file) { - // Only the first frame is required if we have a VBR header. + // Only the first valid frame is required if we have a VBR header. - const long first = file->firstFrameOffset(); - if(first < 0) { - debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream."); + long firstFrameOffset = file->firstFrameOffset(); + if(firstFrameOffset < 0) { + debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream."); return; } - file->seek(first); - const Header firstHeader(file->readBlock(4)); + file->seek(firstFrameOffset); + Header firstHeader(file->readBlock(4)); - if(!firstHeader.isValid()) { - debug("MPEG::Properties::read() -- The first page header is invalid."); - return; + while(!firstHeader.isValid()) { + firstFrameOffset = file->nextFrameOffset(firstFrameOffset + 1); + if(firstFrameOffset < 0) { + debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream."); + return; + } + + file->seek(firstFrameOffset); + firstHeader = Header(file->readBlock(4)); } // Check for a VBR header that will help us in gathering information about a // VBR stream. - file->seek(first + 4); - d->xingHeader = new XingHeader(file->readBlock(firstHeader.frameLength() - 4)); + file->seek(firstFrameOffset); + d->xingHeader = new XingHeader(file->readBlock(firstHeader.frameLength())); if(!d->xingHeader->isValid()) { delete d->xingHeader; d->xingHeader = 0; @@ -201,7 +207,7 @@ void MPEG::Properties::read(File *file) d->bitrate = firstHeader.bitrate(); - long streamLength = file->length() - first; + long streamLength = file->length() - firstFrameOffset; if(file->hasID3v1Tag()) streamLength -= 128; diff --git a/tests/data/invalid-frames.mp3 b/tests/data/invalid-frames.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a6dc1117c4bd168901f24e866c3595f798d8224a GIT binary patch literal 8192 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 literal 0 HcmV?d00001 diff --git a/tests/test_mpeg.cpp b/tests/test_mpeg.cpp index a4ceced4..c04eecd9 100644 --- a/tests/test_mpeg.cpp +++ b/tests/test_mpeg.cpp @@ -22,6 +22,7 @@ class TestMPEG : public CppUnit::TestFixture CPPUNIT_TEST(testAudioPropertiesXingHeaderVBR); CPPUNIT_TEST(testAudioPropertiesVBRIHeader); CPPUNIT_TEST(testAudioPropertiesNoVBRHeaders); + CPPUNIT_TEST(testSkipInvalidFrames); CPPUNIT_TEST(testVersion2DurationWithXingHeader); CPPUNIT_TEST(testSaveID3v24); CPPUNIT_TEST(testSaveID3v24WrongParam); @@ -102,6 +103,19 @@ public: CPPUNIT_ASSERT_EQUAL(209, lastHeader.frameLength()); } + void testSkipInvalidFrames() + { + MPEG::File f(TEST_FILE_PATH_C("invalid-frames.mp3")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->length()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(393, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(160, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT(!f.audioProperties()->xingHeader()); + } + void testVersion2DurationWithXingHeader() { MPEG::File f(TEST_FILE_PATH_C("mpeg2.mp3"));