diff options
-rw-r--r-- | Swiften/Parser/LibXMLParser.cpp | 14 | ||||
-rw-r--r-- | Swiften/Parser/UnitTest/XMLParserTest.cpp | 15 |
2 files changed, 26 insertions, 3 deletions
diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp index b8d941c..158958b 100644 --- a/Swiften/Parser/LibXMLParser.cpp +++ b/Swiften/Parser/LibXMLParser.cpp @@ -100,12 +100,20 @@ static void handleError(void*, const char* /*m*/, ... ) { static void handleWarning(void*, const char*, ... ) { } +static void handleGenericError(void*, const char*, ... ) { +} + +static void handleStructuredError(void*, xmlErrorPtr) { +} + bool LibXMLParser::initialized = false; LibXMLParser::LibXMLParser(XMLParserClient* client, bool allowComments) : XMLParser(client, allowComments), p(new Private()) { // Initialize libXML for multithreaded applications if (!initialized) { xmlInitParser(); + xmlSetGenericErrorFunc(nullptr, handleGenericError); + xmlSetStructuredErrorFunc(nullptr, handleStructuredError); initialized = true; } @@ -136,12 +144,12 @@ bool LibXMLParser::parse(const std::string& data, bool finalData) { if (data.size() > std::numeric_limits<int>::max()) { return false; } - if (xmlParseChunk(p->context_, data.c_str(), static_cast<int>(data.size()), finalData) == XML_ERR_OK) { + auto error = xmlParseChunk(p->context_, data.c_str(), static_cast<int>(data.size()), finalData); + if (error == XML_ERR_OK) { return true; } if (stopped_) return false; - xmlError* error = xmlCtxtGetLastError(p->context_); - if (error->code == XML_WAR_NS_URI || error->code == XML_WAR_NS_URI_RELATIVE) { + if (error == XML_WAR_NS_URI || error == XML_WAR_NS_URI_RELATIVE) { xmlCtxtResetLastError(p->context_); p->context_->errNo = XML_ERR_OK; return true; diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index d38c1cc..89229c9 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp @@ -45,6 +45,7 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_TEST(testParse_Doctype); CPPUNIT_TEST(testParse_ProcessingInstructions); CPPUNIT_TEST(testParse_ProcessingPrefixedElement); + CPPUNIT_TEST(testParse_InvalidlyEncodedInput); CPPUNIT_TEST_SUITE_END(); public: @@ -410,6 +411,20 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[1].ns); } + void testParse_InvalidlyEncodedInput() { + ParserType testling(&client_); + + // The following input was generated by a fuzzer, and triggered a crash in the LibXML2 parser because + // some types of error (buffer I/O errors, for instance) will not update the error in the parser context, + // and the code used to rely on that error always being set if parsing failed. + // This particular input will trick the parser into believing the encoding is UTF-16LE, which eventually will lead + // to two invalid encodings, followed by an I/O error. The latter will end parsing without updating the + // error in the parsing context, which used to trigger a crash. + testling.parse(std::string("<\0?\0\x80q type='get' id='aab9a'<<query xmlns='jabber:iq:roster'/>\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9br:i><quq:private'><storage xml s='s'\x00\x10</query></iq>", 271)); + testling.parse("<iq type='get'\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e to='ad5d8d2b25' ext='ca cs min@wonderland.t' id='aabda'><vCard xmlnr='vcard-temp'/>O/iq>"); + testling.parse("<\xff\xff\xff\x7fype:'get' to='won\x84" "erland.lit' id='aabea'><tuery xmlns='\xd8Vtp://jabber.org/p\x88ot\x8b" "col/disco#info'/>abber.org/protocol/disco#Nnfo'/></iq>"); + } + private: class Client : public XMLParserClient { public: |