浏览代码

2009-12-25 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Check structure depth when decoding.
	* src/bencode.cc
	* src/bencode.h
	* test/BencodeTest.cc
Tatsuhiro Tsujikawa 16 年之前
父节点
当前提交
838fcbbecd
共有 4 个文件被更改,包括 47 次插入10 次删除
  1. 7 0
      ChangeLog
  2. 18 10
      src/bencode.cc
  3. 2 0
      src/bencode.h
  4. 20 0
      test/BencodeTest.cc

+ 7 - 0
ChangeLog

@@ -1,3 +1,10 @@
+2009-12-25  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Check structure depth when decoding.
+	* src/bencode.cc
+	* src/bencode.h
+	* test/BencodeTest.cc
+
 2009-12-25  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Documented tellStopped XML-RPC method in man page.

+ 18 - 10
src/bencode.cc

@@ -44,7 +44,7 @@ namespace aria2 {
 
 namespace bencode {
 
-static BDE decodeiter(std::istream& ss);
+static BDE decodeiter(std::istream& ss, size_t depth);
 
 static void checkdelim(std::istream& ss, const char delim = ':')
 {
@@ -96,7 +96,7 @@ static BDE decodeinteger(std::istream& ss)
   return BDE(integer);
 }
 
-static BDE decodedict(std::istream& ss)
+static BDE decodedict(std::istream& ss, size_t depth)
 {
   BDE dict = BDE::dict();
   char c;
@@ -106,14 +106,14 @@ static BDE decodedict(std::istream& ss)
     } else {
       ss.unget();
       std::string key = decoderawstring(ss);
-      dict[key] = decodeiter(ss);
+      dict[key] = decodeiter(ss, depth);
     }
   }
   throw DL_ABORT_EX("Bencode decoding failed:"
 		    " Unexpected EOF in dict context. 'e' expected.");
 }
 
-static BDE decodelist(std::istream& ss)
+static BDE decodelist(std::istream& ss, size_t depth)
 {
   BDE list = BDE::list();
   char c;
@@ -122,15 +122,23 @@ static BDE decodelist(std::istream& ss)
       return list;
     } else {
       ss.unget();
-      list << decodeiter(ss);
+      list << decodeiter(ss, depth);
     }
   }
   throw DL_ABORT_EX("Bencode decoding failed:"
 		    " Unexpected EOF in list context. 'e' expected.");
 }
 
-static BDE decodeiter(std::istream& ss)
+static void checkDepth(size_t depth)
 {
+  if(depth >= MAX_STRUCTURE_DEPTH) {
+    throw DL_ABORT_EX("Bencode decoding failed: Structure is too deep.");
+  }
+}
+
+static BDE decodeiter(std::istream& ss, size_t depth)
+{
+  checkDepth(depth);
   char c;
   if(!ss.get(c)) {
     throw DL_ABORT_EX("Bencode decoding failed:"
@@ -138,9 +146,9 @@ static BDE decodeiter(std::istream& ss)
 		      " 'd', 'l', 'i' or digit is expected.");
   }
   if(c == 'd') {
-    return decodedict(ss);
+    return decodedict(ss, depth+1);
   } else if(c == 'l') {
-    return decodelist(ss);
+    return decodelist(ss, depth+1);
   } else if(c == 'i') {
     return decodeinteger(ss);
   } else {
@@ -151,7 +159,7 @@ static BDE decodeiter(std::istream& ss)
 
 BDE decode(std::istream& in)
 {
-  return decodeiter(in);
+  return decodeiter(in, 0);
 }
 
 BDE decode(const std::string& s)
@@ -167,7 +175,7 @@ BDE decode(const std::string& s, size_t& end)
   }
   std::istringstream ss(s);
 
-  BDE bde = decodeiter(ss);
+  BDE bde = decodeiter(ss, 0);
   end = ss.tellg();
   return bde;
 }

+ 2 - 0
src/bencode.h

@@ -46,6 +46,8 @@ namespace aria2 {
 
 namespace bencode {
 
+const size_t MAX_STRUCTURE_DEPTH = 100;
+
 BDE decode(std::istream& in);
 
 // Decode the data in s.

+ 20 - 0
test/BencodeTest.cc

@@ -10,12 +10,14 @@ class BencodeTest:public CppUnit::TestFixture {
 
   CPPUNIT_TEST_SUITE(BencodeTest);
   CPPUNIT_TEST(testDecode);
+  CPPUNIT_TEST(testDecode_overflow);
   CPPUNIT_TEST(testEncode);
   CPPUNIT_TEST_SUITE_END();
 private:
 
 public:
   void testDecode();
+  void testDecode_overflow();
   void testEncode();
 };
 
@@ -155,6 +157,24 @@ void BencodeTest::testDecode()
   }
 }
 
+void BencodeTest::testDecode_overflow()
+{
+  std::string s;
+  size_t depth = bencode::MAX_STRUCTURE_DEPTH+1;
+  for(size_t i = 0; i < depth; ++i) {
+    s += "l";
+  }
+  for(size_t i = 0; i < depth; ++i) {
+    s += "e";
+  }
+  try {
+    bencode::decode(s);
+    CPPUNIT_FAIL("exception must be thrown.");
+  } catch(RecoverableException& e) {
+    // success
+  }
+}
+
 void BencodeTest::testEncode()
 {
   {