diff --git a/ChangeLog b/ChangeLog index 88eabf20..216c0736 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-12-25 Tatsuhiro Tsujikawa + + Check structure depth when decoding. + * src/bencode.cc + * src/bencode.h + * test/BencodeTest.cc + 2009-12-25 Tatsuhiro Tsujikawa Documented tellStopped XML-RPC method in man page. diff --git a/src/bencode.cc b/src/bencode.cc index 0d33ea83..949a96bb 100644 --- a/src/bencode.cc +++ b/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; } diff --git a/src/bencode.h b/src/bencode.h index ed056279..280c0af2 100644 --- a/src/bencode.h +++ b/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. diff --git a/test/BencodeTest.cc b/test/BencodeTest.cc index 69b75d69..19a5fc03 100644 --- a/test/BencodeTest.cc +++ b/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() { {