]> 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, 10 Mar 2012 08:06:55 +0000 (09:06 +0100)
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 425bfa020167702717fef3b6b3b1a10a4e845990..72667f6e2e88a21f8b10b588ca4118103ef43f1e 100644 (file)
@@ -87,6 +87,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 8d23bcd6983a475cd19dc88d4fd73be2ee740027..a3ca0e3e9200df10650deaa2831eeec3d730c3e2 100644 (file)
@@ -194,6 +194,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);
@@ -207,8 +220,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 9ec3b510881e43b87d9500160b976c0c0373226c..37d8a4d2de76a90031e6e42ba784091684ef78d4 100644 (file)
@@ -87,6 +87,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 38a9a0fbc1f62c92f81b90d2851343c08496c5ae..0bd820183b50d699ab537e20f3c2899b7dfb0b80 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("data/empty.wav");
+    CPPUNIT_ASSERT_EQUAL(true, f.isValid());
     CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length());
   }
 
+  void testZeroSizeDataChunk()
+  {
+    RIFF::WAV::File f("data/zero-size-chunk.wav");
+    CPPUNIT_ASSERT_EQUAL(false, f.isValid());
+  }
+
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(TestWAV);