summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/Parser/LibXMLParser.cpp14
-rw-r--r--Swiften/Parser/UnitTest/XMLParserTest.cpp15
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
@@ -94,24 +94,32 @@ static void handleError(void*, const char* /*m*/, ... ) {
va_start(args, m);
vfprintf(stdout, m, args);
va_end(args);
*/
}
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;
}
memset(&p->handler_, 0, sizeof(p->handler_) );
p->handler_.initialized = XML_SAX2_MAGIC;
p->handler_.startElementNs = &handleStartElement;
p->handler_.endElementNs = &handleEndElement;
p->handler_.characters = &handleCharacterData;
p->handler_.warning = &handleWarning;
@@ -130,24 +138,24 @@ LibXMLParser::~LibXMLParser() {
if (p->context_) {
xmlFreeParserCtxt(p->context_);
}
}
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;
}
return false;
}
void LibXMLParser::stopParser() {
stopped_ = 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
@@ -39,18 +39,19 @@ class XMLParserTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testParse_BillionLaughs);
CPPUNIT_TEST(testParse_InternalEntity);
//CPPUNIT_TEST(testParse_UndefinedPrefix);
//CPPUNIT_TEST(testParse_UndefinedAttributePrefix);
CPPUNIT_TEST(testParse_AllowCommentsInXML);
CPPUNIT_TEST(testParse_DisallowCommentsInXML);
CPPUNIT_TEST(testParse_Doctype);
CPPUNIT_TEST(testParse_ProcessingInstructions);
CPPUNIT_TEST(testParse_ProcessingPrefixedElement);
+ CPPUNIT_TEST(testParse_InvalidlyEncodedInput);
CPPUNIT_TEST_SUITE_END();
public:
void testParse_NestedElements() {
ParserType testling(&client_);
CPPUNIT_ASSERT(testling.parse(
"<iq type=\"get\">"
"<query xmlns='jabber:iq:version'/>"
@@ -404,18 +405,32 @@ class XMLParserTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[0].data);
CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[0].ns);
CPPUNIT_ASSERT_EQUAL(std::string("prefix"), client_.events[0].prefix);
CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type);
CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[1].data);
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:
using NamespaceMap = std::unordered_map<std::string /* prefix */, std::string /* uri */>;
enum Type { StartElement, StartElementPrefix, EndElement, CharacterData, NamespaceDefined };
struct Event {
Event(
Type type,
const std::string& data,