diff --git a/third_party/libjingle_xmpp/xmllite/xmlparser.cc b/third_party/libjingle_xmpp/xmllite/xmlparser.cc index 7835a2da6e4c95..1fd88d63940934 100644 --- a/third_party/libjingle_xmpp/xmllite/xmlparser.cc +++ b/third_party/libjingle_xmpp/xmllite/xmlparser.cc @@ -41,6 +41,16 @@ XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) { (static_cast(userData))->ExpatXmlDecl(ver, enc, st); } +static void +StartDoctypeDeclCallback(void * userData, const char *, const char *, + const char *, int) { + // XMPP stanzas must never carry a DOCTYPE / internal DTD subset. Abort + // parsing immediately so that doProlog never processes attacker-supplied + // entity / ATTLIST declarations. This is encoding-independent and therefore + // not bypassable by UTF-16 auto-detection (unlike a byte-substring filter). + (static_cast(userData))->ExpatStartDoctypeDecl(); +} + XmlParser::XmlParser(XmlParseHandler *pxph) : pxph_(pxph), sentError_(false) { expat_ = XML_ParserCreate(NULL); @@ -48,6 +58,7 @@ XmlParser::XmlParser(XmlParseHandler *pxph) : XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback); XML_SetCharacterDataHandler(expat_, CharacterDataCallback); XML_SetXmlDeclHandler(expat_, XmlDeclCallback); + XML_SetStartDoctypeDeclHandler(expat_, StartDoctypeDeclCallback); } void @@ -60,6 +71,7 @@ XmlParser::Reset() { XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback); XML_SetCharacterDataHandler(expat_, CharacterDataCallback); XML_SetXmlDeclHandler(expat_, XmlDeclCallback); + XML_SetStartDoctypeDeclHandler(expat_, StartDoctypeDeclCallback); context_.Reset(); sentError_ = false; } @@ -146,6 +158,15 @@ XmlParser::ExpatXmlDecl(const char * ver, const char * enc, int standalone) { } +void +XmlParser::ExpatStartDoctypeDecl() { + // Abort before expat enters the internal-subset state machine. Non-resumable + // stop: returns XML_STATUS_ERROR with XML_ERROR_ABORTED, before any + // / in the subset is tokenised. + XML_StopParser(expat_, /*resumable=*/XML_FALSE); + context_.RaiseError(XML_ERROR_SYNTAX); +} + bool XmlParser::Parse(const char *data, size_t len, bool isFinal) { if (sentError_) diff --git a/third_party/libjingle_xmpp/xmllite/xmlparser.h b/third_party/libjingle_xmpp/xmllite/xmlparser.h index f3cf612372108e..bdfbfa9d9c4a79 100644 --- a/third_party/libjingle_xmpp/xmllite/xmlparser.h +++ b/third_party/libjingle_xmpp/xmllite/xmlparser.h @@ -65,6 +65,7 @@ public: void ExpatEndElement(const char * name); void ExpatCharacterData(const char * text, int len); void ExpatXmlDecl(const char * ver, const char * enc, int standalone); + void ExpatStartDoctypeDecl(); private: