diff options
author | Mitch Curtis <mitch.curtis@digia.com> | 2013-11-07 08:36:29 (GMT) |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-11-07 12:56:40 (GMT) |
commit | 512a1ce0698d370c313bb561bbf078935fa0342e (patch) | |
tree | 4cbb038859c99aa81c99678c52f6a76de7aa615b /src/xml/sax | |
parent | cab363afa347e22c5f738f15533489e0cd671d59 (diff) | |
download | Qt-512a1ce0698d370c313bb561bbf078935fa0342e.zip Qt-512a1ce0698d370c313bb561bbf078935fa0342e.tar.gz Qt-512a1ce0698d370c313bb561bbf078935fa0342e.tar.bz2 |
Disallow deep or widely nested entity references.
Nested references with a depth of 2 or greater will fail. References
that partially expand to greater than 1024 characters will also fail.
This is a backport of 46a8885ae486e238a39efa5119c2714f328b08e4.
Change-Id: I0c2e1fa13d6ccb5f88641dae2ed3f28bfdeaf609
Reviewed-by: Richard J. Moore <rich@kde.org>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/xml/sax')
-rw-r--r-- | src/xml/sax/qxml.cpp | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp index a1777c5..3904632 100644 --- a/src/xml/sax/qxml.cpp +++ b/src/xml/sax/qxml.cpp @@ -424,6 +424,10 @@ private: int stringValueLen; QString emptyStr; + // The limit to the amount of times the DTD parsing functions can be called + // for the DTD currently being parsed. + int dtdRecursionLimit; + const QString &string(); void stringClear(); void stringAddC(QChar); @@ -492,6 +496,7 @@ private: void unexpectedEof(ParseFunction where, int state); void parseFailed(ParseFunction where, int state); void pushParseState(ParseFunction function, int state); + bool isPartiallyExpandedEntityValueTooLarge(QString *errorMessage); Q_DECLARE_PUBLIC(QXmlSimpleReader) QXmlSimpleReader *q_ptr; @@ -2759,6 +2764,7 @@ QXmlSimpleReaderPrivate::QXmlSimpleReaderPrivate(QXmlSimpleReader *reader) useNamespacePrefixes = false; reportWhitespaceCharData = true; reportEntities = false; + dtdRecursionLimit = 2; } QXmlSimpleReaderPrivate::~QXmlSimpleReaderPrivate() @@ -5018,6 +5024,11 @@ bool QXmlSimpleReaderPrivate::parseDoctype() } break; case Mup: + if (dtdRecursionLimit > 0 && parameterEntities.size() > dtdRecursionLimit) { + reportParseError(QString::fromLatin1( + "DTD parsing exceeded recursion limit of %1.").arg(dtdRecursionLimit)); + return false; + } if (!parseMarkupdecl()) { parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state); return false; @@ -6627,6 +6638,37 @@ bool QXmlSimpleReaderPrivate::parseChoiceSeq() return false; } +bool QXmlSimpleReaderPrivate::isPartiallyExpandedEntityValueTooLarge(QString *errorMessage) +{ + const QString value = string(); + QMap<QString, int> referencedEntityCounts; + foreach (QString entityName, entities.keys()) { + for (int i = 0; i < value.size() && i != -1; ) { + i = value.indexOf(entityName, i); + if (i != -1) { + // The entityName we're currently trying to find + // was matched in this string; increase our count. + ++referencedEntityCounts[entityName]; + i += entityName.size(); + } + } + } + + foreach (QString entityName, referencedEntityCounts.keys()) { + const int timesReferenced = referencedEntityCounts[entityName]; + const QString entityValue = entities[entityName]; + if (entityValue.size() * timesReferenced > 1024) { + if (errorMessage) { + *errorMessage = QString::fromLatin1("The XML entity \"%1\"" + "expands too a string that is too large to process when " + "referencing \"%2\" %3 times.").arg(entityName).arg(entityName).arg(timesReferenced); + } + return true; + } + } + return false; +} + /* Parse a EntityDecl [70]. @@ -6721,6 +6763,15 @@ bool QXmlSimpleReaderPrivate::parseEntityDecl() switch (state) { case EValue: if ( !entityExist(name())) { + QString errorMessage; + if (isPartiallyExpandedEntityValueTooLarge(&errorMessage)) { + // The entity at entityName is entityValue.size() characters + // long in its unexpanded form, and was mentioned timesReferenced times, + // resulting in a string that would be greater than 1024 characters. + reportParseError(errorMessage); + return false; + } + entities.insert(name(), string()); if (declHnd) { if (!declHnd->internalEntityDecl(name(), string())) { |