]> granicus.if.org Git - taglib/commitdiff
Detect RIFF files with invalid chunk sizes
authorLukáš Lalinský <lalinsky@gmail.com>
Sat, 8 Oct 2011 16:41:15 +0000 (18:41 +0200)
committerLukáš Lalinský <lalinsky@gmail.com>
Sat, 8 Oct 2011 16:41:15 +0000 (18:41 +0200)
The bug report has a WAVE file with zero-sized 'data' chunk, which causes
TagLib to iterate over the file, 8 bytes in each iteration. The new code
adds a check for the chunk name, which forces it to mark the file as
invalid if the chunk name doesn't contain ASCII characters.

https://bugs.kde.org/show_bug.cgi?id=283412

taglib/riff/aiff/aifffile.cpp
taglib/riff/rifffile.cpp
taglib/riff/wav/wavfile.cpp
tests/data/zero-size-chunk.wav [new file with mode: 0644]
tests/test_wav.cpp

index 9f6be7ff1e7960854b95dc866ad408a326bd3ee8..b868ada46f1d466bc386f5b529e27f221424ce8b 100644 (file)
@@ -95,6 +95,11 @@ bool RIFF::AIFF::File::save()
     return false;
   }
 
+  if(!isValid()) {
+    debug("RIFF::AIFF::File::save() -- Trying to save invalid file.");
+    return false;
+  }
+
   setChunkData(d->tagChunkID, d->tag->render());
 
   return true;
index 984568d19a16854fa136d0a2f52e6e3c8f65ee92..0e70dd5e463a46b8e33f958176d083e3a9ac2652 100644 (file)
@@ -203,6 +203,19 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
 // private members
 ////////////////////////////////////////////////////////////////////////////////
 
+static bool isValidChunkID(const ByteVector &name)
+{
+  if(name.size() != 4) {
+    return false;
+  }
+  for(int i = 0; i < 4; i++) {
+    if(name[i] < 32 || name[i] > 127) {
+      return false;
+    }
+  }
+  return true;
+}
+
 void RIFF::File::read()
 {
   bool bigEndian = (d->endianness == BigEndian);
@@ -216,8 +229,15 @@ void RIFF::File::read()
     ByteVector chunkName = readBlock(4);
     uint chunkSize = readBlock(4).toUInt(bigEndian);
 
+    if(!isValidChunkID(chunkName)) {
+      debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID");
+      setValid(false);
+      break;
+    }
+
     if(tell() + chunkSize > uint(length())) {
-      // something wrong
+      debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)");
+      setValid(false);
       break;
     }
 
index 70d9a35cfecffa10252f0683b5c52d261470e0ca..107d2b45f50a87866ccd81b3d9d8fa63ff592ce6 100644 (file)
@@ -95,6 +95,11 @@ bool RIFF::WAV::File::save()
     return false;
   }
 
+  if(!isValid()) {
+    debug("RIFF::WAV::File::save() -- Trying to save invalid file.");
+    return false;
+  }
+
   setChunkData(d->tagChunkID, d->tag->render());
 
   return true;
diff --git a/tests/data/zero-size-chunk.wav b/tests/data/zero-size-chunk.wav
new file mode 100644 (file)
index 0000000..8517e79
Binary files /dev/null and b/tests/data/zero-size-chunk.wav differ
index c4e5f39008d6483d25b91d85f2534fe7819b8657..d17ce2cc7b2fb7a4a6f048020536f25361f0b825 100644 (file)
@@ -13,6 +13,7 @@ class TestWAV : public CppUnit::TestFixture
 {
   CPPUNIT_TEST_SUITE(TestWAV);
   CPPUNIT_TEST(testLength);
+  CPPUNIT_TEST(testZeroSizeDataChunk);
   CPPUNIT_TEST_SUITE_END();
 
 public:
@@ -20,9 +21,16 @@ public:
   void testLength()
   {
     RIFF::WAV::File f(TEST_FILE_PATH_C("empty.wav"));
+    CPPUNIT_ASSERT_EQUAL(true, f.isValid());
     CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length());
   }
 
+  void testZeroSizeDataChunk()
+  {
+    RIFF::WAV::File f(TEST_FILE_PATH_C("zero-size-chunk.wav"));
+    CPPUNIT_ASSERT_EQUAL(false, f.isValid());
+  }
+
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(TestWAV);